Skip to content

Commit c44c157

Browse files
authored
Merge decb643 into f99109d
2 parents f99109d + decb643 commit c44c157

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1583
-470
lines changed

NEWS.adoc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,24 @@ during a NUT build.
318318
for `bcmxcp_usb`, `richcomm_usb` and `nutdrv_atcl_usb` drivers for now
319319
[#1763, #1764, #1768, #2580]
320320
321+
- all drivers should now support the optional `sdcommands` setting with
322+
a site-local list of instant commands to handle `upsdrv_shutdown()`,
323+
which may be useful in cases when the driver's built-in commands
324+
(or their order) do not meet the goals of particular NUT deployment.
325+
This can also help with shutdown endgame testing, using a mock command like
326+
starting the beeper (where supported) to verify that the UPS communications
327+
happen as expected, without compromising the load connected to the UPS.
328+
+
329+
Also defined `EF_EXIT_SUCCESS` and `EF_EXIT_FAILURE` in `include/common.h`
330+
to avoid magic numbers in code like `set_exit_flag(-2)`, and revised whether
331+
it is getting set at all in "killpower" vs. other cases, based on new
332+
`handling_upsdrv_shutdown` internal flag.
333+
+
334+
NOTE: during this overhaul, many older drivers got their first ever supported
335+
INSTCMD such as `shutdown.return`, `shutdown.stayoff` or `load.off`. Default
336+
logic that was previously the content of `upsdrv_shutdown()` methods was often
337+
relocated into new `shutdown.default` INSTCMD definitions. [#2670]
338+
321339
- common code:
322340
* introduced a `NUT_DEBUG_SYSLOG` environment variable to tweak activation
323341
of syslog message emission (and related detachment of `stderr` when

conf/ups.conf.sample

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ maxretry = 3
160160
#
161161
# The default value for this parameter is 0.
162162
#
163+
# sdcommands: OPTIONAL. Comma-separated list of instant command name(s)
164+
# to send to the UPS when you request its shutdown. For more
165+
# details about relevant use-cases see the ups.conf manual page.
166+
#
167+
# The default value is built into each driver (where supported).
168+
#
163169
# desc: optional, to keep a note of the UPS purpose, location, etc.
164170
#
165171
# nolock: optional, and not recommended for use in this file.

docs/man/ups.conf.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,31 @@ set this to -1.
215215
+
216216
The default value for this parameter is 0.
217217

218+
*sdcommands*::
219+
220+
Optional. Comma-separated list of instant command name(s) to send to
221+
the UPS when you request its shutdown.
222+
+
223+
Default logic is built into each driver (where supported) and can be
224+
referenced here as the `shutdown.default` value.
225+
+
226+
The primary use-case is for devices whose drivers "natively" support
227+
trying several commands, but the built-in order of those calls a
228+
command that is mis-handled by the specific device model (so the
229+
handling is reported as successful and the loop stops, but nothing
230+
happens as far as the load power-down is concerned).
231+
+
232+
Another use-case is differentiation of automated power-off scenarios
233+
where the UPS and its load should stay "OFF" (e.g. by building emergency
234+
power-off) vs. those where the load should return to work automatically
235+
when it is safe to do so. NOTE: This would *currently* need editing of
236+
`ups.conf` for such cases before `nutshutdown` sees the file; but could
237+
be better automated in future NUT releases.
238+
+
239+
NOTE: User-provided commands may be something other than actual shutdown,
240+
e.g. a beeper to test that the INSTCMD happened such and when expected,
241+
and the device was contacted, without impacting the load fed by the UPS.
242+
218243
*allow_killpower*::
219244
Optional. This allows you to request `driver.killpower` instant command,
220245
to immediately call the driver-specific default implementation of

docs/new-drivers.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,10 @@ process.
162162
This method should not directly `exit()` the driver program (neither
163163
should it call `fatalx()` nor `fatal_with_errno()` methods). It can
164164
`upslogx(LOG_ERR, ...)` or `upslog_with_errno(LOG_ERR, ...)`, and then
165-
`set_exit_flag(N)` if required (`-1` for `EXIT_FAILURE` and `-2` for
166-
`EXIT_SUCCESS` which would be handled in the standard driver loop or
167-
`forceshutdown()` method of `main.c`).
165+
`set_exit_flag(N)` if required, using values `EF_EXIT_FAILURE` (`-1`)
166+
for eventual `exit(EXIT_FAILURE)` and `EF_EXIT_SUCCESS` (`-2`) for
167+
`exit(EXIT_SUCCESS)`, which would be handled in the standard driver
168+
loop or in `forceshutdown()` method of `main.c`.
168169

169170
Data types
170171
----------

docs/nut-names.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,13 @@ Instant commands
852852
| load.on | Turn on the load immediately
853853
| load.off.delay | Turn off the load possibly after a delay
854854
| load.on.delay | Turn on the load possibly after a delay
855+
| shutdown.default | Run default driver-defined (device-specific)
856+
routine, primarily intended for emergency
857+
poweroff performed as part of FSD handling;
858+
often an alias to other `shutdown.*` and/or
859+
`load.off` operations or a chain to try
860+
several of those. See also `sdcommands` in
861+
common driver options.
855862
| shutdown.return | Turn off the load possibly after a delay
856863
and return when power is back
857864
| shutdown.stayoff | Turn off the load possibly after a delay

docs/nut.dict

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
personal_ws-1.1 en 3246 utf-8
1+
personal_ws-1.1 en 3247 utf-8
22
AAC
33
AAS
44
ABI
@@ -2753,6 +2753,7 @@ screenshots
27532753
scriptname
27542754
sd
27552755
sdcmd
2756+
sdcommands
27562757
sddelay
27572758
sdk
27582759
sdl

drivers/adelsystem_cbi.c

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#include <timehead.h>
3131

3232
#define DRIVER_NAME "NUT ADELSYSTEM DC-UPS CB/CBI driver"
33-
#define DRIVER_VERSION "0.03"
33+
#define DRIVER_VERSION "0.04"
3434

3535
/* variables */
3636
static modbus_t *mbctx = NULL; /* modbus memory context */
@@ -49,7 +49,6 @@ static uint32_t mod_resp_to_us = MODRESP_TIMEOUT_us; /* set the modbus response
4949
static uint32_t mod_byte_to_s = MODBYTE_TIMEOUT_s; /* set the modbus byte time out (us) */
5050
static uint32_t mod_byte_to_us = MODBYTE_TIMEOUT_us; /* set the modbus byte time out (us) */
5151

52-
5352
/* initialize alarm structs */
5453
void alrminit(void);
5554

@@ -193,6 +192,11 @@ void upsdrv_initinfo(void)
193192
/* register instant commands */
194193
dstate_addcmd("load.off");
195194

195+
/* FIXME: Check with the device what this instcmd
196+
* (nee upsdrv_shutdown() contents) actually does!
197+
*/
198+
dstate_addcmd("shutdown.stayoff");
199+
196200
/* set callback for instant commands */
197201
upsh.instcmd = upscmd;
198202
}
@@ -464,33 +468,24 @@ void upsdrv_updateinfo(void)
464468
/* shutdown UPS */
465469
void upsdrv_shutdown(void)
466470
{
467-
int rval;
468-
int cnt = FSD_REPEAT_CNT; /* shutdown repeat counter */
469-
struct timeval start;
470-
long etime;
471-
472-
/* retry sending shutdown command on error */
473-
while ((rval = upscmd("load.off", NULL)) != STAT_INSTCMD_HANDLED && cnt > 0) {
474-
rval = gettimeofday(&start, NULL);
475-
if (rval < 0) {
476-
upslog_with_errno(LOG_ERR, "upscmd: gettimeofday");
477-
}
471+
/* Only implement "shutdown.default"; do not invoke
472+
* general handling of other `sdcommands` here */
478473

479-
/* wait for an increasing time interval before sending shutdown command */
480-
while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt));
481-
upsdebugx(2, "ERROR: load.off failed, wait for %lims, retries left: %d\n", etime, cnt - 1);
482-
cnt--;
483-
}
484-
switch (rval) {
485-
case STAT_INSTCMD_FAILED:
486-
case STAT_INSTCMD_INVALID:
487-
fatalx(EXIT_FAILURE, "shutdown failed");
488-
case STAT_INSTCMD_UNKNOWN:
489-
fatalx(EXIT_FAILURE, "shutdown not supported");
490-
default:
491-
break;
492-
}
493-
upslogx(LOG_INFO, "shutdown command executed");
474+
/*
475+
* WARNING: When using RTU TCP, this driver will probably
476+
* never support shutdowns properly, except on some systems:
477+
* In order to be of any use, the driver should be called
478+
* near the end of the system halt script (or a service
479+
* management framework's equivalent, if any). By that
480+
* time we, in all likelyhood, won't have basic network
481+
* capabilities anymore, so we could never send this
482+
* command to the UPS. This is not an error, but rather
483+
* a limitation (on some platforms) of the interface/media
484+
* used for these devices.
485+
*/
486+
int ret = do_loop_shutdown_commands("shutdown.stayoff", NULL);
487+
if (handling_upsdrv_shutdown > 0)
488+
set_exit_flag(ret == STAT_INSTCMD_HANDLED ? EF_EXIT_SUCCESS : EF_EXIT_FAILURE);
494489
}
495490

