| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #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=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 <second> Set dog feeding interval (Default: %dsecond)\n", DEFAULT_KEEPALIVE);
- printf(" -T <second> 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;
- }
|