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