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