watchdog_app.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <signal.h>
  8. #include <sys/ioctl.h>
  9. #include <linux/watchdog.h>
  10. #define WATCHDOG_DEV "/dev/watchdog"
  11. #define DEFAULT_KEEPALIVE 5
  12. static int wdt_fd = -1;
  13. static volatile int running = 1;
  14. static int test_mode = 0; // 0=normal dog feeding, 1=stop dog feeding test restart, 2=exit after triggering dog feeding
  15. /* Signal Processing: Graceful Exit */
  16. static void signal_handler(int sig)
  17. {
  18. printf("\n[%d] Receive signal %d,exit...\n", getpid(), sig);
  19. running = 0;
  20. }
  21. /* Print instructions */
  22. static void print_usage(const char *prog)
  23. {
  24. printf("IT87 Watchdog Driver Test Program\n\n");
  25. printf("Usage: %s [Option]\n\n", prog);
  26. printf("Option:\n");
  27. printf(" -h Show Help\n");
  28. printf(" -t <second> Set dog feeding interval (Default: %dsecond)\n", DEFAULT_KEEPALIVE);
  29. printf(" -T <second> Set the watchdog timeout (driver support required)\n");
  30. printf(" -m Test mode: Stop feeding the dog after startup, test system reboot\n");
  31. printf(" -e Test mode: Exit immediately after feeding the dog once (testing nowayout)\n");
  32. printf(" -i Get watchdog information\n");
  33. printf(" -c Enable magic to close characters 'V'\n");
  34. printf(" -d Disable the watchdog (if supported)\n");
  35. printf("\nExample:\n");
  36. printf(" %s # Normal test, feed the dog every 5 seconds\n", prog);
  37. printf(" %s -t 2 # Feed the dog every 2 seconds\n", prog);
  38. printf(" %s -m -t 10 # Stop feeding the dog after 10 seconds, the system should restart\n", prog);
  39. printf(" %s -e # Test nowayout mode\n", prog);
  40. printf("\nWarning: Using the -m or -e option will cause the system to restart!\n");
  41. }
  42. /* Get watchdog information */
  43. static void get_watchdog_info(int fd)
  44. {
  45. struct watchdog_info info;
  46. if (ioctl(fd, WDIOC_GETSUPPORT, &info) < 0) {
  47. perror("WDIOC_GETSUPPORT Failure");
  48. return;
  49. }
  50. printf("\n========== Watchdog Information ==========\n");
  51. printf("Logo: %s\n", info.identity);
  52. printf("Firmware Version: %u\n", info.firmware_version);
  53. printf("Option support:\n");
  54. if (info.options & WDIOF_OVERHEAT) printf(" - Overheat Detection\n");
  55. if (info.options & WDIOF_FANFAULT) printf(" - Fan malfunction\n");
  56. if (info.options & WDIOF_EXTERN1) printf(" - External signal1\n");
  57. if (info.options & WDIOF_EXTERN2) printf(" - External signal2\n");
  58. if (info.options & WDIOF_POWERUNDER) printf(" - Insufficient power\n");
  59. if (info.options & WDIOF_CARDRESET) printf(" - Card restart\n");
  60. if (info.options & WDIOF_POWEROVER) printf(" - Power overload\n");
  61. if (info.options & WDIOF_SETTIMEOUT) printf(" - Set timeout ✓\n");
  62. if (info.options & WDIOF_MAGICCLOSE) printf(" - Magic Off ✓\n");
  63. if (info.options & WDIOF_PRETIMEOUT) printf(" - Pre-timeout\n");
  64. if (info.options & WDIOF_ALARMONLY) printf(" - Alarm only\n");
  65. if (info.options & WDIOF_KEEPALIVEPING) printf(" - Support feeding the dog ✓\n");
  66. printf("================================\n\n");
  67. }
  68. /* Get the current timeout */
  69. static int get_timeout(int fd)
  70. {
  71. int timeout = 0;
  72. if (ioctl(fd, WDIOC_GETTIMEOUT, &timeout) < 0) {
  73. perror("WDIOC_GETTIMEOUT fail");
  74. return -1;
  75. }
  76. return timeout;
  77. }
  78. /* Set timeout */
  79. static int set_timeout(int fd, int timeout)
  80. {
  81. printf("Set the timeout to %d second...\n", timeout);
  82. if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) < 0) {
  83. perror("WDIOC_SETTIMEOUT fail");
  84. return -1;
  85. }
  86. printf("The actual timeout set: %d second\n", timeout);
  87. return 0;
  88. }
  89. /* (keepalive) */
  90. static int keepalive(int fd)
  91. {
  92. int dummy;
  93. if (ioctl(fd, WDIOC_KEEPALIVE, &dummy) < 0) {
  94. perror("WDIOC_KEEPALIVE fail");
  95. return -1;
  96. }
  97. return 0;
  98. }
  99. /* Disable the watchdog */
  100. static int disable_watchdog(int fd)
  101. {
  102. printf("Try to disable the watchdog...\n");
  103. /* Method 1: Magic Close Character */
  104. if (write(fd, "V", 1) != 1) {
  105. perror("Magic failed to write character");
  106. return -1;
  107. }
  108. printf("Magic shutdown character sent 'V'\n");
  109. return 0;
  110. }
  111. /* Main Test Loop */
  112. static void test_loop(int fd, int keepalive_interval, int mode)
  113. {
  114. int count = 0;
  115. time_t start_time = time(NULL);
  116. printf("\n========== Start testing ==========\n");
  117. printf("PID: %d\n", getpid());
  118. printf("Keepalive interval: %d seconds\n", keepalive_interval);
  119. printf("Current timeout setting: %d seconds\n", get_timeout(fd));
  120. if (mode == 1) {
  121. printf("\n⚠️ Test mode: Will stop feeding the dog after %d seconds, the system should restart!\n",
  122. keepalive_interval * 3);
  123. } else if (mode == 2) {
  124. printf("\n⚠️ Test mode: Exit immediately after feeding the dog once (testing nowayout)\n");
  125. } else {
  126. printf("\nNormal mode: Press Ctrl+C to stop\n");
  127. }
  128. printf("==============================\n\n");
  129. /* First keepalive (start watchdog) */
  130. if (keepalive(fd) < 0) {
  131. fprintf(stderr, "Initial keepalive failed\n");
  132. return;
  133. }
  134. printf("[%3d] Initial keepalive completed, watchdog started\n", count++);
  135. if (mode == 2) {
  136. /* Test mode: exit immediately */
  137. printf("Exit immediately, if nowayout=1, the system will restart after timeout\n");
  138. return;
  139. }
  140. /* Main loop */
  141. while (running) {
  142. sleep(keepalive_interval);
  143. if (!running)
  144. break;
  145. /* Test mode 1: stop feeding after specified times */
  146. if (mode == 1 && count >= 3) {
  147. printf("\n⚠️ Intentionally stop feeding the dog! The system should restart in %d seconds...\n",
  148. get_timeout(fd));
  149. printf("Waiting for restart (Ctrl+C can try to interrupt)...\n");
  150. /* Continue loop but don't feed */
  151. while (1) {
  152. sleep(1);
  153. }
  154. }
  155. /* Normal keepalive */
  156. if (keepalive(fd) < 0) {
  157. fprintf(stderr, "Keepalive failed\n");
  158. break;
  159. }
  160. time_t elapsed = time(NULL) - start_time;
  161. printf("[%3d] Keepalive fed (running time: %ld seconds)\n", count++, elapsed);
  162. fflush(stdout);
  163. }
  164. }
  165. int main(int argc, char *argv[])
  166. {
  167. int opt;
  168. int keepalive_interval = DEFAULT_KEEPALIVE;
  169. int new_timeout = 0;
  170. int show_info = 0;
  171. int magic_close = 0;
  172. int disable = 0;
  173. /* Parse command line arguments */
  174. while ((opt = getopt(argc, argv, "ht:T:meicd")) != -1) {
  175. switch (opt) {
  176. case 'h':
  177. print_usage(argv[0]);
  178. return 0;
  179. case 't':
  180. keepalive_interval = atoi(optarg);
  181. if (keepalive_interval < 1) {
  182. fprintf(stderr, "Error: keepalive interval must be >= 1 second\n");
  183. return 1;
  184. }
  185. break;
  186. case 'T':
  187. new_timeout = atoi(optarg);
  188. break;
  189. case 'm':
  190. test_mode = 1; // stop feeding test restart
  191. break;
  192. case 'e':
  193. test_mode = 2; // exit immediately test nowayout
  194. break;
  195. case 'i':
  196. show_info = 1;
  197. break;
  198. case 'c':
  199. magic_close = 1;
  200. break;
  201. case 'd':
  202. disable = 1;
  203. break;
  204. default:
  205. print_usage(argv[0]);
  206. return 1;
  207. }
  208. }
  209. /* Register signal handler */
  210. signal(SIGINT, signal_handler);
  211. signal(SIGTERM, signal_handler);
  212. printf("IT87 Watchdog Test Program\n");
  213. printf("Opening device: %s\n", WATCHDOG_DEV);
  214. /* Open watchdog device */
  215. /* O_CLOEXEC: prevent child process inheritance, but watchdog usually needs to stay open */
  216. wdt_fd = open(WATCHDOG_DEV, O_WRONLY);
  217. if (wdt_fd < 0) {
  218. perror("Cannot open watchdog device (need root privileges?)");
  219. fprintf(stderr, "Hint: try sudo %s\n", argv[0]);
  220. return 1;
  221. }
  222. printf("Device opened successfully (fd=%d)\n", wdt_fd);
  223. /* Get information */
  224. if (show_info) {
  225. get_watchdog_info(wdt_fd);
  226. }
  227. /* Set new timeout */
  228. if (new_timeout > 0) {
  229. if (set_timeout(wdt_fd, new_timeout) < 0) {
  230. close(wdt_fd);
  231. return 1;
  232. }
  233. }
  234. /* Show current timeout */
  235. int current_timeout = get_timeout(wdt_fd);
  236. if (current_timeout > 0) {
  237. printf("Current watchdog timeout: %d seconds\n", current_timeout);
  238. }
  239. /* Disable watchdog */
  240. if (disable) {
  241. if (disable_watchdog(wdt_fd) < 0) {
  242. fprintf(stderr, "Failed to disable watchdog (nowayout may be 1)\n");
  243. }
  244. close(wdt_fd);
  245. return 0;
  246. }
  247. /* Main test loop */
  248. test_loop(wdt_fd, keepalive_interval, test_mode);
  249. /* Cleanup */
  250. printf("\nClosing watchdog device...\n");
  251. if (magic_close) {
  252. /* Try magic close */
  253. printf("Sending magic close character 'V'...\n");
  254. if (write(wdt_fd, "V", 1) != 1) {
  255. perror("Magic close failed");
  256. }
  257. }
  258. close(wdt_fd);
  259. printf("Test program ended\n");
  260. return 0;
  261. }