xref: /base/startup/init/watchdog/init_watchdog.c (revision d9f0492f)
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
43static 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
59int 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
82int main(int argc, const char *argv[])
83{
84    EnableInitLog(INIT_INFO);
85    WaitAtStartup("/dev/watchdog");
86    int fd = open("/dev/watchdog", O_RDWR);
87    if (fd == -1) {
88        INIT_LOGE("Can't open /dev/watchdog.");
89        return 1;
90    }
91
92    int interval = 0;
93    if (argc >= 2) { // Argument nums greater than or equal to 2.
94        interval = atoi(argv[1]);
95        if (interval < 0 || interval > INT16_MAX) {
96            interval = DEFAULT_INTERVAL;
97        }
98    }
99    interval = (interval > 0) ? interval : DEFAULT_INTERVAL;
100
101    int gap = 0;
102    if (argc >= 3) { // Argument nums greater than or equal to 3.
103        gap = atoi(argv[2]); // 2 second parameter.
104    }
105    gap = (gap > 0) ? gap : DEFAULT_GAP;
106
107    INIT_LOGI("Watchdog started (interval %d, margin %d), fd = %d\n", interval, gap, fd);
108#ifdef OHOS_LITE_WATCHDOG
109#ifndef LINUX_WATCHDOG
110    if (setpriority(PRIO_PROCESS, 0, 14) != 0) { // 14 is process priority
111        INIT_LOGE("setpriority failed err=%d\n", errno);
112    }
113#endif
114#endif
115    int timeoutSet = interval + gap;
116    int timeoutGet = 0;
117
118    int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeoutSet);
119    if (ret) {
120        INIT_LOGE("Failed to set timeout to %d\n", timeoutSet);
121    }
122    ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeoutGet);
123    if (ret) {
124        INIT_LOGE("Failed to get timeout\n");
125    }
126
127    if (timeoutGet > 0) {
128        interval = (timeoutGet > gap) ? (timeoutGet - gap) : 1;
129    }
130
131#ifdef WDIOC_SETPRETIMEOUT
132    interval = GetWatcherDogCfg(interval, timeoutGet, fd);
133#endif
134
135    while (1) {
136        ioctl(fd, WDIOC_KEEPALIVE);
137        sleep(interval);
138    }
139    close(fd);
140    return -1;
141}
142