496491
/* print driver usage info */
@@ -832,6 +827,43 @@ int upscmd(const char *cmd, const char *arg)
832827
upsdebugx(2, "load.off: addr: 0x%x, data: %d", regs[FSD].xaddr, data);
833828
rval = STAT_INSTCMD_HANDLED;
834829
}
830+
} else if (!strcasecmp(cmd, "shutdown.stayoff")) {
831+
/* FIXME: Which one is this actually -
832+
* "shutdown.stayoff" or "shutdown.return"? */
833+
int cnt = FSD_REPEAT_CNT; /* shutdown repeat counter */
834+
struct timeval start;
835+
long etime;
836+
837+
/* retry sending shutdown command on error */
838+
while ((rval = upscmd("load.off", NULL)) != STAT_INSTCMD_HANDLED && cnt > 0) {
839+
rval = gettimeofday(&start, NULL);
840+
if (rval < 0) {
841+
upslog_with_errno(LOG_ERR, "upscmd: gettimeofday");
842+
}
843+
844+
/* wait for an increasing time interval before sending shutdown command */
845+
while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt));
846+
upsdebugx(2, "ERROR: load.off failed, wait for %lims, retries left: %d\n", etime, cnt - 1);
847+
cnt--;
848+
}
849+
switch (rval) {
850+
case STAT_INSTCMD_FAILED:
851+
case STAT_INSTCMD_INVALID:
852+
upslog_with_errno(LOG_ERR, "instcmd: %s failed", cmd);
853+
if (handling_upsdrv_shutdown > 0)
854+
set_exit_flag(EF_EXIT_FAILURE);
855+
break;
856+
case STAT_INSTCMD_UNKNOWN:
857+
upslog_with_errno(LOG_ERR, "instcmd: %s not supported", cmd);
858+
if (handling_upsdrv_shutdown > 0)
859+
set_exit_flag(EF_EXIT_FAILURE);
860+
break;
861+
default:
862+
upslogx(LOG_INFO, "shutdown command executed");
863+
if (handling_upsdrv_shutdown > 0)
864+
set_exit_flag(EF_EXIT_SUCCESS);
865+
break;
866+
}
835867
} else {
836868
upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmd, arg);
837869
rval = STAT_INSTCMD_UNKNOWN;

