[Nut-upsdev] [PATCH 31/36] Implement the UPS DYING state.

Greg A. Woods woods at planix.com
Thu Mar 8 23:21:42 UTC 2012


From: "Greg A. Woods" <woods at planix.com>

This change adds a new "DYING" state which UPS drivers may declare for
emergency conditions other than OB+LB where the UPS must be shut down as
quickly as possible even if mains power remains steady, and to do so in
such a way that load is removed, and ideally the UPS itself powers down,
and everything stays off until a human manually restores power
(presumably after fixing the situation that caused the UPS to die).

This makes use of the new Emergency Power Off support added in the
previous change.
---
 clients/status.h        |    8 +++
 clients/upsmon.c        |  168 +++++++++++++++++++++++++++++++++++++++--------
 clients/upsmon.h        |   23 ++++---
 conf/upsmon.conf.sample |    9 ++-
 docs/config-notes.txt   |   19 ++++--
 docs/man/upsmon.txt     |   40 +++++++----
 docs/net-protocol.txt   |    4 +-
 docs/new-drivers.txt    |    4 +-
 drivers/apcsmart.h      |    1 +
 drivers/dummy-ups.h     |    2 +
 10 files changed, 217 insertions(+), 61 deletions(-)

diff --git a/clients/status.h b/clients/status.h
index 20cb858..ba70661 100644
--- a/clients/status.h
+++ b/clients/status.h
@@ -17,6 +17,13 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
+/*
+ * This maps ups.status values to meaningful names and severity values, both of
+ * which are currently only used by upsstats.
+ *
+ * XXX why the heck isn't FSD here!?!?!? 
+ */
+
 struct {
 	char	*name;
 	char	*desc;
@@ -28,6 +35,7 @@ struct {
 	{ "OB",		"ON BATTERY",		2	},
 	{ "LB",		"LOW BATTERY",		2	},
 	{ "RB",		"REPLACE BATTERY",	2	},
+	{ "DYING",	"DYING",		2	},
 	{ "OVER",	"OVERLOAD",		2	},
 	{ "TRIM",	"VOLTAGE TRIM",		1	},
 	{ "BOOST",	"VOLTAGE BOOST",	1	},
diff --git a/clients/upsmon.c b/clients/upsmon.c
index 5116437..d7b12ef 100644
--- a/clients/upsmon.c
+++ b/clients/upsmon.c
@@ -628,17 +628,19 @@ static void forceshutdown(int epo)
 	 * UPS smart enough to have a proper working driver with a proper
 	 * working "shutdown.stayoff" command.
 	 */
-	for (ups = firstups; ups != NULL; ups = ups->next)
+	for (ups = firstups; ups != NULL; ups = ups->next) {
 		if (flag_isset(ups->status, ST_MASTER)) {
 			isamaster = 1;
 			setfsd(ups);
 		}
-
+	}
 	/* if we're not a master on anything, we should shut down now */
-	if (!isamaster)
+	if (!isamaster) {
 		doshutdown(epo);
+		/* does not return */
+	}
 
-	/* must be the master now */
+	/* must be the master... */
 	upsdebugx(1, "This system is a master... waiting for slave logout...");
 
 	/* wait up to HOSTSYNC seconds for slaves to logout */
@@ -646,6 +648,21 @@ static void forceshutdown(int epo)
 
 	/* time expired or all the slaves are gone, so shutdown */
 	doshutdown(epo);
+	/* does not return */
+}
+
+static void epo_ups(utype_t *ups)
+{
+	char    buf[LARGEBUF];
+
+	/*
+	 * directly command a UPS to do an EPO via upsdrvctl(8)
+	 */
+	snprintf(buf, sizeof(buf), "%s/%s epo %s", BINDIR, "upsdrvctl", ups->upsname);
+
+	upslogx(LOG_WARNING, "master sending EPO to driver for dying UPS %s", ups->sys);
+
+	(void) system(buf);		/* hope for the best... */
 }
 
 static int is_ups_critical(utype_t *ups)
@@ -656,31 +673,59 @@ static int is_ups_critical(utype_t *ups)
 	if (flag_isset(ups->status, ST_FSD))
 		return 1;
 
-	/* not OB or not LB = not critical yet */
+	/*
+	 * If this UPS is DYING then it's time to shut down now!
+	 *
+	 * In doing so we will use the EPO method (determined in the caller,
+	 * recalc()), and we will also set FSD on it (in forceshutdown()) so
+	 * that user users of its power can safely shut down first.
+	 *
+	 * XXX it might be nice to return multiple flags from this function so
+	 * that the caller doesn't have to re-test the status again....
+	 */
+	if (flag_isset(ups->status, ST_DYING))
+		return 1;
+
+	/*
+	 * if UPS is not OnBatter, or not LowBattery, then it is not critical
+	 * (it can be OL+LB, and hopefully charging too), but we can keep on
+	 * computing...
+	 */
 	if ((!flag_isset(ups->status, ST_ONBATT)) ||
-		(!flag_isset(ups->status, ST_LOWBATT)))
+	    (!flag_isset(ups->status, ST_LOWBATT)))
 		return 0;
 
