1 /* $NetBSD: wdogctl.c,v 1.17 2006/08/13 23:24:53 wiz Exp $ */
4 * Copyright (c) 2000 Zembu Labs, Inc.
7 * Author: Jason R. Thorpe <thorpej@zembu.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Zembu Labs, Inc.
20 * 4. Neither the name of Zembu Labs nor the names of its employees may
21 * be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
25 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
26 * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
27 * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: wdogctl.c,v 1.17 2006/08/13 23:24:53 wiz Exp $");
42 #include <sys/param.h>
43 #include <sys/ioctl.h>
57 #define _PATH_WATCHDOG "/dev/watchdog"
59 int main(int, char *[]);
60 void enable_kernel(const char *, u_int
);
61 void enable_user(const char *, u_int
, int);
62 void enable_ext(const char *, u_int
);
63 void tickle_ext(void);
65 void prep_wmode(struct wdog_mode
*, int, const char *, u_int
);
66 void list_timers(void);
71 /* Caution -- ordered list; entries >= CMD_EXT_TICKLE set timers */
73 CMD_NONE
, /* No verb given */
83 main(int argc
, char *argv
[])
85 enum cmd command
= CMD_NONE
;
88 u_int period
= WDOG_PERIOD_DEFAULT
;
90 while ((ch
= getopt(argc
, argv
, "Adekp:utx")) != -1) {
97 if (command
!= CMD_NONE
)
99 command
= CMD_DISABLE
;
103 if (command
!= CMD_NONE
)
105 command
= CMD_EXT_TICKLE
;
109 if (command
!= CMD_NONE
)
111 command
= CMD_KERN_TICKLE
;
115 if (command
!= CMD_NONE
)
117 command
= CMD_DOTICKLE
;
125 period
= (unsigned int)tmp
;
130 if (command
!= CMD_NONE
)
133 (ch
== 'u') ? CMD_USER_TICKLE
: CMD_NOCANCEL_TICKLE
;
144 if (command
< CMD_EXT_TICKLE
) {
145 if (Aflag
|| period_flag
)
149 } else if (argc
!= 1)
163 enable_ext(argv
[0], period
);
165 case CMD_KERN_TICKLE
:
166 enable_kernel(argv
[0], period
);
168 case CMD_NOCANCEL_TICKLE
:
169 case CMD_USER_TICKLE
:
170 enable_user(argv
[0], period
, command
== CMD_USER_TICKLE
);
177 prep_wmode(struct wdog_mode
*wp
, int mode
, const char *name
, u_int period
)
179 if (strlen(name
) >= WDOG_NAMESIZE
)
180 errx(EXIT_FAILURE
, "invalid watchdog timer name: %s", name
);
182 strlcpy(wp
->wm_name
, name
, sizeof(wp
->wm_name
));
184 wp
->wm_period
= period
;
186 wp
->wm_mode
|= WDOG_FEATURE_ALARM
;
190 enable_kernel(const char *name
, u_int period
)
195 prep_wmode(&wm
, WDOG_MODE_KTICKLE
, name
, period
);
197 fd
= open(_PATH_WATCHDOG
, O_RDWR
, 0644);
199 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
201 if (ioctl(fd
, WDOGIOC_SMODE
, &wm
) == -1)
202 err(EXIT_FAILURE
, "WDOGIOC_SMODE");
206 enable_ext(const char *name
, u_int period
)
211 prep_wmode(&wm
, WDOG_MODE_ETICKLE
, name
, period
);
213 fd
= open(_PATH_WATCHDOG
, O_RDWR
, 0644);
215 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
216 if (ioctl(fd
, WDOGIOC_SMODE
, &wm
) == -1) {
217 err(EXIT_FAILURE
, "WDOGIOC_SMODE");
219 if (ioctl(fd
, WDOGIOC_TICKLE
) == -1)
220 syslog(LOG_EMERG
, "unable to tickle watchdog timer %s: %m",
226 enable_user(const char *name
, u_int period
, int cancel_on_close
)
234 (cancel_on_close
) ? WDOG_MODE_UTICKLE
: WDOG_MODE_ETICKLE
, name
,
237 fd
= open(_PATH_WATCHDOG
, O_RDWR
, 0644);
239 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
241 /* ...so we can log failures to tickle the timer. */
242 openlog("wdogctl", LOG_PERROR
|LOG_PID
, LOG_DAEMON
);
245 * We fork a child process which detaches from the controlling
246 * terminal once the timer is armed, and tickles the timer
247 * until we send it a SIGTERM.
251 err(EXIT_FAILURE
, "unable to fork tickler process");
252 else if (tickler
!= 0) {
253 if (ioctl(fd
, WDOGIOC_SMODE
, &wm
) == -1) {
254 (void)kill(tickler
, SIGTERM
);
255 err(EXIT_FAILURE
, "WDOGIOC_SMODE");
263 * Wait for the watchdog to be armed. When it is, loop,
264 * tickling the timer, then waiting 1/2 the period before
267 * If the parent fails to enable the watchdog, it will kill
271 rv
= ioctl(fd
, WDOGIOC_WHICH
, &wm
);
274 if (ioctl(fd
, WDOGIOC_TICKLE
) == -1)
275 syslog(LOG_EMERG
, "unable to tickle watchdog timer %s: %m",
279 * Now detach from the controlling terminal, and just run
280 * in the background. The kernel will keep track of who
281 * we are, each time we tickle the timer.
283 if (daemon(0, 0) == -1) {
285 * We weren't able to go into the background. When
286 * we exit, the kernel will disable the watchdog so
287 * that the system won't die.
289 err(EXIT_FAILURE
, "unable to detach from terminal");
292 if (ioctl(fd
, WDOGIOC_TICKLE
) == -1)
293 syslog(LOG_EMERG
, "unable to tickle watchdog timer %s: %m",
297 ts
.tv_sec
= wm
.wm_period
/ 2;
299 (void)nanosleep(&ts
, NULL
);
301 if (ioctl(fd
, WDOGIOC_TICKLE
) == -1)
303 "unable to tickle watchdog timer %s: %m",
314 fd
= open(_PATH_WATCHDOG
, O_RDWR
, 0644);
316 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
317 if (ioctl(fd
, WDOGIOC_TICKLE
) == -1)
318 fprintf(stderr
, "Cannot tickle timer\n");
328 fd
= open(_PATH_WATCHDOG
, O_RDWR
, 0644);
330 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
332 if (ioctl(fd
, WDOGIOC_WHICH
, &wm
) == -1) {
333 printf("No watchdog timer running.\n");
336 mode
= wm
.wm_mode
& WDOG_MODE_MASK
;
339 * If the timer is running in UTICKLE mode, we need
340 * to kill the wdogctl(8) process that is tickling
343 if (mode
== WDOG_MODE_UTICKLE
) {
344 if (ioctl(fd
, WDOGIOC_GTICKLER
, &tickler
) == -1)
345 err(EXIT_FAILURE
, "WDOGIOC_GTICKLER");
347 (void)kill(tickler
, SIGTERM
);
349 wm
.wm_mode
= WDOG_MODE_DISARMED
;
350 if (ioctl(fd
, WDOGIOC_SMODE
, &wm
) == -1) {
351 err(EXIT_FAILURE
, "unable to disarm watchdog %s",
364 int fd
, count
, i
, mode
;
367 fd
= open(_PATH_WATCHDOG
, O_RDONLY
, 0644);
369 err(EXIT_FAILURE
, "open %s", _PATH_WATCHDOG
);
374 if (ioctl(fd
, WDOGIOC_GWDOGS
, &wc
) == -1)
375 err(EXIT_FAILURE
, "ioctl WDOGIOC_GWDOGS for count");
379 printf("No watchdog timers present.\n");
383 buf
= malloc(count
* WDOG_NAMESIZE
);
385 err(EXIT_FAILURE
, "malloc %d byte for watchdog names",
386 count
* WDOG_NAMESIZE
);
389 if (ioctl(fd
, WDOGIOC_GWDOGS
, &wc
) == -1)
390 err(EXIT_FAILURE
, "ioctl WDOGIOC_GWDOGS for names");
394 printf("No watchdog timers present.\n");
399 printf("Available watchdog timers:\n");
400 for (i
= 0, cp
= buf
; i
< count
; i
++, cp
+= WDOG_NAMESIZE
) {
401 cp
[WDOG_NAMESIZE
- 1] = '\0';
402 strlcpy(wm
.wm_name
, cp
, sizeof(wm
.wm_name
));
404 if (ioctl(fd
, WDOGIOC_GMODE
, &wm
) == -1)
406 mode
= wm
.wm_mode
& WDOG_MODE_MASK
;
407 if (mode
== WDOG_MODE_UTICKLE
) {
408 if (ioctl(fd
, WDOGIOC_GTICKLER
, &tickler
) == -1)
409 tickler
= (pid_t
) -1;
412 printf("\t%s, %u second period", cp
, wm
.wm_period
);
413 if (mode
!= WDOG_MODE_DISARMED
) {
415 case WDOG_MODE_KTICKLE
:
416 printf(" [armed, kernel tickle");
418 case WDOG_MODE_UTICKLE
:
419 printf(" [armed, user tickle");
420 if (tickler
!= (pid_t
) -1)
421 printf(", pid %d", tickler
);
423 case WDOG_MODE_ETICKLE
:
424 printf(" [armed, external tickle");
439 fprintf(stderr
, "usage: %s\n", getprogname());
440 fprintf(stderr
, " %s -d\n", getprogname());
441 fprintf(stderr
, " %s -e [-A] [-p seconds] timer\n",
443 fprintf(stderr
, " %s -k [-A] [-p seconds] timer\n",
445 fprintf(stderr
, " %s -t\n", getprogname());
446 fprintf(stderr
, " %s -u [-A] [-p seconds] timer\n",
448 fprintf(stderr
, " %s -x [-A] [-p seconds] timer\n",