Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Feb 2013 09:04:42 +0000 (UTC)
From:      Alfred Perlstein <alfred@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r246901 - in user/alfred/ewatchdog: sys/dev/watchdog sys/sys usr.sbin/watchdogd
Message-ID:  <201302170904.r1H94gnq055684@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alfred
Date: Sun Feb 17 09:04:42 2013
New Revision: 246901
URL: http://svnweb.freebsd.org/changeset/base/246901

Log:
  Support multiple timeout actions.
  
  Add usage() to watchdogd.
  
  Allow setting of soft timeout and pre timeout.
  
  Add defines for 64 and 128 seconds.
  
  Clear EOPNOTSUP when doing software watchdog, default to WD_SOFT_LOG
  
  Remove extra function. Comment code.

Modified:
  user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
  user/alfred/ewatchdog/sys/sys/watchdog.h
  user/alfred/ewatchdog/usr.sbin/watchdogd/watchdogd.c

Modified: user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
==============================================================================
--- user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c	Sun Feb 17 07:40:21 2013	(r246900)
+++ user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c	Sun Feb 17 09:04:42 2013	(r246901)
@@ -51,12 +51,12 @@ static void wd_timeout_cb(void *arg);
 
 static struct callout wd_pretimeo_handle;
 static int wd_pretimeout;
-static int wd_pretimeout_act;
+static int wd_pretimeout_act = WD_SOFT_LOG;
 
 static struct callout wd_softtimeo_handle;
 static int wd_softtimer;	/* true = use softtimer instead of hardware
 				   watchdog */
-static int wd_softtimeout_act;	/* action for the software timeout */
+static int wd_softtimeout_act = WD_SOFT_LOG;	/* action for the software timeout */
 
 static struct cdev *wd_dev;
 static volatile u_int wd_last_u;    /* last timeout value set by kern_do_pat */
@@ -64,8 +64,8 @@ static volatile u_int wd_last_u;    /* l
 static int wd_lastpat_valid = 0;
 static time_t wd_lastpat = 0;	/* when the watchdog was last patted */
 
-static int
-kern_do_pat(u_int utim)
+int
+wdog_kern_pat(u_int utim)
 {
 	int error;
 
@@ -103,6 +103,7 @@ kern_do_pat(u_int utim)
 			(void) callout_reset(&wd_softtimeo_handle,
 			    hz*utim, wd_timeout_cb, "soft");
 		}
+		error = 0;
 	} else {
 		EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
 	}
@@ -128,15 +129,9 @@ static int
 wd_valid_act(int act)
 {
 
-	switch (act) {
-	case WD_SOFT_PANIC:
-#ifdef DDB
-	case WD_SOFT_DDB:
-#endif
-	case WD_SOFT_LOG:
-		return true;
-	}
-	return false;
+	if ((act & ~(WD_SOFT_MASK)) != 0)
+		return false;
+	return true;
 }
 
 static int
@@ -156,7 +151,7 @@ wd_ioctl_patpat(caddr_t data)
 		return (ENOSYS);	/* XXX Not implemented yet */
 	u &= ~(WD_ACTIVE | WD_PASSIVE);
 
-	return (kern_do_pat(u));
+	return (wdog_kern_pat(u));
 }
 
 static int
@@ -178,28 +173,21 @@ static void
 wd_timeout_cb(void *arg)
 {
 	const char *type = arg;
-#ifdef DDB
-	char kdb_why[80];
-#endif
 
-	switch (wd_pretimeout_act) {
-	case WD_SOFT_PANIC:
-		panic("watchdog %s-timeout, WD_SOFT_PANIC set", type);
-		break;
 #ifdef DDB
-	case WD_SOFT_DDB:
+	if ((wd_pretimeout_act & WD_SOFT_DDB)) {
+		char kdb_why[80];
 		snprintf(kdb_why, sizeof(buf), "watchdog %s timeout", type);
 		kdb_backtrace();
 		kdb_enter(KDB_WHY_WATCHDOG, kdb_why);
-		break;
+	}
 #endif
-	case WD_SOFT_LOG:
+	if ((wd_pretimeout_act & WD_SOFT_LOG))
 		log(LOG_EMERG, "watchdog %s-timeout, WD_SOFT_LOG", type);
-		break;
-	default:
-		panic("watchdog: unexpected wd_pretimeout_act %d",
-		    wd_pretimeout_act);
-	}
+	if ((wd_pretimeout_act & WD_SOFT_PRINTF))
+		printf("watchdog %s-timeout, WD_SOFT_PRINTF\n", type);
+	if ((wd_pretimeout_act & WD_SOFT_PANIC))
+		panic("watchdog %s-timeout, WD_SOFT_PANIC set", type);
 }
 
 /*
@@ -310,6 +298,10 @@ wd_ioctl(struct cdev *dev __unused, u_lo
 	return (error);
 }
 
+/*
+ * Return the last timeout set, this is NOT the seconds from NOW until timeout,
+ * rather it is the amount of seconds passed to WDIOCPATPAT/WDIOC_SETTIMEOUT.
+ */
 u_int
 wdog_kern_last_timeout(void)
 {
@@ -317,16 +309,6 @@ wdog_kern_last_timeout(void)
 	return (wd_last_u);
 }
 