drivers/al175.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ typedef uint8_t byte_t;
5252

5353

5454
#define DRIVER_NAME "Eltek AL175/COMLI driver"
55-
#define DRIVER_VERSION "0.15"
55+
#define DRIVER_VERSION "0.16"
5656

5757
/* driver description structure */
5858
upsdrv_info_t upsdrv_info = {
@@ -1267,6 +1267,9 @@ void upsdrv_updateinfo(void)
12671267

12681268
void upsdrv_shutdown(void)
12691269
{
1270+
/* Only implement "shutdown.default"; do not invoke
1271+
* general handling of other `sdcommands` here */
1272+
12701273
/* TODO use TOGGLE_PRS_ONOFF for shutdown */
12711274

12721275
/* tell the UPS to shut down, then return - DO NOT SLEEP HERE */
@@ -1276,7 +1279,8 @@ void upsdrv_shutdown(void)
12761279

12771280
/* replace with a proper shutdown function */
12781281
upslogx(LOG_ERR, "shutdown not supported");
1279-
set_exit_flag(-1);
1282+
if (handling_upsdrv_shutdown > 0)
1283+
set_exit_flag(EF_EXIT_FAILURE);
12801284

12811285
/* you may have to check the line status since the commands
12821286
for toggling power are frequently different for OL vs. OB */

drivers/apc_modbus.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
#else
3939
# define DRIVER_NAME "NUT APC Modbus driver without USB support"
4040
#endif
41-
#define DRIVER_VERSION "0.10"
41+
#define DRIVER_VERSION "0.11"
4242

4343
#if defined NUT_MODBUS_HAS_USB
4444

@@ -1569,7 +1569,31 @@ void upsdrv_updateinfo(void)
15691569

15701570
void upsdrv_shutdown(void)
15711571
{
1572-
modbus_write_register(modbus_ctx, APC_MODBUS_OUTLETCOMMAND_BF_REG, APC_MODBUS_OUTLETCOMMAND_BF_CMD_OUTPUT_SHUTDOWN | APC_MODBUS_OUTLETCOMMAND_BF_TARGET_MAIN_OUTLET_GROUP);
1572+
/* Only implement "shutdown.default"; do not invoke
1573+
* general handling of other `sdcommands` here */
1574+
1575+
/*
1576+
* WARNING: When using RTU TCP, this driver will probably
1577+
* never support shutdowns properly, except on some systems:
1578+
* In order to be of any use, the driver should be called
1579+
* near the end of the system halt script (or a service
1580+
* management framework's equivalent, if any). By that
1581+
* time we, in all likelyhood, won't have basic network
1582+
* capabilities anymore, so we could never send this
1583+
* command to the UPS. This is not an error, but rather
1584+
* a limitation (on some platforms) of the interface/media
1585+
* used for these devices.
1586+
*/
1587+
1588+
/* FIXME: got no direct equivalent in apc_modbus_command_map[]
1589+
* used for instcmd above. Investigate if we can add this
1590+
* combo into that map and name it as an INSTCMD to call by
1591+
* this driver's standard approach.
1592+
*/
1593+
modbus_write_register(modbus_ctx,
1594+
APC_MODBUS_OUTLETCOMMAND_BF_REG,
1595+
APC_MODBUS_OUTLETCOMMAND_BF_CMD_OUTPUT_SHUTDOWN | APC_MODBUS_OUTLETCOMMAND_BF_TARGET_MAIN_OUTLET_GROUP
1596+
);
15731597
}
15741598

15751599
void upsdrv_help(void)

drivers/apcsmart-old.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include "nut_stdint.h"
2626

2727
#define DRIVER_NAME "APC Smart protocol driver (old)"
28-
#define DRIVER_VERSION "2.33"
28+
#define DRIVER_VERSION "2.34"
2929

3030
static upsdrv_info_t table_info = {
3131
"APC command table",
@@ -1063,6 +1063,9 @@ static void upsdrv_shutdown_advanced(long status)
10631063
/* power down the attached load immediately */
10641064
void upsdrv_shutdown(void)
10651065
{
1066+
/* Only implement "shutdown.default"; do not invoke
1067+
* general handling of other `sdcommands` here */
1068+
10661069
char temp[32];
10671070
ssize_t ret;
10681071
long status;

0 commit comments

Comments
 (0)