-	/* must be OB+LB now */
+	/* Must be OB+LB now, i.e. critical! */
 
-	/* if we're a master, declare it critical so we set FSD on it */
+	/*
+	 * if we're the master of this UPS, declare it critical so that we can
+	 * shut down now
+	 *
+	 * in doing so we will set FSD on the UPS (in forceshutdown()) to
+	 * notify other users of its power that we're going to shut it off and
+	 * wait for mains power to return
+	 */
 	if (flag_isset(ups->status, ST_MASTER))
 		return 1;
 
-	/* must be a slave now */
-
-	/* FSD isn't set, so the master hasn't seen it yet */
-
+	/*
+	 * otherwise we're a slave....
+	 *
+	 * ... but apparently FSD isn't set, so the master hasn't seen it yet.
+	 *
+	 * This is odd!
+	 *
+	 * Give the master time to notice the UPS state (up to HOSTSYNC
+	 * seconds) before we declare it critical and shut down anyway
+	 */
 	time(&now);
-
-	/* give the master up to HOSTSYNC seconds before shutting down */
 	if ((now - ups->lastnoncrit) > hostsync) {
 		upslogx(LOG_WARNING, "Giving up on the master for UPS [%s]",
 			ups->sys);
 		return 1;
 	}
 
-	/* there's still time left */
+	/* all is well, keep on computing... */
 	return 0;
 }
 
@@ -688,7 +733,7 @@ static int is_ups_critical(utype_t *ups)
 static void recalc(void)
 {
 	utype_t	*ups;
-	int	val_ol = 0;
+	int	val_ol = 0, epo = 0;
 	time_t	now;
 
 	time(&now);
@@ -706,12 +751,14 @@ static void recalc(void)
 		 * this means a UPS we've never heard from is assumed OL     *
 		 * whether this is really the best thing to do is undecided  */
 
-		/* crit = (FSD) || (OB & LB) > HOSTSYNC seconds */
-		if (is_ups_critical(ups))
-			upsdebugx(1, "Critical UPS: %s", ups->sys);
-		else
+		/* crit = (FSD) || (DYING) || (OB & LB) > HOSTSYNC seconds */
+		if (is_ups_critical(ups)) {
+			if (flag_isset(ups->status, ST_DYING))
+				epo = 1;
+			upsdebugx(1, "%s UPS: %s", epo ? "Dying" : "Critical", ups->sys);
+		} else {
 			val_ol += ups->pv;
-
+		}
 		ups = ups->next;
 	}
 
@@ -720,8 +767,50 @@ static void recalc(void)
 	upsdebugx(3, "Minimum power value: %d", minsupplies);
 #endif
 
