1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <sys/ioctl.h>
20 #include <sys/resource.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23
24 #ifdef LINUX_WATCHDOG
25 #include <linux/watchdog.h>
26 #else
27 #include <linux/types.h>
28 #define WDIOC_KEEPALIVE _IO('W', 5)
29 #define WDIOC_SETTIMEOUT _IOWR('W', 6, int)
30 #define WDIOC_GETTIMEOUT _IOR('W', 7, int)
31 #endif
32
33 #include "init_log.h"
34
35 #define WAIT_MAX_COUNT 20
36 #define DEFAULT_INTERVAL 3
37 #define DEFAULT_GAP 3
38 #define CONVERSION_BASE 1000000U
39
40 #define PRETIMEOUT_GAP 5
41 #define PRETIMEOUT_DIV 2
42
WaitAtStartup(const char * source)43 static void WaitAtStartup(const char *source)
44 {
45 unsigned int count = 0;
46 struct stat sourceInfo;
47 const unsigned int waitTime = 500000;
48 do {
49 usleep(waitTime);
50 count++;
51 } while ((stat(source, &sourceInfo) < 0) && (errno == ENOENT) && (count < WAIT_MAX_COUNT));
52 if (count == WAIT_MAX_COUNT) {
53 INIT_LOGE("wait for file:%s failed after %u seconds.", source, (WAIT_MAX_COUNT * waitTime) / CONVERSION_BASE);
54 }
55 return;
56 }
57
58 #ifdef WDIOC_SETPRETIMEOUT
GetWatcherDogCfg(int interval,int timeoutGet,int fd)59 int GetWatcherDogCfg(int interval, int timeoutGet, int fd)
60 {
61 int preTimeout = 0;
62 int preTimeoutGet = 0;
63 preTimeout = timeoutGet - PRETIMEOUT_GAP; // ensure pretimeout smaller then timeout
64 if (preTimeout > 0) {
65 int ret = ioctl(fd, WDIOC_SETPRETIMEOUT, &preTimeout);
66 if (ret) {
67 INIT_LOGE("Failed to set pretimeout to %d\n", preTimeout);
68 }
69 ret = ioctl(fd, WDIOC_GETPRETIMEOUT, &preTimeoutGet);
70 if (ret) {
71 INIT_LOGE("Failed to get pretimeout\n");
72 }
73 }
74
75 if (preTimeoutGet > 0 && preTimeoutGet < interval) {
76 interval = preTimeoutGet / PRETIMEOUT_DIV;
77 }
78 return interval;
79 }
80 #endif
81
main(int argc,const char * argv[])82 int main(int argc, const char *argv[])
83 {
84 WaitAtStartup("/dev/watchdog");
85 int fd = open("/dev/watchdog", O_RDWR);
86 if (fd == -1) {
87 INIT_LOGE("Can't open /dev/watchdog.");
88 return 1;
89 }
90
91 int interval = 0;
92 if (argc >= 2) { // Argument nums greater than or equal to 2.
93 interval = atoi(argv[1]);
94 if (interval < 0 || interval > INT16_MAX) {
95 interval = DEFAULT_INTERVAL;
96 }
97 }
98 interval = (interval > 0) ? interval : DEFAULT_INTERVAL;
99
100 int gap = 0;
101 if (argc >= 3) { // Argument nums greater than or equal to 3.
102 gap = atoi(argv[2]); // 2 second parameter.
103 }
104 gap = (gap > 0) ? gap : DEFAULT_GAP;
105
106 INIT_LOGI("Watchdog started (interval %d, margin %d), fd = %d\n", interval, gap, fd);
107 #ifdef OHOS_LITE_WATCHDOG
108 #ifndef LINUX_WATCHDOG
109 if (setpriority(PRIO_PROCESS, 0, 14) != 0) { // 14 is process priority
110 INIT_LOGE("setpriority failed err=%d\n", errno);
111 }
112 #endif
113 #endif
114 int timeoutSet = interval + gap;
115 int timeoutGet = 0;
116
117 int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeoutSet);
118 if (ret) {
119 INIT_LOGE("Failed to set timeout to %d\n", timeoutSet);
120 }
121 ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeoutGet);
122 if (ret) {
123 INIT_LOGE("Failed to get timeout\n");
124 }
125
126 if (timeoutGet > 0) {
127 interval = (timeoutGet > gap) ? (timeoutGet - gap) : 1;
128 }
129
130 #ifdef WDIOC_SETPRETIMEOUT
131 interval = GetWatcherDogCfg(interval, timeoutGet, fd);
132 #endif
133
134 while (1) {
135 ioctl(fd, WDIOC_KEEPALIVE);
136 sleep(interval);
137 }
138 close(fd);
139 return -1;
140 }
141