#include #include #include #include #include #include #include #include #include #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=normal dog feeding, 1=stop dog feeding test restart, 2=exit after triggering dog feeding /* Signal Processing: Graceful Exit */ static void signal_handler(int sig) { printf("\n[%d] Receive signal %d,exit...\n", getpid(), sig); running = 0; } /* Print instructions */ static void print_usage(const char *prog) { printf("IT87 Watchdog Driver Test Program\n\n"); printf("Usage: %s [Option]\n\n", prog); printf("Option:\n"); printf(" -h Show Help\n"); printf(" -t Set dog feeding interval (Default: %dsecond)\n", DEFAULT_KEEPALIVE); printf(" -T Set the watchdog timeout (driver support required)\n"); printf(" -m Test mode: Stop feeding the dog after startup, test system reboot\n"); printf(" -e Test mode: Exit immediately after feeding the dog once (testing nowayout)\n"); printf(" -i Get watchdog information\n"); printf(" -c Enable magic to close characters 'V'\n"); printf(" -d Disable the watchdog (if supported)\n"); printf("\nExample:\n"); printf(" %s # Normal test, feed the dog every 5 seconds\n", prog); printf(" %s -t 2 # Feed the dog every 2 seconds\n", prog); printf(" %s -m -t 10 # Stop feeding the dog after 10 seconds, the system should restart\n", prog); printf(" %s -e # Test nowayout mode\n", prog); printf("\nWarning: Using the -m or -e option will cause the system to restart!\n"); } /* Get watchdog information */ static void get_watchdog_info(int fd) { struct watchdog_info info; if (ioctl(fd, WDIOC_GETSUPPORT, &info) < 0) { perror("WDIOC_GETSUPPORT Failure"); return; } printf("\n========== Watchdog Information ==========\n"); printf("Logo: %s\n", info.identity); printf("Firmware Version: %u\n", info.firmware_version); printf("Option support:\n"); if (info.options & WDIOF_OVERHEAT) printf(" - Overheat Detection\n"); if (info.options & WDIOF_FANFAULT) printf(" - Fan malfunction\n"); if (info.options & WDIOF_EXTERN1) printf(" - External signal1\n"); if (info.options & WDIOF_EXTERN2) printf(" - External signal2\n"); if (info.options & WDIOF_POWERUNDER) printf(" - Insufficient power\n"); if (info.options & WDIOF_CARDRESET) printf(" - Card restart\n"); if (info.options & WDIOF_POWEROVER) printf(" - Power overload\n"); if (info.options & WDIOF_SETTIMEOUT) printf(" - Set timeout ✓\n"); if (info.options & WDIOF_MAGICCLOSE) printf(" - Magic Off ✓\n"); if (info.options & WDIOF_PRETIMEOUT) printf(" - Pre-timeout\n"); if (info.options & WDIOF_ALARMONLY) printf(" - Alarm only\n"); if (info.options & WDIOF_KEEPALIVEPING) printf(" - Support feeding the dog ✓\n"); printf("================================\n\n"); } /* Get the current timeout */ static int get_timeout(int fd) { int timeout = 0; if (ioctl(fd, WDIOC_GETTIMEOUT, &timeout) < 0) { perror("WDIOC_GETTIMEOUT fail"); return -1; } return timeout; } /* Set timeout */ static int set_timeout(int fd, int timeout) { printf("Set the timeout to %d second...\n", timeout); if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) < 0) { perror("WDIOC_SETTIMEOUT fail"); return -1; } printf("The actual timeout set: %d second\n", timeout); return 0; } /* (keepalive) */ static int keepalive(int fd) { int dummy; if (ioctl(fd, WDIOC_KEEPALIVE, &dummy) < 0) { perror("WDIOC_KEEPALIVE fail"); return -1; } return 0; } /* Disable the watchdog */ static int disable_watchdog(int fd) { printf("Try to disable the watchdog...\n"); /* Method 1: Magic Close Character */ if (write(fd, "V", 1) != 1) { perror("Magic failed to write character"); return -1; } printf("Magic shutdown character sent 'V'\n"); return 0; } /* Main Test Loop */ static void test_loop(int fd, int keepalive_interval, int mode) { int count = 0; time_t start_time = time(NULL); printf("\n========== Start testing ==========\n"); printf("PID: %d\n", getpid()); printf("Keepalive interval: %d seconds\n", keepalive_interval); printf("Current timeout setting: %d seconds\n", get_timeout(fd)); if (mode == 1) { printf("\n⚠️ Test mode: Will stop feeding the dog after %d seconds, the system should restart!\n", keepalive_interval * 3); } else if (mode == 2) { printf("\n⚠️ Test mode: Exit immediately after feeding the dog once (testing nowayout)\n"); } else { printf("\nNormal mode: Press Ctrl+C to stop\n"); } printf("==============================\n\n"); /* First keepalive (start watchdog) */ if (keepalive(fd) < 0) { fprintf(stderr, "Initial keepalive failed\n"); return; } printf("[%3d] Initial keepalive completed, watchdog started\n", count++); if (mode == 2) { /* Test mode: exit immediately */ printf("Exit immediately, if nowayout=1, the system will restart after timeout\n"); return; } /* Main loop */ while (running) { sleep(keepalive_interval); if (!running) break; /* Test mode 1: stop feeding after specified times */ if (mode == 1 && count >= 3) { printf("\n⚠️ Intentionally stop feeding the dog! The system should restart in %d seconds...\n", get_timeout(fd)); printf("Waiting for restart (Ctrl+C can try to interrupt)...\n"); /* Continue loop but don't feed */ while (1) { sleep(1); } } /* Normal keepalive */ if (keepalive(fd) < 0) { fprintf(stderr, "Keepalive failed\n"); break; } time_t elapsed = time(NULL) - start_time; printf("[%3d] Keepalive fed (running time: %ld seconds)\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; /* Parse command line arguments */ 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, "Error: keepalive interval must be >= 1 second\n"); return 1; } break; case 'T': new_timeout = atoi(optarg); break; case 'm': test_mode = 1; // stop feeding test restart break; case 'e': test_mode = 2; // exit immediately test 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; } } /* Register signal handler */ signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); printf("IT87 Watchdog Test Program\n"); printf("Opening device: %s\n", WATCHDOG_DEV); /* Open watchdog device */ /* O_CLOEXEC: prevent child process inheritance, but watchdog usually needs to stay open */ wdt_fd = open(WATCHDOG_DEV, O_WRONLY); if (wdt_fd < 0) { perror("Cannot open watchdog device (need root privileges?)"); fprintf(stderr, "Hint: try sudo %s\n", argv[0]); return 1; } printf("Device opened successfully (fd=%d)\n", wdt_fd); /* Get information */ if (show_info) { get_watchdog_info(wdt_fd); } /* Set new timeout */ if (new_timeout > 0) { if (set_timeout(wdt_fd, new_timeout) < 0) { close(wdt_fd); return 1; } } /* Show current timeout */ int current_timeout = get_timeout(wdt_fd); if (current_timeout > 0) { printf("Current watchdog timeout: %d seconds\n", current_timeout); } /* Disable watchdog */ if (disable) { if (disable_watchdog(wdt_fd) < 0) { fprintf(stderr, "Failed to disable watchdog (nowayout may be 1)\n"); } close(wdt_fd); return 0; } /* Main test loop */ test_loop(wdt_fd, keepalive_interval, test_mode); /* Cleanup */ printf("\nClosing watchdog device...\n"); if (magic_close) { /* Try magic close */ printf("Sending magic close character 'V'...\n"); if (write(wdt_fd, "V", 1) != 1) { perror("Magic close failed"); } } close(wdt_fd); printf("Test program ended\n"); return 0; }