xref: /netbsd-src/sbin/wdogctl/wdogctl.c (revision 77cc846abe803dbe84390a0b2a8d9d86ab061971)
1*77cc846aSpgoyette /*	$NetBSD: wdogctl.c,v 1.21 2015/05/06 23:08:30 pgoyette Exp $	*/
2fb6f7d6fSthorpej 
3fb6f7d6fSthorpej /*-
4fb6f7d6fSthorpej  * Copyright (c) 2000 Zembu Labs, Inc.
5fb6f7d6fSthorpej  * All rights reserved.
6fb6f7d6fSthorpej  *
7fb6f7d6fSthorpej  * Author: Jason R. Thorpe <thorpej@zembu.com>
8fb6f7d6fSthorpej  *
9fb6f7d6fSthorpej  * Redistribution and use in source and binary forms, with or without
10fb6f7d6fSthorpej  * modification, are permitted provided that the following conditions
11fb6f7d6fSthorpej  * are met:
12fb6f7d6fSthorpej  * 1. Redistributions of source code must retain the above copyright
13fb6f7d6fSthorpej  *    notice, this list of conditions and the following disclaimer.
14fb6f7d6fSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
15fb6f7d6fSthorpej  *    notice, this list of conditions and the following disclaimer in the
16fb6f7d6fSthorpej  *    documentation and/or other materials provided with the distribution.
17fb6f7d6fSthorpej  * 3. All advertising materials mentioning features or use of this software
18fb6f7d6fSthorpej  *    must display the following acknowledgement:
19fb6f7d6fSthorpej  *	This product includes software developed by Zembu Labs, Inc.
20fb6f7d6fSthorpej  * 4. Neither the name of Zembu Labs nor the names of its employees may
21fb6f7d6fSthorpej  *    be used to endorse or promote products derived from this software
22fb6f7d6fSthorpej  *    without specific prior written permission.
23fb6f7d6fSthorpej  *
24fb6f7d6fSthorpej  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
25fb6f7d6fSthorpej  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
26fb6f7d6fSthorpej  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
27fb6f7d6fSthorpej  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
28fb6f7d6fSthorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29fb6f7d6fSthorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30fb6f7d6fSthorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31fb6f7d6fSthorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32fb6f7d6fSthorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33fb6f7d6fSthorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34fb6f7d6fSthorpej  */
35c2a3b5ecSagc #include <sys/cdefs.h>
36c2a3b5ecSagc 
37c2a3b5ecSagc #ifndef lint
38*77cc846aSpgoyette __RCSID("$NetBSD: wdogctl.c,v 1.21 2015/05/06 23:08:30 pgoyette Exp $");
39c2a3b5ecSagc #endif
40c2a3b5ecSagc 
41fb6f7d6fSthorpej 
42fb6f7d6fSthorpej #include <sys/param.h>
43fb6f7d6fSthorpej #include <sys/ioctl.h>
44fb6f7d6fSthorpej #include <sys/wdog.h>
45fb6f7d6fSthorpej 
46fb6f7d6fSthorpej #include <err.h>
47fb6f7d6fSthorpej #include <errno.h>
48fb6f7d6fSthorpej #include <fcntl.h>
49fb6f7d6fSthorpej #include <stdio.h>
50fb6f7d6fSthorpej #include <stdlib.h>
51fb6f7d6fSthorpej #include <time.h>
52fb6f7d6fSthorpej #include <signal.h>
53fb6f7d6fSthorpej #include <syslog.h>
54fb6f7d6fSthorpej #include <unistd.h>
55f23be04bSminoura #include <string.h>
56*77cc846aSpgoyette #include <paths.h>
57fb6f7d6fSthorpej 
58b7935600Sjoerg static void	enable_kernel(const char *, u_int);
59b7935600Sjoerg static void	enable_user(const char *, u_int, int);
60b7935600Sjoerg static void	enable_ext(const char *, u_int);
61b7935600Sjoerg static void	tickle_ext(void);
62b7935600Sjoerg static void	disable(void);
63b7935600Sjoerg static void	prep_wmode(struct wdog_mode *, int,  const char *, u_int);
64b7935600Sjoerg static void	list_timers(void);
65b7935600Sjoerg __dead static void	usage(void);
66fb6f7d6fSthorpej 
67b7935600Sjoerg static int	Aflag;
68fb6f7d6fSthorpej 
69ddd2ade2Ssmb /* Caution -- ordered list; entries >= CMD_EXT_TICKLE set timers */
70ddd2ade2Ssmb enum	cmd {
71ddd2ade2Ssmb 	CMD_NONE,	/* No verb given */
72ddd2ade2Ssmb 	CMD_DISABLE,
73ddd2ade2Ssmb 	CMD_DOTICKLE,
74ddd2ade2Ssmb 	CMD_EXT_TICKLE,
75ddd2ade2Ssmb 	CMD_KERN_TICKLE,
76a79c18d7Sdyoung 	CMD_NOCANCEL_TICKLE,
77ddd2ade2Ssmb 	CMD_USER_TICKLE
78ddd2ade2Ssmb };
79ddd2ade2Ssmb 
80fb6f7d6fSthorpej int
main(int argc,char * argv[])81fb6f7d6fSthorpej main(int argc, char *argv[])
82fb6f7d6fSthorpej {
83ddd2ade2Ssmb 	enum cmd command = CMD_NONE;
84ddd2ade2Ssmb 	int period_flag = 0;
8507f76885Slukem 	int ch, tmp;
86fb6f7d6fSthorpej 	u_int period = WDOG_PERIOD_DEFAULT;
87fb6f7d6fSthorpej 
88a79c18d7Sdyoung 	while ((ch = getopt(argc, argv, "Adekp:utx")) != -1) {
89fb6f7d6fSthorpej 		switch (ch) {
90fb6f7d6fSthorpej 		case 'A':
91fb6f7d6fSthorpej 			Aflag = 1;
92fb6f7d6fSthorpej 			break;
93fb6f7d6fSthorpej 
94fb6f7d6fSthorpej 		case 'd':
95ddd2ade2Ssmb 			if (command != CMD_NONE)
96ddd2ade2Ssmb 				usage();
97ddd2ade2Ssmb 			command = CMD_DISABLE;
98ddd2ade2Ssmb 			break;
99ddd2ade2Ssmb 
100ddd2ade2Ssmb 		case 'e':
101ddd2ade2Ssmb 			if (command != CMD_NONE)
102ddd2ade2Ssmb 				usage();
103ddd2ade2Ssmb 			command = CMD_EXT_TICKLE;
104fb6f7d6fSthorpej 			break;
105fb6f7d6fSthorpej 
106fb6f7d6fSthorpej 		case 'k':
107ddd2ade2Ssmb 			if (command != CMD_NONE)
108ddd2ade2Ssmb 				usage();
109ddd2ade2Ssmb 			command = CMD_KERN_TICKLE;
110ddd2ade2Ssmb 			break;
111ddd2ade2Ssmb 
112ddd2ade2Ssmb 		case 't':
113ddd2ade2Ssmb 			if (command != CMD_NONE)
114ddd2ade2Ssmb 				usage();
115ddd2ade2Ssmb 			command = CMD_DOTICKLE;
116fb6f7d6fSthorpej 			break;
117fb6f7d6fSthorpej 
118fb6f7d6fSthorpej 		case 'p':
119ddd2ade2Ssmb 			period_flag = 1;
12007f76885Slukem 			tmp = atoi(optarg);
12107f76885Slukem 			if (tmp < 0)
122fb6f7d6fSthorpej 				usage();
12307f76885Slukem 			period = (unsigned int)tmp;
124fb6f7d6fSthorpej 			break;
125fb6f7d6fSthorpej 
126a79c18d7Sdyoung 		case 'x':
127fb6f7d6fSthorpej 		case 'u':
128ddd2ade2Ssmb 			if (command != CMD_NONE)
129ddd2ade2Ssmb 				usage();
130a79c18d7Sdyoung 			command =
131a79c18d7Sdyoung 			    (ch == 'u') ? CMD_USER_TICKLE : CMD_NOCANCEL_TICKLE;
132fb6f7d6fSthorpej 			break;
133fb6f7d6fSthorpej 
134fb6f7d6fSthorpej 		default:
135fb6f7d6fSthorpej 			usage();
136fb6f7d6fSthorpej 		}
137fb6f7d6fSthorpej 	}
138fb6f7d6fSthorpej 
139fb6f7d6fSthorpej 	argc -= optind;
140fb6f7d6fSthorpej 	argv += optind;
141fb6f7d6fSthorpej 
142ddd2ade2Ssmb 	if (command < CMD_EXT_TICKLE) {
143ddd2ade2Ssmb 		if (Aflag || period_flag)
144fb6f7d6fSthorpej 			usage();
145fb6f7d6fSthorpej 		if (argc != 0)
146fb6f7d6fSthorpej 			usage();
1471c952b1bSdyoung 	} else if (argc != 1)
148ddd2ade2Ssmb 		usage();
149fb6f7d6fSthorpej 
150ddd2ade2Ssmb 	switch (command) {
151ddd2ade2Ssmb 	case CMD_NONE:
152ddd2ade2Ssmb 		list_timers();
153ddd2ade2Ssmb 		break;
154ddd2ade2Ssmb 	case CMD_DISABLE:
155ddd2ade2Ssmb 		disable();
156ddd2ade2Ssmb 		break;
157ddd2ade2Ssmb 	case CMD_DOTICKLE:
158ddd2ade2Ssmb 		tickle_ext();
159ddd2ade2Ssmb 		break;
160ddd2ade2Ssmb 	case CMD_EXT_TICKLE:
161ddd2ade2Ssmb 		enable_ext(argv[0], period);
162ddd2ade2Ssmb 		break;
163ddd2ade2Ssmb 	case CMD_KERN_TICKLE:
164ddd2ade2Ssmb 		enable_kernel(argv[0], period);
165ddd2ade2Ssmb 		break;
166a79c18d7Sdyoung 	case CMD_NOCANCEL_TICKLE:
167ddd2ade2Ssmb 	case CMD_USER_TICKLE:
168a79c18d7Sdyoung 		enable_user(argv[0], period, command == CMD_USER_TICKLE);
169ddd2ade2Ssmb 		break;
170ddd2ade2Ssmb 	}
1711c952b1bSdyoung 	exit(EXIT_SUCCESS);
172fb6f7d6fSthorpej }
173fb6f7d6fSthorpej 
174b7935600Sjoerg static void
prep_wmode(struct wdog_mode * wp,int mode,const char * name,u_int period)175ddd2ade2Ssmb prep_wmode(struct wdog_mode *wp, int mode,  const char *name, u_int period)
176ddd2ade2Ssmb {
177ddd2ade2Ssmb 	if (strlen(name) >= WDOG_NAMESIZE)
1781c952b1bSdyoung 		errx(EXIT_FAILURE, "invalid watchdog timer name: %s", name);
179ddd2ade2Ssmb 
180ddd2ade2Ssmb 	strlcpy(wp->wm_name, name, sizeof(wp->wm_name));
181ddd2ade2Ssmb 	wp->wm_mode = mode;
182ddd2ade2Ssmb 	wp->wm_period = period;
183ddd2ade2Ssmb 	if (Aflag)
184ddd2ade2Ssmb 		wp->wm_mode |= WDOG_FEATURE_ALARM;
185ddd2ade2Ssmb }
186ddd2ade2Ssmb 
187b7935600Sjoerg static void
enable_kernel(const char * name,u_int period)188fb6f7d6fSthorpej enable_kernel(const char *name, u_int period)
189fb6f7d6fSthorpej {
190fb6f7d6fSthorpej 	struct wdog_mode wm;
191fb6f7d6fSthorpej 	int fd;
192fb6f7d6fSthorpej 
193ddd2ade2Ssmb 	prep_wmode(&wm, WDOG_MODE_KTICKLE, name, period);
194fb6f7d6fSthorpej 
195fb6f7d6fSthorpej 	fd = open(_PATH_WATCHDOG, O_RDWR, 0644);
196fb6f7d6fSthorpej 	if (fd == -1)
1971c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
198fb6f7d6fSthorpej 
199fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_SMODE, &wm) == -1)
2001c952b1bSdyoung 		err(EXIT_FAILURE, "WDOGIOC_SMODE");
201a8861125Swiz 
202a8861125Swiz 	(void)close(fd);
203fb6f7d6fSthorpej }
204fb6f7d6fSthorpej 
205b7935600Sjoerg static void
enable_ext(const char * name,u_int period)206ddd2ade2Ssmb enable_ext(const char *name, u_int period)
207ddd2ade2Ssmb {
208ddd2ade2Ssmb 	struct wdog_mode wm;
209ddd2ade2Ssmb 	int fd;
210ddd2ade2Ssmb 
211ddd2ade2Ssmb 	prep_wmode(&wm, WDOG_MODE_ETICKLE, name, period);
212ddd2ade2Ssmb 
213ddd2ade2Ssmb 	fd = open(_PATH_WATCHDOG, O_RDWR, 0644);
214ddd2ade2Ssmb 	if (fd == -1)
2151c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
216ddd2ade2Ssmb 	if (ioctl(fd, WDOGIOC_SMODE, &wm) == -1) {
2171c952b1bSdyoung 		err(EXIT_FAILURE, "WDOGIOC_SMODE");
218ddd2ade2Ssmb 	}
219ddd2ade2Ssmb 	if (ioctl(fd, WDOGIOC_TICKLE) == -1)
220ddd2ade2Ssmb 		syslog(LOG_EMERG, "unable to tickle watchdog timer %s: %m",
221ddd2ade2Ssmb 		    wm.wm_name);
222a8861125Swiz 
223a8861125Swiz 	(void)close(fd);
224ddd2ade2Ssmb 	return;
225ddd2ade2Ssmb }
226ddd2ade2Ssmb 
227b7935600Sjoerg static void
enable_user(const char * name,u_int period,int cancel_on_close)228a79c18d7Sdyoung enable_user(const char *name, u_int period, int cancel_on_close)
229fb6f7d6fSthorpej {
230fb6f7d6fSthorpej 	struct wdog_mode wm;
231fb6f7d6fSthorpej 	struct timespec ts;
232fb6f7d6fSthorpej 	pid_t tickler;
233fb6f7d6fSthorpej 	int fd, rv;
234fb6f7d6fSthorpej 
235a79c18d7Sdyoung 	prep_wmode(&wm,
236a79c18d7Sdyoung 	    (cancel_on_close) ? WDOG_MODE_UTICKLE : WDOG_MODE_ETICKLE, name,
237a79c18d7Sdyoung 	    period);
238fb6f7d6fSthorpej 
239fb6f7d6fSthorpej 	fd = open(_PATH_WATCHDOG, O_RDWR, 0644);
240fb6f7d6fSthorpej 	if (fd == -1)
2411c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
242fb6f7d6fSthorpej 
243fb6f7d6fSthorpej 	/* ...so we can log failures to tickle the timer. */
2440645f2f6Slukem 	openlog("wdogctl", LOG_PERROR|LOG_PID, LOG_DAEMON);
245fb6f7d6fSthorpej 
246fb6f7d6fSthorpej 	/*
247fb6f7d6fSthorpej 	 * We fork a child process which detaches from the controlling
248fb6f7d6fSthorpej 	 * terminal once the timer is armed, and tickles the timer
249fb6f7d6fSthorpej 	 * until we send it a SIGTERM.
250fb6f7d6fSthorpej 	 */
251fb6f7d6fSthorpej 	tickler = fork();
252fb6f7d6fSthorpej 	if (tickler == -1)
2531c952b1bSdyoung 		err(EXIT_FAILURE, "unable to fork tickler process");
254fb6f7d6fSthorpej 	else if (tickler != 0) {
255fb6f7d6fSthorpej 		if (ioctl(fd, WDOGIOC_SMODE, &wm) == -1) {
256fb6f7d6fSthorpej 			(void)kill(tickler, SIGTERM);
257fab04101Sdyoung 			err(EXIT_FAILURE, "WDOGIOC_SMODE");
258fb6f7d6fSthorpej 		}
259fb6f7d6fSthorpej 		(void)close(fd);
260fb6f7d6fSthorpej 		return;
261fb6f7d6fSthorpej 	}
262fb6f7d6fSthorpej 
263fb6f7d6fSthorpej 
264fb6f7d6fSthorpej 	/*
265fb6f7d6fSthorpej 	 * Wait for the watchdog to be armed.  When it is, loop,
266fb6f7d6fSthorpej 	 * tickling the timer, then waiting 1/2 the period before
267fb6f7d6fSthorpej 	 * doing it again.
268fb6f7d6fSthorpej 	 *
269fb6f7d6fSthorpej 	 * If the parent fails to enable the watchdog, it will kill
270fb6f7d6fSthorpej 	 * us.
271fb6f7d6fSthorpej 	 */
272fb6f7d6fSthorpej 	do {
273fb6f7d6fSthorpej 		rv = ioctl(fd, WDOGIOC_WHICH, &wm);
274fb6f7d6fSthorpej 	} while (rv == -1);
275fb6f7d6fSthorpej 
276fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_TICKLE) == -1)
277fb6f7d6fSthorpej 		syslog(LOG_EMERG, "unable to tickle watchdog timer %s: %m",
278fb6f7d6fSthorpej 		    wm.wm_name);
279fb6f7d6fSthorpej 
280fb6f7d6fSthorpej 	/*
281fb6f7d6fSthorpej 	 * Now detach from the controlling terminal, and just run
282fb6f7d6fSthorpej 	 * in the background.  The kernel will keep track of who
283fb6f7d6fSthorpej 	 * we are, each time we tickle the timer.
284fb6f7d6fSthorpej 	 */
285fb6f7d6fSthorpej 	if (daemon(0, 0) == -1) {
286fb6f7d6fSthorpej 		/*
287fb6f7d6fSthorpej 		 * We weren't able to go into the background.  When
288fb6f7d6fSthorpej 		 * we exit, the kernel will disable the watchdog so
289fb6f7d6fSthorpej 		 * that the system won't die.
290fb6f7d6fSthorpej 		 */
2911c952b1bSdyoung 		err(EXIT_FAILURE, "unable to detach from terminal");
292fb6f7d6fSthorpej 	}
293fb6f7d6fSthorpej 
294fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_TICKLE) == -1)
295fb6f7d6fSthorpej 		syslog(LOG_EMERG, "unable to tickle watchdog timer %s: %m",
296fb6f7d6fSthorpej 		    wm.wm_name);
297fb6f7d6fSthorpej 
298fb6f7d6fSthorpej 	for (;;) {
299fb6f7d6fSthorpej 		ts.tv_sec = wm.wm_period / 2;
300fb6f7d6fSthorpej 		ts.tv_nsec = 0;
301fb6f7d6fSthorpej 		(void)nanosleep(&ts, NULL);
302fb6f7d6fSthorpej 
303fb6f7d6fSthorpej 		if (ioctl(fd, WDOGIOC_TICKLE) == -1)
304fb6f7d6fSthorpej 			syslog(LOG_EMERG,
305fb6f7d6fSthorpej 			    "unable to tickle watchdog timer %s: %m",
306fb6f7d6fSthorpej 			    wm.wm_name);
307fb6f7d6fSthorpej 	}
308fb6f7d6fSthorpej 	/* NOTREACHED */
309fb6f7d6fSthorpej }
310fb6f7d6fSthorpej 
311b7935600Sjoerg static void
tickle_ext(void)312b7935600Sjoerg tickle_ext(void)
313ddd2ade2Ssmb {
314ddd2ade2Ssmb 	int fd;
315ddd2ade2Ssmb 
316ddd2ade2Ssmb 	fd = open(_PATH_WATCHDOG, O_RDWR, 0644);
317ddd2ade2Ssmb 	if (fd == -1)
3181c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
319ddd2ade2Ssmb 	if (ioctl(fd, WDOGIOC_TICKLE) == -1)
320ddd2ade2Ssmb 		fprintf(stderr, "Cannot tickle timer\n");
321a8861125Swiz 
322a8861125Swiz 	(void)close(fd);
323ddd2ade2Ssmb }
324ddd2ade2Ssmb 
325b7935600Sjoerg static void
disable(void)326fb6f7d6fSthorpej disable(void)
327fb6f7d6fSthorpej {
328fb6f7d6fSthorpej 	struct wdog_mode wm;
329fb6f7d6fSthorpej 	pid_t tickler;
330bad83216Sdrochner 	int fd, mode;
331fb6f7d6fSthorpej 
332fb6f7d6fSthorpej 	fd = open(_PATH_WATCHDOG, O_RDWR, 0644);
333fb6f7d6fSthorpej 	if (fd == -1)
3341c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
335fb6f7d6fSthorpej 
336fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_WHICH, &wm) == -1) {
337fb6f7d6fSthorpej 		printf("No watchdog timer running.\n");
338a8861125Swiz 		(void)close(fd);
339fb6f7d6fSthorpej 		return;
340fb6f7d6fSthorpej 	}
341bad83216Sdrochner 	mode = wm.wm_mode & WDOG_MODE_MASK;
342fb6f7d6fSthorpej 
343fb6f7d6fSthorpej 	/*
344fb6f7d6fSthorpej 	 * If the timer is running in UTICKLE mode, we need
345fb6f7d6fSthorpej 	 * to kill the wdogctl(8) process that is tickling
346fb6f7d6fSthorpej 	 * the timer.
347fb6f7d6fSthorpej 	 */
348bad83216Sdrochner 	if (mode == WDOG_MODE_UTICKLE) {
349fb6f7d6fSthorpej 		if (ioctl(fd, WDOGIOC_GTICKLER, &tickler) == -1)
3501c952b1bSdyoung 			err(EXIT_FAILURE, "WDOGIOC_GTICKLER");
351fb6f7d6fSthorpej 		(void)close(fd);
352fb6f7d6fSthorpej 		(void)kill(tickler, SIGTERM);
353fb6f7d6fSthorpej 	} else {
354fb6f7d6fSthorpej 		wm.wm_mode = WDOG_MODE_DISARMED;
3551c952b1bSdyoung 		if (ioctl(fd, WDOGIOC_SMODE, &wm) == -1) {
3561c952b1bSdyoung 			err(EXIT_FAILURE, "unable to disarm watchdog %s",
3571c952b1bSdyoung 			    wm.wm_name);
3581c952b1bSdyoung 		}
359fb6f7d6fSthorpej 		(void)close(fd);
360fb6f7d6fSthorpej 	}
361fb6f7d6fSthorpej }
362fb6f7d6fSthorpej 
363b7935600Sjoerg static void
list_timers(void)364fb6f7d6fSthorpej list_timers(void)
365fb6f7d6fSthorpej {
366fb6f7d6fSthorpej 	struct wdog_conf wc;
367fb6f7d6fSthorpej 	struct wdog_mode wm;
368fb6f7d6fSthorpej 	char *buf, *cp;
369bad83216Sdrochner 	int fd, count, i, mode;
370fb6f7d6fSthorpej 	pid_t tickler;
371fb6f7d6fSthorpej 
372fb6f7d6fSthorpej 	fd = open(_PATH_WATCHDOG, O_RDONLY, 0644);
373fb6f7d6fSthorpej 	if (fd == -1)
3741c952b1bSdyoung 		err(EXIT_FAILURE, "open %s", _PATH_WATCHDOG);
375fb6f7d6fSthorpej 
376fb6f7d6fSthorpej 	wc.wc_names = NULL;
377fb6f7d6fSthorpej 	wc.wc_count = 0;
378fb6f7d6fSthorpej 
379fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_GWDOGS, &wc) == -1)
3801c952b1bSdyoung 		err(EXIT_FAILURE, "ioctl WDOGIOC_GWDOGS for count");
381fb6f7d6fSthorpej 
382fb6f7d6fSthorpej 	count = wc.wc_count;
383fb6f7d6fSthorpej 	if (count == 0) {
384fb6f7d6fSthorpej 		printf("No watchdog timers present.\n");
385fb6f7d6fSthorpej 		goto out;
386fb6f7d6fSthorpej 	}
387fb6f7d6fSthorpej 
388fb6f7d6fSthorpej 	buf = malloc(count * WDOG_NAMESIZE);
389fb6f7d6fSthorpej 	if (buf == NULL)
3901c952b1bSdyoung 		err(EXIT_FAILURE, "malloc %d byte for watchdog names",
391fb6f7d6fSthorpej 		    count * WDOG_NAMESIZE);
392fb6f7d6fSthorpej 
393fb6f7d6fSthorpej 	wc.wc_names = buf;
394fb6f7d6fSthorpej 	if (ioctl(fd, WDOGIOC_GWDOGS, &wc) == -1)
3951c952b1bSdyoung 		err(EXIT_FAILURE, "ioctl WDOGIOC_GWDOGS for names");
396fb6f7d6fSthorpej 
397fb6f7d6fSthorpej 	count = wc.wc_count;
398fb6f7d6fSthorpej 	if (count == 0) {
399fb6f7d6fSthorpej 		printf("No watchdog timers present.\n");
400fb6f7d6fSthorpej 		free(buf);
401fb6f7d6fSthorpej 		goto out;
402fb6f7d6fSthorpej 	}
403fb6f7d6fSthorpej 
404fb6f7d6fSthorpej 	printf("Available watchdog timers:\n");
405fb6f7d6fSthorpej 	for (i = 0, cp = buf; i < count; i++, cp += WDOG_NAMESIZE) {
406fb6f7d6fSthorpej 		cp[WDOG_NAMESIZE - 1] = '\0';
4078883e1fbSitojun 		strlcpy(wm.wm_name, cp, sizeof(wm.wm_name));
408fb6f7d6fSthorpej 
409fb6f7d6fSthorpej 		if (ioctl(fd, WDOGIOC_GMODE, &wm) == -1)
410bad83216Sdrochner 			continue;
411bad83216Sdrochner 		mode = wm.wm_mode & WDOG_MODE_MASK;
412bad83216Sdrochner 		if (mode == WDOG_MODE_UTICKLE) {
413fb6f7d6fSthorpej 			if (ioctl(fd, WDOGIOC_GTICKLER, &tickler) == -1)
414fb6f7d6fSthorpej 				tickler = (pid_t) -1;
415fb6f7d6fSthorpej 		}
416fb6f7d6fSthorpej 
417fb6f7d6fSthorpej 		printf("\t%s, %u second period", cp, wm.wm_period);
418bad83216Sdrochner 		if (mode != WDOG_MODE_DISARMED) {
419bad83216Sdrochner 			switch(mode) {
420ddd2ade2Ssmb 			case WDOG_MODE_KTICKLE:
421ddd2ade2Ssmb 				printf(" [armed, kernel tickle");
422ddd2ade2Ssmb 				break;
423ddd2ade2Ssmb 			case WDOG_MODE_UTICKLE:
424ddd2ade2Ssmb 				printf(" [armed, user tickle");
425ddd2ade2Ssmb 				if (tickler != (pid_t) -1)
426fb6f7d6fSthorpej 					printf(", pid %d", tickler);
427ddd2ade2Ssmb 				break;
428ddd2ade2Ssmb 			case WDOG_MODE_ETICKLE:
429ddd2ade2Ssmb 				printf(" [armed, external tickle");
430ddd2ade2Ssmb 				break;
431ddd2ade2Ssmb 			}
432fb6f7d6fSthorpej 			printf("]");
433fb6f7d6fSthorpej 		}
434fb6f7d6fSthorpej 		printf("\n");
435fb6f7d6fSthorpej 	}
436fb6f7d6fSthorpej  out:
437fb6f7d6fSthorpej 	(void)close(fd);
438fb6f7d6fSthorpej }
439fb6f7d6fSthorpej 
440b7935600Sjoerg static void
usage(void)441fb6f7d6fSthorpej usage(void)
442fb6f7d6fSthorpej {
443da2ab5caSwiz 
444b635f565Sjmmv 	fprintf(stderr, "usage: %s\n", getprogname());
445da2ab5caSwiz 	fprintf(stderr, "       %s -d\n", getprogname());
446ddd2ade2Ssmb 	fprintf(stderr, "       %s -e [-A] [-p seconds] timer\n",
447ddd2ade2Ssmb 	    getprogname());
448d7666f6cScgd 	fprintf(stderr, "       %s -k [-A] [-p seconds] timer\n",
449d7666f6cScgd 	    getprogname());
450da2ab5caSwiz 	fprintf(stderr, "       %s -t\n", getprogname());
451d7666f6cScgd 	fprintf(stderr, "       %s -u [-A] [-p seconds] timer\n",
452d7666f6cScgd 	    getprogname());
45300352349Swiz 	fprintf(stderr, "       %s -x [-A] [-p seconds] timer\n",
45400352349Swiz 	    getprogname());
455fb6f7d6fSthorpej 
456fb6f7d6fSthorpej 	exit(1);
457fb6f7d6fSthorpej }
458