-int
-wdog_kern_pat(u_int utim)
-{
-
-	if (utim & ~(WD_LASTVAL | WD_INTERVAL))
-		return (EINVAL);
-
-	return (kern_do_pat(utim));
-}
-
 static struct cdevsw wd_cdevsw = {
 	.d_version =	D_VERSION,
 	.d_ioctl =	wd_ioctl,

Modified: user/alfred/ewatchdog/sys/sys/watchdog.h
==============================================================================
--- user/alfred/ewatchdog/sys/sys/watchdog.h	Sun Feb 17 07:40:21 2013	(r246900)
+++ user/alfred/ewatchdog/sys/sys/watchdog.h	Sun Feb 17 09:04:42 2013	(r246901)
@@ -1,5 +1,8 @@
 /*-
  * Copyright (c) 2003 Poul-Henning Kamp
+ * Copyright (c) 2013 iXsystems.com,
+ *                    author: Alfred Perlstein <alfred@freebsd.org>
+ *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -87,11 +90,15 @@
 #define WD_TO_8SEC	33
 #define WD_TO_16SEC	34
 #define WD_TO_32SEC	35
+#define WD_TO_64SEC	36
+#define WD_TO_128SEC	37
 
 /* action on pre-timeout trigger */
-#define	WD_SOFT_PANIC	1	/* panic */
-#define	WD_SOFT_DDB	2	/* enter debugger */
-#define	WD_SOFT_LOG	3	/* log(9) */
+#define	WD_SOFT_PANIC	0x01	/* panic */
+#define	WD_SOFT_DDB	0x02	/* enter debugger */
+#define	WD_SOFT_LOG	0x04	/* log(9) */
+#define	WD_SOFT_PRINTF	0x08	/* printf(9) */
+#define WD_SOFT_MASK	0x0f	/* all of the above */
 
 #ifdef _KERNEL
 

Modified: user/alfred/ewatchdog/usr.sbin/watchdogd/watchdogd.c
==============================================================================
--- user/alfred/ewatchdog/usr.sbin/watchdogd/watchdogd.c	Sun Feb 17 07:40:21 2013	(r246900)
+++ user/alfred/ewatchdog/usr.sbin/watchdogd/watchdogd.c	Sun Feb 17 09:04:42 2013	(r246901)
@@ -1,5 +1,8 @@
 /*-
  * Copyright (c) 2003-2004  Sean M. Kelly <smkelly@FreeBSD.org>
+ * Copyright (c) 2013 iXsystems.com,
+ *                    author: Alfred Perlstein <alfred@freebsd.org>
+ *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,6 +56,8 @@ __FBSDID("$FreeBSD$");
 #include <syslog.h>
 #include <unistd.h>
 
+#include <getopt.h>
+
 static void	parseargs(int, char *[]);
 static void	sighandler(int);
 static void	watchdog_loop(void);
@@ -64,7 +69,8 @@ static void	usage(void);
 static int debugging = 0;
 static int end_program = 0;
 static const char *pidfile = _PATH_VARRUN "watchdogd.pid";
-static u_int timeout = WD_TO_16SEC;
+static u_int timeout = WD_TO_128SEC;
+static u_int pretimeout = 0;
 static u_int passive = 0;
 static int is_daemon = 0;
 static int is_dry_run = 0;  /* do not arm the watchdog, only
@@ -77,6 +83,25 @@ static int nap = 1;
 static int carp_thresh_seconds = -1;
 static char *test_cmd = NULL;
 
+static const char *getopt_shortopts;
+
+static int pretimeout_set;
+static int pretimeout_act;
+static int pretimeout_act_set;
+
+static int softtimeout_set;
+static int softtimeout_act;
+static int softtimeout_act_set;
+
+static struct option longopts[] = {
+	{ "debug", no_argument, &debugging, 1 },
+	{ "pretimeout", required_argument, &pretimeout_set, 1 },
+	{ "pretimeout-action", required_argument, &pretimeout_act_set, 1 },
+	{ "softtimeout", no_argument, &softtimeout_set, 1 },
+	{ "softtimeout-action", required_argument, &softtimeout_act_set, 1 },
+	{ NULL, 0, NULL, 0}
+};
+
 /*
  * Ask malloc() to map minimum-sized chunks of virtual address space at a time,
  * so that mlockall() won't needlessly wire megabytes of unused memory into the
@@ -121,6 +146,7 @@ main(int argc, char *argv[])
 		pfh = pidfile_open(pidfile, 0600, &otherpid);
 		if (pfh == NULL) {
 			if (errno == EEXIST) {
+				watchdog_onoff(0);
 				errx(EX_SOFTWARE, "%s already running, pid: %d",
 				    getprogname(), otherpid);
 			}
@@ -312,15 +338,62 @@ watchdog_patpat(u_int t)
 static int
 watchdog_onoff(int onoff)
 {
+	int error;
 
 	/* fake successful watchdog op if a dry run */
 	if (is_dry_run)
 		return 0;
 
-	if (onoff)
+	if (onoff) {
+		/*
+		 * Call the WDIOC_SETSOFT regardless of softtimeout_set
+		 * because we'll need to turn it off if someone had turned
+		 * it on.
+		 */
+		error = ioctl(fd, WDIOC_SETSOFT, &softtimeout_set);
+		if (error) {
+			warn("setting WDIOC_SETSOFT %d", softtimeout_set);
+			return (error);
+		}
+		error = watchdog_patpat((timeout|WD_ACTIVE));
+		if (error) {
+			warn("watchdog_patpat failed");
+			goto failsafe;
+		}
+		if (softtimeout_act_set) {
+			error = ioctl(fd, WDIOC_SETSOFTTIMEOUTACT,
+			    &softtimeout_act);
+			if (error) {
+				warn("setting WDIOC_SETSOFTTIMEOUTACT %d",
+				    softtimeout_act);
+				goto failsafe;
+			}
+		}
+		if (pretimeout_set) {
+			error = ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
+			if (error) {
+				warn("setting WDIOC_SETPRETIMEOUT %d",
+				    pretimeout);
+				goto failsafe;
+			}
+		}
+		if (pretimeout_act_set) {
+			error = ioctl(fd, WDIOC_SETPRETIMEOUTACT,
+			    &pretimeout_act);
+			if (error) {
+				warn("setting WDIOC_SETPRETIMEOUTACT %d",
+				    pretimeout_act);
+				goto failsafe;
+			}
+		}
+		/* pat one more time for good measure */
 		return watchdog_patpat((timeout|WD_ACTIVE));
-	else
+	 } else {
 		return watchdog_patpat(0);
+	 }
+failsafe:
+	watchdog_patpat(0);
+	return (error);
 }
 
 /*
@@ -330,41 +403,132 @@ static void
 usage(void)
 {
 	if (is_daemon)
-		fprintf(stderr, "usage: watchdogd [-dnw] [-e cmd] [-I file] [-s sleep] [-t timeout] [-T script_timeout]\n");
+		fprintf(stderr, "usage:\n"
+"  watchdogd [-dnw] [-e cmd] [-I file] [-s sleep] [-t timeout]\n"
+"            [-T script_timeout]\n"
+"            [--debug]\n"
+"            [--pretimeout seconds] [-pretimeout-action action]\n"
+"            [--softtimeout] [-softtimeout-action action]\n"
+);
 	else
 		fprintf(stderr, "usage: watchdog [-d] [-t timeout]\n");
 	exit(EX_USAGE);
 }
 
 static long
-fetchtimeout(int opt, const char *myoptarg)
+fetchtimeout(int opt, const char *longopt, const char *myoptarg)
 {
+	const char *errstr;
 	char *p;
 	long rv;
 
+	errstr = NULL;
 	p = NULL;
 	errno = 0;
 	rv = strtol(myoptarg, &p, 0);
 	if ((p != NULL && *p != '\0') || errno != 0)
-		errx(EX_USAGE, "-%c argument is not a number", opt);
+		errstr = "is not a number";
+	if (rv <= 0)
+		errstr = "must be greater than zero";
+	if (errstr) {
+		if (longopt) 
+			errx(EX_USAGE, "--%s argument %s", longopt, errstr);
+		else 
+			errx(EX_USAGE, "-%c argument %s", opt, errstr);
+	}
 	return (rv);
 }
 
+struct act_tbl {
+	const char *at_act;
+	int at_value;
+};
+
+struct act_tbl act_tbl[] = {
+	{ "panic", WD_SOFT_PANIC },
+	{ "ddb", WD_SOFT_DDB },
+	{ "log", WD_SOFT_LOG },
+	{ "printf", WD_SOFT_PRINTF },
+	{ NULL, 0 }
+};
+
+static void
+timeout_act_error(const char *lopt, const char *badact)
+{
+	char *opts, *oldopts;
+	int i;
+
+	opts = NULL;
+	for (i = 0; act_tbl[i].at_act != NULL; i++) {
+		oldopts = opts;
+		if (asprintf(&opts, "%s%s%s",
+		    oldopts == NULL ? "" : oldopts,
+		    oldopts == NULL ? "" : ", ",
+		    act_tbl[i].at_act) == -1)
+			err(EX_OSERR, "malloc");
+		free(oldopts);
+	}
+	warnx("bad --%s argument '%s' must be one of (%s).",
+	    lopt, badact, opts);
+	usage();
+}
+
+/*
+ * Take a comma separated list of actions and or the flags
+ * together for the ioctl.
+ */
+static int
+timeout_act_str2int(const char *lopt, const char *acts)
+{
+	int i;
+	char *dupacts, *tofree;
+	char *o;
+	int rv = 0;
+
+	tofree = dupacts = strdup(acts);
+	if (!tofree)
+		err(EX_OSERR, "malloc");
+	while ((o = strsep(&dupacts, ",")) != NULL) {
+		for (i = 0; act_tbl[i].at_act != NULL; i++) {
+			if (!strcmp(o, act_tbl[i].at_act)) {
+				rv |= act_tbl[i].at_value;
+				break;
+			}
+		}
+		if (act_tbl[i].at_act == NULL)
+			timeout_act_error(lopt, o);
+	}
+	free(tofree);
+	return rv;
+}
+
 /*
  * Handle the few command line arguments supported.
  */
 static void
 parseargs(int argc, char *argv[])
 {
+	int longindex;
 	int c;
 	char *p;
+	const char *lopt;
 	double a;
 
+	/*
+	 * if we end with a 'd' aka 'watchdogd' then we are the daemon program,
+	 * otherwise run as a command line utility.
+	 */
 	c = strlen(argv[0]);
 	if (argv[0][c - 1] == 'd')
 		is_daemon = 1;
-	while ((c = getopt(argc, argv,
-	    is_daemon ? "I:de:ns:t:ST:w?" : "dt:?")) != -1) {
+
+	if (is_daemon)
+		getopt_shortopts = "I:de:ns:t:ST:w?";
+	else
+		getopt_shortopts = "dt:?";
+
+	while ((c = getopt_long(argc, argv, getopt_shortopts, longopts,
+		    &longindex)) != -1) {
 		switch (c) {
 		case 'I':
 			pidfile = optarg;
@@ -384,7 +548,7 @@ parseargs(int argc, char *argv[])
 			break;
 #endif
 		case 's':
-			nap = fetchtimeout(c, optarg);
+			nap = fetchtimeout(c, NULL, optarg);
 			break;
 		case 'S':
 			do_syslog = 1;
@@ -397,6 +561,7 @@ parseargs(int argc, char *argv[])
 				errx(EX_USAGE, "-t argument is not a number");
 			if (a < 0)
 				errx(EX_USAGE, "-t argument must be positive");
+
 			if (a == 0)
 				timeout = WD_TO_NEVER;
 			else
@@ -406,11 +571,28 @@ parseargs(int argc, char *argv[])
 				    timeout);
 			break;
 		case 'T':
-			carp_thresh_seconds = fetchtimeout(c, optarg);
+			carp_thresh_seconds = fetchtimeout(c, "NULL", optarg);
 			break;
 		case 'w':
 			do_timedog = 1;
 			break;
+		case 0:
+			lopt = longopts[longindex].name;
+			if (!strcmp(lopt, "pretimeout")) {
+				pretimeout = fetchtimeout(0, lopt, optarg);
+			} else if (!strcmp(lopt, "pretimeout-action")) {
+				pretimeout_act = timeout_act_str2int(lopt,
+				    optarg);
+			} else if (!strcmp(lopt, "softtimeout-action")) {
+				softtimeout_act = timeout_act_str2int(lopt,
+				    optarg);
+			} else {
+		/*		warnx("bad option at index %d: %s", optind,
+				    argv[optind]);
+				usage();
+				*/
+			}
+			break;
 		case '?':
 		default:
 			usage();



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302170904.r1H94gnq055684>