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