-	if (val_ol < minsupplies)
-		forceshutdown(0);	/* !epo */
+	if (val_ol < minsupplies) {
+		/*
+		 * XXX if "epo" is true this will EPO _all_ of the UPS's this
+		 * host is master to, not just the critical one!
+		 *
+		 * Idealy we only want to permanently shut down the DYING UPS,
+		 * but, in this case where we don't have an alternate power
+		 * source we would like the non-DYING units to return if/when
+		 * mains power is on.
+		 */
+		forceshutdown(epo);
+		/* does not return */
+	} else if (epo) {
+		/*
+		 * If we got here then this host is not shutting down but one
+		 * or more UPS units it monitors was in need EPO.
+		 *
+		 * We go through the list one more time to see if....
+		 */
+		ups = firstups;
+		while (ups != NULL) {
+			if (flag_isset(ups->status, ST_DYING) &&
+			    flag_isset(ups->status, ST_MASTER)) {
+
+				/*
+				 * the current UPS has been marked as dying and
+				 * this host is its master, and apparently this
+				 * host has additional power source(s), so just
+				 * do a forced shutdown on the dying UPS and
+				 * command its driver directly to EPO the UPS
+				 * after slaves have had a chance to shut down.
+				 *
+				 * XXX this could take some time if there are
+				 * several such UPS units in trouble -- maybe
+				 * we should fork a child process to handle
+				 * this job for each dying UPS?
+				 */
+				setfsd(ups);
+				slavesync();
+				epo_ups(ups);
+			}
+			ups = ups->next;
+		}
+	}
 }		
 
 static void ups_low_batt(utype_t *ups)
@@ -751,6 +840,21 @@ static void upsreplbatt(utype_t *ups)
 	}
 }
 
