Skip to content

Commit 8f4dba5

Browse files
committed
drivers/main.{c,h}, docs/man/ups.conf.txt, conf/ups.conf.sample, NEWS.adoc: introduce reconnect_max_tries setting for NUT drivers [#3541]
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
1 parent 28e3bf0 commit 8f4dba5

5 files changed

Lines changed: 143 additions & 1 deletion

File tree

NEWS.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ https://github.com/networkupstools/nut/milestone/13
156156
chunks populated only partially with bytes we intended. These buffers are
157157
now more diligently pre-zeroed as their siblings were in other code paths,
158158
to avoid sending host stack garbage to a device. [#3529]
159+
* Introduced a `reconnect_max_tries` setting for NUT drivers, so they can
160+
be configured to exit after the specified number of reconnection attempts
161+
(so that the OS service management facility can completely recycle the
162+
driver program). [#3541]
159163

160164
- NUT client libraries:
161165
* Complete support for actions documented in `docs/net-protocol.txt`

conf/ups.conf.sample

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ maxretry = 3
112112
#
113113
# The default is 75 seconds.
114114
#
115+
# reconnect_max_tries: OPTIONAL. This can be set as a global variable above
116+
# your first UPS definition and it can also be set in a
117+
# UPS section. If a driver loses connection to the device,
118+
# try reconnecting for the specified number of iterations and
119+
# exit (so some OS service management facility or an alerted
120+
# sysadmin can restart the driver program "from scratch").
121+
# A zero value (unreasonable but possible) means to exit as
122+
# soon as the device connection was lost.
123+
# A negative value (default) means to try reconnecting
124+
# indefinitely (e.g. data cable fell out, or the data path
125+
# to a networked UPS was lost for a significant time).
126+
#
115127
# debug_min: OPTIONAL. Specify a minimum debug level for all driver daemons
116128
# and for the upsdrvctl tool (when specified at global level),
117129
# or for this driver daemon (when specified in a driver section),

docs/man/ups.conf.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,19 @@ its own in `upsd.conf`.
100100
+
101101
Environment variable `NUT_STATEPATH` set by caller can override this setting.
102102

103+
*reconnect_max_tries*::
104+
105+
Optional. If a driver loses connection to the device, try reconnecting for
106+
the specified number of iterations and exit (so some OS service management
107+
facility or an alerted sysadmin can restart the driver program "from scratch").
108+
+
109+
A zero value (unreasonable but possible) means to exit as soon as the device
110+
connection was lost.
111+
+
112+
A negative value (default) means to try reconnecting indefinitely (e.g. data
113+
cable fell out, or the data path to a networked UPS was lost for a significant
114+
time).
115+
103116
*maxstartdelay*::
104117

105118
Optional. Same as the UPS field of the same name, but this is the
@@ -340,6 +353,11 @@ They would not be actively killed by `upsdrvctl` after this timeout expires.
340353
+
341354
The default is 75 seconds.
342355

356+
*reconnect_max_tries*::
357+
Optional. This can be set as a global variable above your first UPS
358+
definition and it can also be set in a UPS section. See explanation
359+
above, in the global section.
360+
343361
*maxretry*::
344362
Optional. This can be set as a global variable above your first UPS
345363
definition and it can also be set in a UPS section. See explanation

drivers/main.c

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ vartab_t *vartab_h = NULL;
101101
*/
102102
time_t poll_interval = 2;
103103
static char *chroot_path = NULL, *user = NULL, *group = NULL;
104-
static int user_from_cmdline = 0, group_from_cmdline = 0;
104+
static int user_from_cmdline = 0, group_from_cmdline = 0,
105+
reconnect_max_tries = -1, reconnect_count = 0;
105106

106107
/* signal handling */
107108
int exit_flag = 0;
@@ -1397,6 +1398,18 @@ static int main_arg(char *var, char *val)
13971398
return 1; /* handled */
13981399
}
13991400

1401+
/* Allow per-driver overrides of the global setting
1402+
* and allow to reload this, why not. */
1403+
if (!strcmp(var, "reconnect_max_tries")) {
1404+
int intval = -1;
1405+
if ( str_to_int (val, &intval, 10) ) {
1406+
reconnect_max_tries = intval;
1407+
reconnect_count = 0;
1408+
} else {
1409+
upslogx(LOG_INFO, "WARNING : Invalid reconnect_max_tries value found in ups.conf global settings");
1410+
}
1411+
}
1412+
14001413
/* only for upsdrvctl - ignored here */
14011414
if (!strcmp(var, "sdorder"))
14021415
return 1; /* handled */
@@ -1571,6 +1584,18 @@ static void do_global_args(const char *var, const char *val)
15711584
return;
15721585
}
15731586

1587+
if (!strcmp(var, "reconnect_max_tries")) {
1588+
int intval = -1;
1589+
if ( str_to_int (val, &intval, 10) ) {
1590+
reconnect_max_tries = intval;
1591+
reconnect_count = 0;
1592+
} else {
1593+
upslogx(LOG_INFO, "WARNING : Invalid reconnect_max_tries value found in ups.conf global settings");
1594+
}
1595+
1596+
return;
1597+
}
1598+
15741599
/* Allow to specify its minimal debugging level for all drivers -
15751600
* admins can set more with command-line args, but can't set
15761601
* less without changing config. Should help debug of services.
@@ -2169,6 +2194,77 @@ void setup_signals(void)
21692194
}
21702195
#endif /* !WIN32*/
21712196

2197+
/* Called by a driver to enter/continue a reconnection loop (trying=1,
2198+
* with certain configuration can activate exit_flag) or to end it (0).
2199+
* Sets the driver.state to "reconnect.trying" or "quiet" respectively.
2200+
* Returns how many attempts remain before driver exits (-1 if it won't).
2201+
*/
2202+
int reconnect_trying(int trying)
2203+
{
2204+
if (!trying) {
2205+
if (reconnect_count > 0)
2206+
upslogx(LOG_INFO, "Driver reconnected "
2207+
"to the device [%s] after %d attempts",
2208+
upsname, reconnect_count);
2209+
reconnect_count = 0;
2210+
dstate_setinfo("driver.state", "quiet");
2211+
return -1;
2212+
}
2213+
2214+
if (reconnect_max_tries == 0) {
2215+
upslogx(LOG_WARNING, "Driver lost connection "
2216+
"to the device [%s] and will exit immediately",
2217+
upsname);
2218+
exit_flag = 1;
2219+
return 0;
2220+
}
2221+
2222+
dstate_setinfo("driver.state", "reconnect.trying");
2223+
2224+
if (reconnect_count == 0) {
2225+
if (reconnect_max_tries < 0) {
2226+
upslogx(LOG_INFO, "Driver reconnecting "
2227+
"to the device [%s], will try "
2228+
"indefinitely",
2229+
upsname);
2230+
} else {
2231+
upslogx(LOG_INFO, "Driver reconnecting "
2232+
"to the device [%s], will try for "
2233+
"max %d attempts, then will exit",
2234+
upsname, reconnect_max_tries);
2235+
}
2236+
}
2237+
2238+
if (reconnect_count < INT_MAX) {
2239+
reconnect_count++;
2240+
} else {
2241+
upsdebugx(1, "%s: reconnect counter overflowed", __func__);
2242+
if (reconnect_max_tries > 0) {
2243+
upslogx(LOG_WARNING, "Driver lost connection "
2244+
"to the device [%s] and reconnect "
2245+
"counter overflowed, will exit immediately",
2246+
upsname);
2247+
exit_flag = 1;
2248+
return 0;
2249+
}
2250+
}
2251+
2252+
if (reconnect_max_tries > 0) {
2253+
if (reconnect_max_tries < reconnect_count) {
2254+
upslogx(LOG_WARNING, "Driver lost connection "
2255+
"to the device [%s] and tried to "
2256+
"reconnect for %d times, "
2257+
"now will exit as configured",
2258+
upsname, reconnect_count);
2259+
exit_flag = 1;
2260+
return 0;
2261+
}
2262+
return reconnect_max_tries - reconnect_count + 1;
2263+
}
2264+
2265+
return -1;
2266+
}
2267+
21722268
/* This source file is used in some unit tests to mock realistic driver
21732269
* behavior - using a production driver skeleton, but their own main().
21742270
* It is called from main-stub.c in shared-mode builds.
@@ -3301,6 +3397,11 @@ int main(int argc, char **argv)
33013397
gettimeofday(&timeout, NULL);
33023398
timeout.tv_sec += poll_interval;
33033399

3400+
if (reconnect_count > 0) {
3401+
dstate_setinfo("driver.reconnect_count", "%d", reconnect_count);
3402+
dstate_setinfo("driver.reconnect_max_tries", "%d", reconnect_max_tries);
3403+
}
3404+
33043405
/* Drivers can now choose to track changes of current battery
33053406
* charge vs. its previous value to e.g. report "CHRG" status.
33063407
* TODO: Eventually provide a common `runtimecal` fallback to all?

drivers/main.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ typedef struct vartab_s {
112112
void addvar(int vartype, const char *name, const char *desc);
113113
void addvar_reloadable(int vartype, const char *name, const char *desc);
114114

115+
/* Called by a driver to enter/continue a reconnection loop (trying=1,
116+
* with certain configuration can activate exit_flag) or to end it (0).
117+
* Sets the driver.state to "reconnect.trying" or "quiet" respectively.
118+
* Returns how many attempts remain before driver exits (-1 if it won't).
119+
*/
120+
int reconnect_trying(int trying);
121+
115122
/* Several helpers for driver configuration reloading follow:
116123
* * testval_reloadable() checks if we are currently reloading (or initially
117124
* loading) the configuration, and if strings oldval==newval or not,

0 commit comments

Comments
 (0)