Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[openvswitch] / utilities / ovs-wdt.c
1 /* Copyright (c) 2008, 2009 Nicira Networks, Inc.
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * In addition, as a special exception, Nicira Networks gives permission
17  * to link the code of its release of vswitchd with the OpenSSL project's
18  * "OpenSSL" library (or with modified versions of it that use the same
19  * license as the "OpenSSL" library), and distribute the linked
20  * executables.  You must obey the GNU General Public License in all
21  * respects for all of the code used other than "OpenSSL".  If you modify
22  * this file, you may extend this exception to your version of the file,
23  * but you are not obligated to do so.  If you do not wish to do so,
24  * delete this exception statement from your version.
25  *
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <getopt.h>
35 #include <signal.h>
36 #include <sys/ioctl.h>
37 #include <linux/types.h>
38 #include <linux/watchdog.h>
39
40
41 /* Default values for the interval and timer.  In seconds. */
42 #define DEFAULT_INTERVAL  1
43 #define DEFAULT_TIMEOUT   30
44
45 int fd = -1;
46
47 /* The WDT is automatically enabled when /dev/watchdog is opened.  If we
48  * do not send the magic value to the device first before exiting, the 
49  * system will reboot.  This function allows the program to exit without 
50  * causing a reboot.
51  */
52 static void
53 cleanup(void)
54 {
55     if (fd == -1) {
56         return;
57     }
58
59     /* Writing the magic value "V" to the device is an indication that
60      * the device is about to be closed.  This causes the watchdog to be
61      * disabled after the call to close.
62      */
63     if (write(fd, "V", 1) != 1) {
64         fprintf(stderr, "Couldn't write magic val: %d\n", errno);
65         return;
66     }
67     close(fd); 
68     fd = -1;
69 }
70
71
72 /* If we receive a SIGINT, cleanup first, which will disable the
73  * watchdog timer.
74  */
75 static void
76 sighandler(int signum)
77 {
78     cleanup();
79     signal(signum, SIG_DFL);
80     raise(signum);
81 }
82
83 static void
84 setup_signal(void)
85 {
86     struct sigaction action;
87
88     action.sa_handler = sighandler;
89     sigemptyset(&action.sa_mask);
90     action.sa_flags = 0;
91
92     if (sigaction(SIGINT, &action, NULL) != 0) {
93         fprintf(stderr, "Problem setting up SIGINT handler...\n");
94     }
95     if (sigaction(SIGTERM, &action, NULL) != 0) {
96         fprintf(stderr, "Problem setting up SIGTERM handler...\n");
97     }
98 }
99
100
101 /* Print information on the WDT hardware */
102 static void
103 print_wdt_info(void)
104 {
105     struct watchdog_info ident;
106
107     if (ioctl(fd, WDIOC_GETSUPPORT, &ident) == -1) {
108         fprintf(stderr, "Couldn't get version: %d\n", errno);
109         cleanup();
110         exit(-1);
111     }
112     printf("identity: %s, ver: %d, opt: %#x\n", ident.identity, 
113             ident.firmware_version, ident.options);
114 }
115
116
117 static void
118 print_help(char *progname)
119 {
120     printf("%s: Watchdog timer utility\n", progname);
121     printf("usage: %s [OPTIONS]\n\n", progname);
122     printf("Options:\n");
123     printf("  -t, --timeout=SECS     expiration time of WDT (default: %d)\n",
124             DEFAULT_TIMEOUT);
125     printf("  -i, --interval=SECS    interval to send keep-alives (default: %d)\n",
126             DEFAULT_INTERVAL);
127     printf("  -d, --disable          disable the WDT and exit\n");
128     printf("  -h, --help             display this help message\n");
129     printf("  -v, --verbose          enable verbose printing\n");
130     printf("  -V, --version          display version information of WDT and exit\n");
131 }
132
133
134 int main(int argc, char *argv[])
135 {
136     int arg;
137     int optc;
138     int verbose = 0;
139     int interval = DEFAULT_INTERVAL;
140     int timeout = DEFAULT_TIMEOUT;
141     static struct option const longopts[] =
142     { 
143         {"timeout", required_argument, NULL, 't'},
144         {"interval", required_argument, NULL, 'i'},
145         {"disable", no_argument, NULL, 'd'},
146         {"help", no_argument, NULL, 'h'},
147         {"verbose", no_argument, NULL, 'v'},
148         {"version", no_argument, NULL, 'V'},
149         {0, 0, 0, 0}
150     };
151
152     setup_signal();
153
154     fd = open("/dev/watchdog", O_RDWR);
155     if (fd == -1) {
156         fprintf(stderr, "Couldn't open watchdog device: %s\n", strerror(errno));
157         exit(-1);
158     }
159
160     while ((optc = getopt_long(argc, argv, "t:i:dh?vV", longopts, NULL)) != -1) {
161         switch (optc) {
162         case 't':
163             timeout = strtol(optarg, NULL, 10);
164             if (!timeout) {
165                 fprintf(stderr, "Invalid timeout: %s\n", optarg);
166                 goto error;
167             }
168             break;
169
170        case 'i':
171             interval = strtol(optarg, NULL, 10);
172             if (!interval) {
173                 fprintf(stderr, "Invalid interval: %s\n", optarg);
174                 goto error;
175             }
176             break;
177
178         case 'd':
179             arg = WDIOS_DISABLECARD;
180             if (ioctl(fd, WDIOC_SETOPTIONS, &arg) == -1) {
181                 fprintf(stderr, "Couldn't disable: %d\n", errno);
182                 goto error;
183             }
184             cleanup();
185             exit(0);
186             break;
187
188         case 'h':
189             print_help(argv[0]);
190             cleanup();
191             exit(0);
192             break;
193
194         case 'v':
195             verbose = 1;
196             break;
197
198         case 'V':
199             print_wdt_info();
200             cleanup();
201             exit(0);
202             break;
203
204         default:
205             print_help(argv[0]);
206             goto error;
207             break;
208         }
209     }
210
211     argc -= optind;
212     argv += optind;
213
214     /* Sanity-check the arguments */
215     if (argc != 0) {
216         fprintf(stderr, "Illegal argument: %s\n", argv[0]);
217         goto error;
218     }
219
220     if (verbose) {
221         print_wdt_info();
222         printf("timeout: %d, interval: %d\n", timeout, interval);
223     }
224
225     /* Prevent the interval being greater than the timeout, since it
226      * will always cause a reboot.
227      */
228     if (interval > timeout) {
229         fprintf(stderr, "Interval greater than timeout: %d > %d\n", 
230                 interval, timeout);
231         goto error;
232     }
233
234     /* Always set the timeout */
235     if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) == -1) {
236         fprintf(stderr, "Couldn't set timeout: %d\n", errno);
237         goto error;
238     }
239
240     /* Loop and send a keep-alive every "interval" seconds */
241     while (1) {
242         if (verbose) {
243             if (ioctl(fd, WDIOC_GETTIMELEFT, &arg) == -1) {
244                 fprintf(stderr, "Couldn't get time left: %d\n", errno);
245                 goto error;
246             }
247             printf("Sending keep alive, time remaining: %d\n", arg);
248         }
249
250         /* Send a keep-alive.  The argument is ignored */
251         if (ioctl(fd, WDIOC_KEEPALIVE, &arg) == -1) {
252             fprintf(stderr, "Couldn't keepalive: %d\n", errno);
253             goto error;
254         }
255
256         sleep(interval);
257     }
258
259     /* Never directly reached... */
260 error:
261     cleanup();
262     exit(-1);
263 }