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
|
/* watchdog - start a watchdog timer with configurable kick frequencies
Author: Chris Sarra, chrissarra@google.com
Date: 25 July 2019
Ref: kernel.org/doc/Documentation/watchdog/watchdog-api.txt
USE_WATCHDOG(NEWTOY(watchdog, "Ft#T#", TOYFLAG_NEEDROOT|TOYFLAG_BIN))
config WATCHDOG
bool "watchdog"
default y
help
usage: watchdog [-F] [-t SW_TIMER_S] [-T HW_TIMER_S] DEV
Start the watchdog timer at DEV with optional timeout parameters.
-F run in the foreground (do not daemonize)
-t software timer (in seconds)
-T hardware timer (in seconds)
*/
#define FOR_watchdog
#include "toys.h"
#include "linux/watchdog.h"
// Make sure no DEBUG variable is set; change this if you need debug prints!
#undef WATCHDOG_DEBUG
// Default timeout values in seconds.
#define WATCHDOG_SW_TIMER_S_DEFAULT (4)
#define WATCHDOG_HW_TIMER_S_DEFAULT (60)
GLOBALS(
long hw_timer_s;
long sw_timer_s;
int fd;
)
static int intercept_signals(void (*fn)(int)) {
int rc = 0;
struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = fn;
rc = sigaction(SIGTERM, &sigact, NULL);
#if defined(WATCHDOG_DEBUG)
if ( rc ) {
printf("failed to create new sigaction for SIGTERM: %d\n", rc);
}
#endif
return rc;
}
void safe_shutdown(int __attribute__((unused))ignored) {
write(TT.fd, "V", 1);
close(TT.fd);
TT.fd = -1;
error_exit("safely exited watchdog.");
}
void watchdog_main(void) {
int rc = 0;
long hw_timer_sec = 0;
char *watchdog_dev = NULL;
if ( toys.optc > 0 ) {
watchdog_dev = toys.optargs[0];
#if defined(WATCHDOG_DEBUG)
printf("using dev @ '%s'\n", watchdog_dev);
#endif
} else {
error_exit("watchdog dev required");
}
// Set default values for timeouts if no flags
if (!(toys.optflags & FLAG_t)) {
TT.sw_timer_s = WATCHDOG_SW_TIMER_S_DEFAULT;
#if defined(WATCHDOG_DEBUG)
printf("using default sw_timer_s.\n");
#endif
}
if (!(toys.optflags & FLAG_T)) {
TT.hw_timer_s = WATCHDOG_HW_TIMER_S_DEFAULT;
#if defined(WATCHDOG_DEBUG)
printf("using default hw_timer_s.\n");
#endif
}
#if defined(WATCHDOG_DEBUG)
printf("hw timer: %ld seconds\n", TT.hw_timer_s);
printf("sw timer: %ld seconds\n", TT.sw_timer_s);
#endif
if (!(toys.optflags & FLAG_F)) {
#if defined(WATCHDOG_DEBUG)
printf("daemonizing. so long, foreground!\n");
#endif
// Attempt to daemonize
rc = daemon(1, 1);
if ( rc ) {
perror_exit("failed to daemonize: %d", rc);
}
}
// Intercept terminating signals so we can call our shutdown routine first.
if ( intercept_signals(safe_shutdown) ) {
perror_exit("failed to intercept desired signals: %d", rc);
}
#if defined(WATCHDOG_DEBUG)
printf("Successfully intercepted signals.\n");
#endif
TT.fd = open(watchdog_dev, O_WRONLY);
if ( TT.fd == -1 ) {
perror_exit("failed to open '%s'", watchdog_dev);
}
#if defined(WDIOC_SETTIMEOUT)
// SETTIMEOUT takes time value in seconds: s = ms / (1000 ms/s)
hw_timer_sec = TT.hw_timer_s;
xioctl(TT.fd, WDIOC_SETTIMEOUT, (void *)&hw_timer_sec);
#endif // WDIOC_SETTIMEOUT
// Now that we've got the watchdog device open, kick it periodically.
while (1) {
write(TT.fd, "\0", 1);
usleep(TT.sw_timer_s * 1000 * 1000);
}
}
|