+static void ups_dying(utype_t *ups)
+{
+	if (flag_isset(ups->status, ST_DYING)) {	/* no change */
+		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
+		return;
+	}
+
+	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
+
+	/* must have changed from !DYING to DYING, so notify */
+
+	do_notify(ups, NOTIFY_DYING);
+	setflag(&ups->status, ST_DYING);
+}
+
 static void ups_fsd(utype_t *ups)
 {
 	if (flag_isset(ups->status, ST_FSD)) {		/* no change */
@@ -1372,12 +1476,13 @@ static void setup_signals(void)
 	sigaction(SIGCMD_RELOAD, &sa, NULL);
 }
 
-/* remember the last time the ups was not critical (OB + LB) */
+/* remember the last time the UPS was "not critical" (!DYING || !OB || !LB) */
 static void update_crittimer(utype_t *ups)
 {
-	/* if !OB or !LB, then it's not critical, so log the time */
-	if ((!flag_isset(ups->status, ST_ONBATT)) || 
-		(!flag_isset(ups->status, ST_LOWBATT))) {
+	/* if !DYING or !OB or !LB, then it's not critical, so mark the time */
+	if ((!flag_isset(ups->status, ST_DYING)) ||
+	    (!flag_isset(ups->status, ST_ONBATT)) ||
+	    (!flag_isset(ups->status, ST_LOWBATT))) {
 
 		time(&ups->lastnoncrit);
 		return;
@@ -1504,6 +1609,8 @@ static void parse_status(utype_t *ups, char *status)
 	/* clear these out early if they disappear */
 	if (!strstr(status, "LB"))
 		clearflag(&ups->status, ST_LOWBATT);
+	if (!strstr(status, "DYING"))
+		clearflag(&ups->status, ST_DYING);
 	if (!strstr(status, "FSD"))
 		clearflag(&ups->status, ST_FSD);
 
@@ -1525,6 +1632,8 @@ static void parse_status(utype_t *ups, char *status)
 			ups_low_batt(ups);
 		if (!strcasecmp(statword, "RB"))
 			upsreplbatt(ups);
+		if (!strcasecmp(statword, "DYING"))
+			ups_dying(ups);
 
 		/* do it last to override any possible OL */
 		if (!strcasecmp(statword, "FSD"))
@@ -2026,9 +2135,10 @@ int main(int argc, char *argv[])
 		utype_t	*ups;
 
 		/* check flags from signal handlers */
-		if (userfsd || userepo)
+		if (userfsd || userepo) {
 			forceshutdown(userepo);
-
+			/* does not return */
+		}
 		if (reload_flag)
 			reload_conf();
 
diff --git a/clients/upsmon.h b/clients/upsmon.h
index 9c5fe39..b672560 100644
--- a/clients/upsmon.h
+++ b/clients/upsmon.h
@@ -23,9 +23,10 @@
 #define ST_ONBATT	(1 << 1)	/* UPS is on battery (OB)		*/
 #define ST_LOWBATT	(1 << 2)  	/* UPS has a low battery (LB)		*/
 #define ST_FSD		(1 << 3)	/* master has set forced shutdown flag	*/
-#define ST_MASTER	(1 << 4)	/* we are the master on this UPS	*/
-#define ST_LOGIN	(1 << 5)  	/* we are logged into this UPS		*/
-#define ST_CONNECTED	(1 << 6)	/* upscli_connect returned OK		*/
+#define ST_DYING	(1 << 4)	/* UPS is dying for some other reason	*/
+#define ST_MASTER	(1 << 5)	/* we are the master on this UPS	*/
+#define ST_LOGIN	(1 << 6)  	/* we are logged into this UPS		*/
+#define ST_CONNECTED	(1 << 7)	/* upscli_connect returned OK		*/
 
 /* required contents of flag file */
 #define SDMAGIC		"upsmon-shutdown-file" /* may be followed by " epo" */
@@ -62,13 +63,14 @@ typedef struct {
 #define NOTIFY_ONLINE	0	/* UPS went on-line			*/
 #define NOTIFY_ONBATT	1	/* UPS went on battery			*/
 #define NOTIFY_LOWBATT	2	/* UPS went to low battery		*/
-#define NOTIFY_FSD	3	/* Master upsmon set FSD flag		*/
-#define NOTIFY_COMMOK	4	/* Communication established		*/
-#define NOTIFY_COMMBAD	5	/* Communication lost			*/
-#define NOTIFY_SHUTDOWN	6	/* System shutdown in progress		*/
-#define NOTIFY_REPLBATT	7	/* UPS battery needs to be replaced	*/
-#define NOTIFY_NOCOMM	8	/* UPS hasn't been contacted in awhile	*/
-#define NOTIFY_NOPARENT	9	/* privileged parent process died	*/
+#define NOTIFY_DYING	3	/* UPS is dying for some other reason	*/
+#define NOTIFY_FSD	4	/* Master upsmon set FSD flag		*/
+#define NOTIFY_COMMOK	5	/* Communication established		*/
+#define NOTIFY_COMMBAD	6	/* Communication lost			*/
+#define NOTIFY_SHUTDOWN	7	/* System shutdown in progress		*/
+#define NOTIFY_REPLBATT	8	/* UPS battery needs to be replaced	*/
+#define NOTIFY_NOCOMM	9	/* UPS hasn't been contacted in awhile	*/
+#define NOTIFY_NOPARENT	10	/* privileged parent process died	*/
 
 /* notify flag values */
 
@@ -92,6 +94,7 @@ struct {
 	{ NOTIFY_ONBATT,   "ONBATT",   NULL, "UPS %s on battery", NOTIFY_SYSLOG | NOTIFY_WALL },
 	{ NOTIFY_LOWBATT,  "LOWBATT",  NULL, "UPS %s battery is low", NOTIFY_SYSLOG | NOTIFY_WALL },
 	{ NOTIFY_FSD,	   "FSD",      NULL, "UPS %s: forced shutdown in progress", NOTIFY_SYSLOG | NOTIFY_WALL },
+	{ NOTIFY_DYING,    "DYING",    NULL, "UPS %s is dying", NOTIFY_SYSLOG | NOTIFY_WALL },
 	{ NOTIFY_COMMOK,   "COMMOK",   NULL, "Communications with UPS %s established", NOTIFY_SYSLOG | NOTIFY_WALL },
 	{ NOTIFY_COMMBAD,  "COMMBAD",  NULL, "Communications with UPS %s lost", NOTIFY_SYSLOG | NOTIFY_WALL },
 	{ NOTIFY_SHUTDOWN, "SHUTDOWN", NULL, "Auto logout and shutdown proceeding", NOTIFY_SYSLOG | NOTIFY_WALL },
diff --git a/conf/upsmon.conf.sample b/conf/upsmon.conf.sample
index 6e09429..6605d44 100644
--- a/conf/upsmon.conf.sample
+++ b/conf/upsmon.conf.sample
@@ -73,9 +73,11 @@
 #		upsmon master 	(or slave)
 # 
 # "master" means this system will shutdown last, allowing the slaves
-# time to shutdown first.
+# time to shutdown first.  This system is also expected to manage the
+# UPS, sending it commands to shutdown when necessary.
 #
 # "slave" means this system shuts down immediately when power goes critical.
+# This system does not manage the UPS.
 #
 # Examples: 
 #
@@ -194,7 +196,7 @@ DEADTIME 15
 # to shut down the load.  You should check for this file's existence in
 # your shutdown scripts and run 'upsdrvctl shutdown' if it exists.
 #
-# See the shutdown.txt file in the docs subdirectory for more information.
+# See the config-notes.txt file in the docs subdirectory for more information.
 
 POWERDOWNFLAG /etc/killpower
 
@@ -207,6 +209,7 @@ POWERDOWNFLAG /etc/killpower
 #
 # NOTIFYMSG ONLINE	"UPS %s on line power"
 # NOTIFYMSG ONBATT	"UPS %s on battery"
+# NOTIFYMSG DYING	"UPS %s is in imminent danger of failing"
 # NOTIFYMSG LOWBATT	"UPS %s battery is low"
 # NOTIFYMSG FSD		"UPS %s: forced shutdown in progress"
 # NOTIFYMSG COMMOK	"Communications with UPS %s established"
@@ -223,6 +226,7 @@ POWERDOWNFLAG /etc/killpower
 # ONLINE   : UPS is back online
 # ONBATT   : UPS is on battery
 # LOWBATT  : UPS has a low battery (if also on battery, it's "critical")
+# DYING    : UPS has serious failure condition and must be shut down
 # FSD      : UPS is being shutdown by the master (FSD = "Forced Shutdown")
 # COMMOK   : Communications established with the UPS
 # COMMBAD  : Communications lost to the UPS
@@ -242,6 +246,7 @@ POWERDOWNFLAG /etc/killpower
 # NOTIFYFLAG ONLINE	SYSLOG+WALL
 # NOTIFYFLAG ONBATT	SYSLOG+WALL
 # NOTIFYFLAG LOWBATT	SYSLOG+WALL
+# NOTIFYFLAG DYING	SYSLOG+WALL
 # NOTIFYFLAG FSD	SYSLOG+WALL
 # NOTIFYFLAG COMMOK	SYSLOG+WALL
 # NOTIFYFLAG COMMBAD	SYSLOG+WALL
diff --git a/docs/config-notes.txt b/docs/config-notes.txt
index 0042e61..070b3d6 100644
--- a/docs/config-notes.txt
+++ b/docs/config-notes.txt
@@ -250,7 +250,7 @@ You should see just one line in response:
 	OL
 
 OL means your system is running on line power.  If it says something
-else (like OB - on battery, or LB - low battery), your driver was 
+else (like OB - on battery, or LB - low battery, or DYING - imminent failure), your driver was 
 probably misconfigured during the <<Driver_configuration, Driver configuration>>
 step.  If you reconfigure the driver, use 'upsdrvctl stop' to stop it, then
 start it again as shown in the <<Starting_drivers, Starting driver(s)>> step.
@@ -355,10 +355,18 @@ Here are the steps that occur when a critical power event happens:
 +
    ups.status: OB LB
 +
+or maybe:
++
+   ups.status: OL DYING
++
 The exact behavior depends on the specific device, and is related to:
 +
    - battery.charge and battery.charge.low
    - battery.runtime and battery.runtime.low
+#blank line to end nested list#
+
++
+or some other critical parameter, such as temperature.
 
 3. The upsmon master notices and sets "FSD" - the "forced shutdown"
    flag to tell all slave systems that it will soon power down the load.
@@ -381,7 +389,7 @@ The exact behavior depends on the specific device, and is related to:
 
    - generates a NOTIFY_SHUTDOWN event
    - waits FINALDELAY seconds - typically 5
-   - creates the POWERDOWNFLAG file - usually /etc/killpower
+   - creates the POWERDOWNFLAG file - usually /etc/killpower - noting EPO
    - calls the SHUTDOWNCMD
 
 7. On most systems, init takes over, kills your processes, syncs and
@@ -394,9 +402,10 @@ The exact behavior depends on the specific device, and is related to:
    POWERDOWNFLAG, finds it, and tells the UPS driver(s) to power off the
    load by running "upsdrvctl shutdown".  At the moment the driver
    decides how to power down the load and/or the UPS.  Usually this
-   means that if the UPS is still online, but is being shut off by force.
-   The driver will have to command it to shut off and stay off, thus
-   requiring human intervention to restore power.
+   means that if the UPS is still online, but is being shut off by force
+   or because of an emergency "DYING" state, then the driver will have
+   to command it to shut off and stay off, thus requiring human
+   intervention to restore power.
 
 9. The system loses power.
 
diff --git a/docs/man/upsmon.txt b/docs/man/upsmon.txt
index 95d8c1b..96d0c99 100644
--- a/docs/man/upsmon.txt
+++ b/docs/man/upsmon.txt
@@ -25,7 +25,7 @@ power events.
 
 upsmon can monitor multiple systems using a single process.  Every UPS
 that is defined in the linkman:upsmon.conf[5] configuration file is assigned
-a power value and a type (slave or master).  
+a power value and a type (*slave* or *master*).  
 
 OPTIONS
 -------
@@ -37,9 +37,9 @@ Display the help message.
 Send the command 'command' to the existing upsmon process.  Valid
 commands are:
 
-*fsd*;; shutdown all master UPSes (use with caution)
+*fsd*;; shutdown all *master*-mode UPSes (use with caution)
 
-*epo*;; Emergency Power Off of all master UPSes (use with caution)
+*epo*;; Emergency Power Off of all *master*-mode UPSes (use with caution)
 
 *stop*;; stop monitoring and exit
 
@@ -107,10 +107,17 @@ Whatever password you set in that section must match the 'password'
 set in this file.  
 
 The type set in that section must also match the 'type' here--
-*master* or *slave*.  In general, a master process is one
+*master* or *slave*.  In general, a master upsmon process is the one
 running on the system with the UPS actually plugged into a serial
-port, and a slave is drawing power from the UPS but can't talk to it
-directly.  See the section on UPS types for more.
+port, and a slave process is running on a system drawing power from the
+UPS but it can't talk to the UPS directly.
+See the section on UPS types for more.
+
+Note that it would generally be an error to set a UPS to *master* if its
+driver is not running on the local system.  Upsmon will use
+linkman:upsdrvctl[8] to do send any necessary emergency power off
+commands to the UPS using only the "upsname" portion of 'system'
+specified.
 
 NOTIFY EVENTS
 -------------
@@ -129,6 +136,9 @@ The UPS is on battery.
 *LOWBATT*::
 The UPS battery is low (as determined by the driver).
 
+*DYING*::
+The UPS is in imminent danger of failing (as determined by the driver).
+
 *FSD*::
 The UPS has been commanded into the "forced shutdown" mode.
 
@@ -247,7 +257,7 @@ may be greater than 1.  You may also have more than one of them defined.
 You can also set the power value for a UPS to 0 if it does not supply any
 power to that system.  This is generally used when you want to use the
 upsmon notification features for a UPS even though it's not actually
-running the system that hosts upsmon.  Don't set this to "master" unless
+running the system that hosts upsmon.  Don't set this to *master* unless
 you really want to power this UPS off when this instance of upsmon needs
 to shut down for its own reasons.
 
@@ -278,7 +288,7 @@ UPS TYPES
 
 *upsmon* and linkman:upsd[8] don't always run on the same system.  When they
 do, any UPSes that are directly attached to the upsmon host should be
-monitored in "master" mode.  This makes upsmon take charge of that
+monitored in *master* mode.  This makes upsmon take charge of that
 equipment, and it will wait for slaves to disconnect before shutting
 down the local system.  This allows the distant systems (monitoring over
 the network) to shut down cleanly before `upsdrvctl shutdown` runs
@@ -368,7 +378,7 @@ FORCED SHUTDOWNS
 ----------------
 
 When upsmon is forced to bring down the local system, it sets the
-"FSD" (forced shutdown) flag on any UPSes that it is running in master
+"FSD" (forced shutdown) flag on any UPSes that it is managing in master
 mode.  This is used to synchronize slaves in the event that a master UPS
 that is otherwise OK needs to be brought down due to some pressing event
 on the master.
@@ -378,6 +388,12 @@ copy with `-c fsd`.  This is useful when you want to initiate a shutdown
 before the critical stage through some external means, such as
 linkman:upssched[8].
 
+Upsmon may also shut down a managed UPS in the "DYING" state without
+shutting down the local system, if the overall power value without that
+UPS would remain higher than the configured setting for "MINSUPPLIES".
+In this case it will still set the "FSD" flag on the UPS before shutting
+it down.
+
 DEAD UPSES
 ----------
 
@@ -430,9 +446,9 @@ they still have mains power, so ready for a restart.
 EMERGENCY POWER OFF
 -------------------
 
-To handle emergency situations you can set the emergency power off (EPO)
-flag on your master upsmon system.  You can do this by calling upsmon
-again to set the flag, i.e.:
+To handle emergency situations you can send the emergency power off (EPO)
+command on your master upsmon system.  You can do this by calling upsmon
+as follows:
 
 +upsmon -c epo+
 
diff --git a/docs/net-protocol.txt b/docs/net-protocol.txt
index 1420587..59eeba4 100644
--- a/docs/net-protocol.txt
+++ b/docs/net-protocol.txt
@@ -395,8 +395,8 @@ done so that slave systems will know about it and shut down before the
 power disappears.
 
 Setting this flag makes "FSD" appear in a STATUS request for this UPS.
-Finding "FSD" in a status request should be treated just like a "OB LB".
-Note that since from the point of view of a slave system
+Finding "FSD" in a status request should be treated just like a "OB LB"
+or "DYING".  Note that since from the point of view of a slave system
 there is no difference between a forced shutdown and an emergency power
 off so there is no equivalent "EPO" function in the protocol.
 
diff --git a/docs/new-drivers.txt b/docs/new-drivers.txt
index a59e389..3a918e9 100644
--- a/docs/new-drivers.txt
+++ b/docs/new-drivers.txt
@@ -135,7 +135,8 @@ or not an Emergency Power Off (EPO) shutdown has been requested or not.
 
 In the case of an EPO shutdown you may need to use a different device
 command to shut down the UPS and say off if it is still online (as it
-most likely will be in the EPO shutdown scenario), e.g. being shutdown as a
+most likely will be in the EPO shutdown scenario), e.g. when your driver
+has sent out an emergency "DYING" status and is then being shutdown as a
 result of an Emergency Power Off (EPO) command from its master upsmon.
 Use the same method as you use for a "shutdown.stayoff" command.
 
@@ -210,6 +211,7 @@ Possible values for status_set:
 	OL      - On line (mains is present)
 	OB      - On battery (mains is not present)
 	LB      - Low battery
+	DYING   - The UPS is dying and must be powered off (mains may be present)
 	RB      - The battery needs to be replaced
 	CHRG    - The battery is charging
 	DISCHRG - The battery is discharging (inverter is providing load power)
diff --git a/drivers/apcsmart.h b/drivers/apcsmart.h
index d06fb27..542a035 100644
--- a/drivers/apcsmart.h
+++ b/drivers/apcsmart.h
@@ -123,6 +123,7 @@
 #define APC_STAT_OVER	(1 << 5)	/* overload */
 #define APC_STAT_LB	(1 << 6)	/* low battery */
 #define APC_STAT_RB	(1 << 7)	/* replace battery */
+#define APC_STAT_DYING	(1 << 8)	/* dying! */
 
 /*
  * serial protocol: special commands - initialization and such
diff --git a/drivers/dummy-ups.h b/drivers/dummy-ups.h
index ba49094..5b2706b 100644
--- a/drivers/dummy-ups.h
+++ b/drivers/dummy-ups.h
@@ -62,6 +62,7 @@ typedef struct {
 #define STATUS_OFF		(1 << 9)	/* ups is off */
 #define STATUS_CHRG		(1 << 10)	/* charging */
 #define STATUS_DISCHRG		(1 << 11)	/* discharging */
+#define STATUS_DYING		(1 << 12)	/* imminent death predicted */
  
 /*
  * Status lookup table
@@ -74,6 +75,7 @@ status_lkp_t status_info[] = {
   { "OB", STATUS_OB },
   { "OVER", STATUS_OVER },
   { "LB", STATUS_LB },
+  { "DYING", STATUS_DYING },
   { "RB", STATUS_RB },
   { "BYPASS", STATUS_BYPASS },
   { "OFF", STATUS_OFF },
-- 
1.7.9.2




More information about the Nut-upsdev mailing list