| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * it87_wdt_test.c - IT87 看门狗驱动测试程序
- *
- * 编译: gcc -o it87_wdt_test it87_wdt_test.c -Wall
- * 运行: sudo ./it87_wdt_test [选项]
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/ioctl.h>
- #include <linux/watchdog.h>
- #define WATCHDOG_DEV "/dev/watchdog"
- #define DEFAULT_KEEPALIVE 5 // 默认喂狗间隔(秒)
- static int wdt_fd = -1;
- static volatile int running = 1;
- static int test_mode = 0; // 0=正常喂狗, 1=停止喂狗测试重启, 2=触发喂狗后退出
- /* 信号处理:优雅退出 */
- static void signal_handler(int sig)
- {
- printf("\n[%d] 收到信号 %d,准备退出...\n", getpid(), sig);
- running = 0;
- }
- /* 打印使用说明 */
- static void print_usage(const char *prog)
- {
- printf("IT87 看门狗驱动测试程序\n\n");
- printf("用法: %s [选项]\n\n", prog);
- printf("选项:\n");
- printf(" -h 显示帮助\n");
- printf(" -t <秒> 设置喂狗间隔 (默认: %d秒)\n", DEFAULT_KEEPALIVE);
- printf(" -T <秒> 设置看门狗超时时间 (需要驱动支持)\n");
- printf(" -m 测试模式: 启动后停止喂狗,测试系统重启\n");
- printf(" -e 测试模式: 喂狗一次后立即退出(测试 nowayout)\n");
- printf(" -i 获取看门狗信息\n");
- printf(" -c 启用魔法关闭字符 'V'\n");
- printf(" -d 禁用看门狗(如果支持)\n");
- printf("\n示例:\n");
- printf(" %s # 正常测试,每5秒喂狗\n", prog);
- printf(" %s -t 2 # 每2秒喂狗一次\n", prog);
- printf(" %s -m -t 10 # 10秒后停止喂狗,系统应该重启\n", prog);
- printf(" %s -e # 测试 nowayout 模式\n", prog);
- printf("\n警告: 使用 -m 或 -e 选项会导致系统重启!\n");
- }
- /* 获取看门狗信息 */
- static void get_watchdog_info(int fd)
- {
- struct watchdog_info info;
- if (ioctl(fd, WDIOC_GETSUPPORT, &info) < 0) {
- perror("WDIOC_GETSUPPORT 失败");
- return;
- }
- printf("\n========== 看门狗信息 ==========\n");
- printf("标识: %s\n", info.identity);
- printf("固件版本: %u\n", info.firmware_version);
- printf("选项支持:\n");
- if (info.options & WDIOF_OVERHEAT) printf(" - 过热检测\n");
- if (info.options & WDIOF_FANFAULT) printf(" - 风扇故障\n");
- if (info.options & WDIOF_EXTERN1) printf(" - 外部信号1\n");
- if (info.options & WDIOF_EXTERN2) printf(" - 外部信号2\n");
- if (info.options & WDIOF_POWERUNDER) printf(" - 电源不足\n");
- if (info.options & WDIOF_CARDRESET) printf(" - 卡片重启\n");
- if (info.options & WDIOF_POWEROVER) printf(" - 电源过载\n");
- if (info.options & WDIOF_SETTIMEOUT) printf(" - 设置超时时间 ✓\n");
- if (info.options & WDIOF_MAGICCLOSE) printf(" - 魔法关闭 ✓\n");
- if (info.options & WDIOF_PRETIMEOUT) printf(" - 预超时\n");
- if (info.options & WDIOF_ALARMONLY) printf(" - 仅报警\n");
- if (info.options & WDIOF_KEEPALIVEPING) printf(" - 喂狗支持 ✓\n");
- printf("================================\n\n");
- }
- /* 获取当前超时时间 */
- static int get_timeout(int fd)
- {
- int timeout = 0;
- if (ioctl(fd, WDIOC_GETTIMEOUT, &timeout) < 0) {
- perror("WDIOC_GETTIMEOUT 失败");
- return -1;
- }
- return timeout;
- }
- /* 设置超时时间 */
- static int set_timeout(int fd, int timeout)
- {
- printf("设置超时时间为 %d 秒...\n", timeout);
- if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) < 0) {
- perror("WDIOC_SETTIMEOUT 失败");
- return -1;
- }
- printf("实际设置的超时时间: %d 秒\n", timeout);
- return 0;
- }
- /* 喂狗(keepalive) */
- static int keepalive(int fd)
- {
- int dummy;
- if (ioctl(fd, WDIOC_KEEPALIVE, &dummy) < 0) {
- perror("WDIOC_KEEPALIVE 失败");
- return -1;
- }
- return 0;
- }
- /* 禁用看门狗 */
- static int disable_watchdog(int fd)
- {
- printf("尝试禁用看门狗...\n");
- /* 方法1: 魔法关闭字符 */
- if (write(fd, "V", 1) != 1) {
- perror("魔法关闭字符写入失败");
- return -1;
- }
- printf("已发送魔法关闭字符 'V'\n");
- return 0;
- }
- /* 主测试循环 */
- static void test_loop(int fd, int keepalive_interval, int mode)
- {
- int count = 0;
- time_t start_time = time(NULL);
- printf("\n========== 开始测试 ==========\n");
- printf("PID: %d\n", getpid());
- printf("喂狗间隔: %d 秒\n", keepalive_interval);
- printf("当前超时设置: %d 秒\n", get_timeout(fd));
- if (mode == 1) {
- printf("\n⚠️ 测试模式: 将在 %d 秒后停止喂狗,系统应该重启!\n",
- keepalive_interval * 3);
- } else if (mode == 2) {
- printf("\n⚠️ 测试模式: 喂狗一次后立即退出,测试 nowayout\n");
- } else {
- printf("\n正常模式: 按 Ctrl+C 停止\n");
- }
- printf("==============================\n\n");
- /* 第一次喂狗(启动看门狗) */
- if (keepalive(fd) < 0) {
- fprintf(stderr, "初始喂狗失败\n");
- return;
- }
- printf("[%3d] 初始喂狗完成,看门狗已启动\n", count++);
- if (mode == 2) {
- /* 测试模式: 立即退出 */
- printf("立即退出,如果 nowayout=1,系统将在超时后重启\n");
- return;
- }
- /* 主循环 */
- while (running) {
- sleep(keepalive_interval);
- if (!running)
- break;
- /* 测试模式1: 在指定次数后停止喂狗 */
- if (mode == 1 && count >= 3) {
- printf("\n⚠️ 故意停止喂狗!系统应在 %d 秒后重启...\n",
- get_timeout(fd));
- printf("等待重启中(按 Ctrl+C 可尝试中断)...\n");
- /* 继续循环但不喂狗 */
- while (1) {
- sleep(1);
- }
- }
- /* 正常喂狗 */
- if (keepalive(fd) < 0) {
- fprintf(stderr, "喂狗失败\n");
- break;
- }
- time_t elapsed = time(NULL) - start_time;
- printf("[%3d] 已喂狗 (运行时间: %ld 秒)\n", count++, elapsed);
- fflush(stdout);
- }
- }
- int main(int argc, char *argv[])
- {
- int opt;
- int keepalive_interval = DEFAULT_KEEPALIVE;
- int new_timeout = 0;
- int show_info = 0;
- int magic_close = 0;
- int disable = 0;
- /* 解析命令行参数 */
- while ((opt = getopt(argc, argv, "ht:T:meicd")) != -1) {
- switch (opt) {
- case 'h':
- print_usage(argv[0]);
- return 0;
- case 't':
- keepalive_interval = atoi(optarg);
- if (keepalive_interval < 1) {
- fprintf(stderr, "错误: 喂狗间隔必须 >= 1 秒\n");
- return 1;
- }
- break;
- case 'T':
- new_timeout = atoi(optarg);
- break;
- case 'm':
- test_mode = 1; // 停止喂狗测试重启
- break;
- case 'e':
- test_mode = 2; // 立即退出测试 nowayout
- break;
- case 'i':
- show_info = 1;
- break;
- case 'c':
- magic_close = 1;
- break;
- case 'd':
- disable = 1;
- break;
- default:
- print_usage(argv[0]);
- return 1;
- }
- }
- /* 注册信号处理 */
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
- printf("IT87 看门狗测试程序\n");
- printf("打开设备: %s\n", WATCHDOG_DEV);
- /* 打开看门狗设备 */
- /* O_CLOEXEC: 防止子进程继承,但看门狗通常需要保持打开 */
- wdt_fd = open(WATCHDOG_DEV, O_WRONLY);
- if (wdt_fd < 0) {
- perror("无法打开看门狗设备(需要 root 权限?)");
- fprintf(stderr, "提示: 尝试 sudo %s\n", argv[0]);
- return 1;
- }
- printf("设备打开成功 (fd=%d)\n", wdt_fd);
- /* 获取信息 */
- if (show_info) {
- get_watchdog_info(wdt_fd);
- }
- /* 设置新的超时时间 */
- if (new_timeout > 0) {
- if (set_timeout(wdt_fd, new_timeout) < 0) {
- close(wdt_fd);
- return 1;
- }
- }
- /* 显示当前超时 */
- int current_timeout = get_timeout(wdt_fd);
- if (current_timeout > 0) {
- printf("当前看门狗超时: %d 秒\n", current_timeout);
- }
- /* 禁用看门狗 */
- if (disable) {
- if (disable_watchdog(wdt_fd) < 0) {
- fprintf(stderr, "禁用看门狗失败(可能 nowayout=1)\n");
- }
- close(wdt_fd);
- return 0;
- }
- /* 主测试循环 */
- test_loop(wdt_fd, keepalive_interval, test_mode);
- /* 清理 */
- printf("\n关闭看门狗设备...\n");
- if (magic_close) {
- /* 尝试魔法关闭 */
- printf("发送魔法关闭字符 'V'...\n");
- if (write(wdt_fd, "V", 1) != 1) {
- perror("魔法关闭失败");
- }
- }
- close(wdt_fd);
- printf("测试程序结束\n");
- return 0;
- }
|