1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/*
* wdd - simple watchdog daemon - 2003-2004 - willy tarreau
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
const char dev_wd_str[] = "/dev/watchdog"; /* standard entry */
const char dev_misc_str[] = "/dev/misc/watchdog"; /* devfs entry */
const char root_str[] = "/";
/*
* This function checks if the system can allocate memory
* In case of failure, we exit so that the watchdog device
* notices it and can reboot.
*/
static inline void try_malloc() {
void *heap;
heap = (void*)sbrk(NULL);
if (brk(heap + 4096))
exit(1);
memset(heap, 0, 4096);
if (brk(heap))
exit(1);
}
/*
* This function checks if the system can fork
* In case of failure, we exit so that the watchdog device
* notices it and can reboot.
*/
static inline void try_fork() {
int pid;
pid = fork();
if (pid < 0) /* exit on error */
exit(1);
else if (pid == 0) /* child returns cleanly */
exit(0);
if (waitpid(pid, NULL, 0) != pid) /* father checks child */
exit(1);
}
/*
* This function checks if the system can stat a given directory entry on the
* VFS. In case of failure, we either report the problem, or exit so that the
* watchdog device notices it and can reboot.
*/
static inline int try_stat(const char *file, int do_exit) {
void *heap;
int ret;
heap = (void*)sbrk(NULL);
if (brk(heap + sizeof (struct stat)))
exit(1);
memset(heap, 0, sizeof (struct stat));
ret = stat(file, heap);
if (brk(heap))
exit(1);
if (ret == -1) {
if (do_exit)
exit(1);
else
return 0;
}
return 1;
}
int main (int argc, char **argv) {
int dev;
int curr_file;
if (argc > 1) {
/* we'll do a quick check on all the arguments to
* ensure that they are valid at load time, and avoid
* an accidental start of the watchdog which could be
* a disaster in case of a file name error.
*/
for (curr_file = 1; curr_file < argc; ) {
if (try_stat(argv[curr_file], 0))
curr_file++;
else {
/* remove this file from the list, and make it noticeable from 'ps' */
*argv[curr_file] = '!';
argv[curr_file] = argv[--argc];
}
}
}
if (fork() > 0)
return 0;
for (dev = 2; dev >= 0; dev--)
close(dev);
chdir(root_str);
setsid();
curr_file = 1; /* start with first file in the list */
/* let's try indefinitely to open the watchdog device */
/* note that dev is -1 now ;-) */
while (1) {
if (dev == -1)
dev = open(dev_wd_str, O_RDWR);
if (dev == -1)
dev = open(dev_misc_str, O_RDWR);
if ((dev != -1) && (write(dev, dev_wd_str, 1) != 1)) {
/* write error, we'll restart */
close(dev);
dev = -1;
}
try_malloc();
try_fork();
if (argc > 1) {
try_stat(argv[curr_file], 1);
curr_file++;
if (curr_file >= argc)
curr_file = 1;
} else {
try_stat(root_str, 1);
}
/* avoid a fast loop */
sleep(1);
}
/* we never get there theorically... */
return 0;
}
|