From owner-svn-src-user@FreeBSD.ORG Sun Feb 17 09:04:43 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 56B17CD; Sun, 17 Feb 2013 09:04:43 +0000 (UTC) (envelope-from alfred@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 48848EAE; Sun, 17 Feb 2013 09:04:43 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1H94hoe055689; Sun, 17 Feb 2013 09:04:43 GMT (envelope-from alfred@svn.freebsd.org) Received: (from alfred@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1H94gnq055684; Sun, 17 Feb 2013 09:04:42 GMT (envelope-from alfred@svn.freebsd.org) Message-Id: <201302170904.r1H94gnq055684@svn.freebsd.org> From: Alfred Perlstein Date: Sun, 17 Feb 2013 09:04:42 +0000 (UTC) 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 X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Feb 2013 09:04:43 -0000 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 + * * 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 + * Copyright (c) 2013 iXsystems.com, + * author: Alfred Perlstein + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + 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();