Maximum ping time should be 120 seconds.
[watchdog-test-framework.git] / watchdog-test.c
1 /* watchdog-test framework
2  * Copyright (C) 2014-2015 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <time.h>
26 #include <fcntl.h>
27 #include <sys/ioctl.h>
28 #include <linux/watchdog.h>
29
30 #define WATCHDOG_DEVICE "/dev/watchdog"
31 #define WATCHDOG_TIMEOUT_DEFAULT 30
32
33 #define MIN(a,b) ((a)<(b)?(a):(b))
34
35 enum { HELP_OPTION = CHAR_MAX + 1 };
36
37 static const char *options = "";
38 static const struct option long_options[] = {
39   { "timeout", 1, 0, 0 },
40   { "yes", 0, 0, 0 },
41   { 0, 0, 0, 0 }
42 };
43
44 static void
45 usage (int r)
46 {
47   printf ("usage: watchdog-test [--timeout=TIMEOUT] [--yes]\n");
48   exit (r);
49 }
50
51 int
52 main (int argc, char *argv[])
53 {
54   int watchdog_timeout = WATCHDOG_TIMEOUT_DEFAULT;
55   int ping_time;
56   int fd;
57   int timeout;
58   char input[256];
59   time_t start_t, t;
60   int option_index, c, yes = 0;
61
62   /* Parse the command line. */
63   for (;;) {
64     c = getopt_long (argc, argv, options, long_options, &option_index);
65     if (c == -1) break;
66
67     switch (c) {
68     case 0:                     /* options which are long only */
69       if (strcmp (long_options[option_index].name, "timeout") == 0) {
70         if (sscanf (optarg, "%d", &watchdog_timeout) != 1) {
71           fprintf (stderr, "%s: invalid --timeout option\n", argv[0]);
72           exit (EXIT_FAILURE);
73         }
74       } else if (strcmp (long_options[option_index].name, "yes") == 0) {
75         yes = 1;
76       } else {
77         fprintf (stderr, "%s: unknown long option: %s (%d)\n",
78                  argv[0], long_options[option_index].name, option_index);
79         exit (EXIT_FAILURE);
80       }
81       break;
82
83     case HELP_OPTION:
84       usage (EXIT_SUCCESS);
85
86     default:
87       usage (EXIT_FAILURE);
88     }
89   }
90
91   ping_time = MIN (watchdog_timeout * 2, 120);
92
93   setvbuf (stdout, NULL, _IONBF, 0);
94
95   printf ("\n");
96   printf ("Welcome to the watchdog test framework.\n");
97   printf ("You should read the README file and run this in the guest.\n");
98   printf ("DO NOT RUN IT IN THE HOST!\n");
99   printf ("\n");
100   printf ("The test is as follows:\n");
101   printf ("(1) I will set up the watchdog with a %d second timeout.\n",
102           watchdog_timeout);
103   printf ("(2) I will ping the watchdog for %d seconds.  During this time\n"
104           "    the guest should run normally.\n",
105           ping_time);
106   printf ("(3) I will stop pinging the watchdog and just count up.  If the\n"
107           "    virtual watchdog device is set correctly, then the watchdog\n"
108           "    action (eg. reboot) should happen around the %d second mark.\n",
109           watchdog_timeout);
110   printf ("\n");
111
112   if (!yes) {
113     printf ("Do you want to start the test?  Type \"yes\" without quotes:\n");
114
115     if (fgets (input, sizeof input, stdin) == NULL ||
116         strncmp (input, "yes", 3) != 0) {
117       printf ("Exiting the program.\n");
118       exit (EXIT_SUCCESS);
119     }
120
121     printf ("\n");
122   }
123
124   printf ("Setting up the watchdog (%s) with a %d second timeout.\n",
125           WATCHDOG_DEVICE, watchdog_timeout);
126
127   sync ();
128   fd = open (WATCHDOG_DEVICE, O_WRONLY);
129   if (fd == -1) {
130     perror (WATCHDOG_DEVICE);
131     exit (EXIT_FAILURE);
132   }
133
134   timeout = watchdog_timeout;
135   if (ioctl (fd, WDIOC_SETTIMEOUT, &timeout) == -1) {
136     perror ("ioctl: WDIOC_SETTIMEOUT: error setting timeout");
137     exit (EXIT_FAILURE);
138   }
139
140   if (ioctl (fd, WDIOC_GETTIMEOUT, &timeout) == -1)
141     perror ("ioctl: WDIOC_GETTIMEOUT");
142   else {
143     printf ("Timeout is set to %d seconds.\n", timeout);
144     if (timeout != watchdog_timeout)
145       printf ("Note: some watchdog devices don't support setting exact timeout values.\n");
146   }
147
148   printf ("\n");
149   printf ("Pinging the watchdog for %d seconds ...\n", ping_time);
150   printf ("\n");
151
152   time (&start_t);
153   for (;;) {
154     time (&t);
155     if (t - start_t > ping_time)
156       break;
157     printf ("%d...\n", (int) (t - start_t));
158
159     sync ();
160
161     sleep (3);
162
163     printf ("ping\n");
164     if (ioctl (fd, WDIOC_KEEPALIVE, 0) == -1)
165       perror ("\nioctl: WDIOC_KEEPALIVE");
166   }
167
168   printf ("\n");
169   printf ("\n");
170   printf ("Stopping pings.\n");
171   printf ("The watchdog action should happen at approximately %d second mark.\n",
172           watchdog_timeout);
173   printf ("\n");
174
175   time (&start_t);
176   for (;;) {
177     time (&t);
178     printf ("%d...\n", (int) (t - start_t));
179     sync ();
180     sleep (3);
181   }
182
183   /*NOTREACHED*/
184   exit (EXIT_SUCCESS);
185 }