Skip to content

Commit 4635bec

Browse files
authored
Merge b529f0b into 373241b
2 parents 373241b + b529f0b commit 4635bec

File tree

10 files changed

+204
-16
lines changed

10 files changed

+204
-16
lines changed

NEWS.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,8 @@ relocated into new `shutdown.default` INSTCMD definitions. [#2670]
479479
* custom `distcheck-something` targets did not inherit `DISTCHECK_FLAGS`
480480
properly. [#2541]
481481
* added `status_get()` in NUT driver state API, to check if a status
482-
token string had been set recently, and to avoid duplicate settings.
483-
[PR #2565]
482+
token string had been set recently, and to avoid duplicate settings;
483+
fixed `status_set()` for multi-token arguments. [PR #2565, issue #2708]
484484
* local socket/pipe protocol introduced a `LOGOUT` command for cleaner
485485
disconnection handling. [#2572]
486486
* codebase adapted to the liking of `clang-18` and newer revisions of

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ after_test:
110110
set MSYSTEM=MINGW64
111111
REM Oh the joys of shell scripting with strings passed through CMD:
112112
REM Note: currently Python installation path with MSYS is buggy [#1584]
113-
C:\msys64\usr\bin\bash -lc 'date -u; set -e ; if ! rm -rf ".inst" ; then echo "WARNING: Failed to clean away .inst" ; fi ; PATH="/mingw64/lib/ccache/bin:/mingw64/bin:$PATH" make -s install-win-bundle DESTDIR="`pwd`/.inst/NUT-for-Windows-x86_64-SNAPSHOT-%APPVEYOR_BUILD_VERSION%" ; ln -fs "NUT-for-Windows-x86_64-SNAPSHOT-%APPVEYOR_BUILD_VERSION%" ./.inst/NUT-for-Windows-x86_64-SNAPSHOT ; ( cd .inst/NUT-for-Windows-x86_64-SNAPSHOT ; find . -ls ; ) ; date -u'
113+
C:\msys64\usr\bin\bash -lc 'date -u; set -e ; if ! rm -rf ".inst" ; then echo "WARNING: Failed to clean away .inst" ; fi ; PATH="/mingw64/lib/ccache/bin:/mingw64/bin:$PATH" make -s install-win-bundle DESTDIR="`pwd`/.inst/NUT-for-Windows-x86_64-SNAPSHOT-%APPVEYOR_BUILD_VERSION%" ; rm -rf ./.inst/NUT-for-Windows-x86_64-SNAPSHOT || true ; ln -fs "NUT-for-Windows-x86_64-SNAPSHOT-%APPVEYOR_BUILD_VERSION%" ./.inst/NUT-for-Windows-x86_64-SNAPSHOT ; ( cd .inst/NUT-for-Windows-x86_64-SNAPSHOT ; find . -ls ; ) ; date -u'
114114
cd .inst
115115
7z a ../NUT-for-Windows-x86_64-SNAPSHOT-%APPVEYOR_BUILD_VERSION%.7z NUT*
116116
- cmd: |

docs/new-drivers.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ Possible values for status_set:
247247
BOOST -- UPS is boosting incoming voltage
248248
FSD -- Forced Shutdown (restricted use, see the note below)
249249

250+
Internally, an `ALARM` value would be added (typically as first in the list)
251+
if the `ups.alarm` is currently not empty. For more details, see below in
252+
`alarm_set()` description.
253+
250254
Anything else will not be recognized by the usual clients expecting a
251255
particular NUT standard release. New tokens may appear over time, but
252256
driver developers should coordinate with the nut-upsdev list before creating

drivers/bestfortress.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#endif
3636

3737
#define DRIVER_NAME "Best Fortress UPS driver"
38-
#define DRIVER_VERSION "0.10"
38+
#define DRIVER_VERSION "0.11"
3939

4040
/* driver description structure */
4141
upsdrv_info_t upsdrv_info = {
@@ -401,13 +401,13 @@ void upsdrv_updateinfo(void)
401401

402402
status_init();
403403
if (low_batt)
404-
status_set("LB ");
404+
status_set("LB");
405405
else if (trimming)
406406
status_set("TRIM");
407407
else if (boosting)
408408
status_set("BOOST");
409409
else
410-
status_set(is_online ? (is_off ? "OFF " : "OL ") : "OB ");
410+
status_set(is_online ? (is_off ? "OFF" : "OL") : "OB");
411411

412412
/* setinfo(INFO_STATUS, "%s%s",
413413
* (util < lownorm) ? "BOOST ", "",

drivers/dstate.c

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,11 +1644,16 @@ int status_get(const char *buf)
16441644
s = strstr(status_buf, buf);
16451645
buflen = strlen(buf);
16461646

1647-
/* not found */
1648-
if (!s)
1647+
repeat:
1648+
/* not found or hit end of line */
1649+
if (!s || !*s)
16491650
return 0;
16501651

1651-
offset = status_buf - s;
1652+
offset = s - status_buf;
1653+
#if 0
1654+
upsdebugx(3, "%s: '%s' in '%s': offset=%" PRIuSIZE" buflen=%" PRIuSIZE" s[buflen]='0x%2X'\n",
1655+
__func__, buf, status_buf, offset, buflen, s[buflen]);
1656+
#endif
16521657
if (offset == 0 || status_buf[offset - 1] == ' ') {
16531658
/* We have hit the start of token */
16541659
if (s[buflen] == '\0' || s[buflen] == ' ') {
@@ -1658,12 +1663,46 @@ int status_get(const char *buf)
16581663
}
16591664

16601665
/* buf was a substring of some other token */
1661-
return 0;
1666+
s = strstr(s + 1, buf);
1667+
goto repeat;
16621668
}
16631669

16641670
/* add a status element */
16651671
void status_set(const char *buf)
16661672
{
1673+
#if 0
1674+
upsdebugx(3, "%s: '%s'\n", __func__, buf);
1675+
#endif
1676+
if (strstr(buf, " ")) {
1677+
/* Recurse adding each sub-status one by one (avoid duplicates)
1678+
* We frown upon adding "A FEW TOKENS" at once, but in e.g.
1679+
* snmp-ups subdrivers with a mapping table this is not easily
1680+
* avoidable...
1681+
*/
1682+
char *tmp = xstrdup(buf), *p = tmp, *s = tmp;
1683+
while (*p) {
1684+
if (*p == ' ') {
1685+
*p = '\0';
1686+
if (s != p) {
1687+
/* Only recurse to set non-trivial tokens */
1688+
status_set(s);
1689+
}
1690+
p++;
1691+
s = p; /* Start of new word... or a consecutive space to ignore on next cycle */
1692+
} else {
1693+
p++;
1694+
}
1695+
}
1696+
1697+
if (s != p) {
1698+
/* Last valid token did end with (*p=='\0') */
1699+
status_set(s);
1700+
}
1701+
1702+
free(tmp);
1703+
return;
1704+
}
1705+
16671706
if (ignorelb && !strcasecmp(buf, "LB")) {
16681707
upsdebugx(2, "%s: ignoring LB flag from device", __func__);
16691708
return;

drivers/liebert-gxe.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "ydn23.h"
2525

2626
#define DRIVER_NAME "Liebert GXE Series UPS driver"
27-
#define DRIVER_VERSION "0.02"
27+
#define DRIVER_VERSION "0.03"
2828

2929
#define PROBE_RETRIES 3
3030
#define DEFAULT_STALE_RETRIES 3
@@ -173,9 +173,10 @@ static void upsdrv_updateinfo_onoff(void)
173173
status_set("OB");
174174
else if (pwrval == 0x01)
175175
status_set("OL");
176-
else if (pwrval == 0x02)
177-
status_set("OL BYPASS");
178-
else
176+
else if (pwrval == 0x02) {
177+
status_set("OL");
178+
status_set("BYPASS");
179+
} else
179180
upslogx(LOG_WARNING, "unknown ups state: %x %x",
180181
(unsigned int)pwrval,
181182
(unsigned int)rectval);

drivers/main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ const char *progname = NULL, *upsname = NULL, *device_name = NULL;
4747

4848
/* may be set by the driver to wake up while in dstate_poll_fds */
4949
TYPE_FD extrafd = ERROR_FD;
50-
#ifdef WIN32
50+
#ifndef DRIVERS_MAIN_WITHOUT_MAIN
51+
# ifdef WIN32
5152
static HANDLE mutex = INVALID_HANDLE_VALUE;
52-
#endif
53+
# endif /* WIN32 */
54+
#endif /* DRIVERS_MAIN_WITHOUT_MAIN */
5355

5456
/* Set by INSTCMD to killpower or by running `drivername -k` to
5557
* help differentiate calls into upsdrv_shutdown() and further

tests/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
/cppnit
55
/cppnit.log
66
/cppnit.trs
7+
/driver_methods_utest
8+
/driver_methods_utest.log
9+
/driver_methods_utest.trs
710
/gpiotest
811
/gpiotest.log
912
/gpiotest.trs

tests/Makefile.am

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ endif !WITH_GPIO
116116
CLEANFILES += generic_gpio_libgpiod.c generic_gpio_common.c
117117
EXTRA_DIST += generic_gpio_utest.h generic_gpio_test.txt
118118

119+
TESTS += driver_methods_utest
120+
driver_methods_utest_SOURCES = driver_methods_utest.c
121+
driver_methods_utest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la
122+
driver_methods_utest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1
123+
119124
# Make sure out-of-dir dependencies exist (especially when dev-building parts):
120125
$(top_builddir)/drivers/libdummy_mockdrv.la \
121126
$(top_builddir)/common/libnutconf.la \

tests/driver_methods_utest.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/* driver_methods_utest.c - NUT driver code test tool
2+
*
3+
* Copyright (C)
4+
* 2025 Jim Klimov <[email protected]>
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20+
*
21+
*/
22+
23+
#include "config.h"
24+
#include "main.h"
25+
#include "dstate.h"
26+
#include "attribute.h"
27+
#include "nut_stdint.h"
28+
29+
/* driver version */
30+
#define DRIVER_NAME "Mock driver for unit tests"
31+
#define DRIVER_VERSION "0.01"
32+
33+
/* driver description structure */
34+
upsdrv_info_t upsdrv_info = {
35+
DRIVER_NAME,
36+
DRIVER_VERSION,
37+
"Jim Klimov <[email protected]>",
38+
DRV_EXPERIMENTAL,
39+
{ NULL }
40+
};
41+
42+
static int cases_passed = 0;
43+
static int cases_failed = 0;
44+
45+
static char * pass_fail[2] = {"pass", "fail"};
46+
47+
void upsdrv_cleanup(void) {}
48+
void upsdrv_shutdown(void) {}
49+
50+
static void report_pass(void) {
51+
printf("%s", pass_fail[0]);
52+
cases_passed++;
53+
}
54+
55+
static void report_fail(void) {
56+
printf("%s", pass_fail[1]);
57+
cases_failed++;
58+
}
59+
60+
static int report_0_means_pass(int i) {
61+
if (i == 0) {
62+
report_pass();
63+
} else {
64+
report_fail();
65+
}
66+
return i;
67+
}
68+
int main(int argc, char **argv) {
69+
const char *valueStr = NULL;
70+
71+
NUT_UNUSED_VARIABLE(argc);
72+
NUT_UNUSED_VARIABLE(argv);
73+
74+
cases_passed = 0;
75+
cases_failed = 0;
76+
77+
/* test case #1 */
78+
status_init();
79+
nut_debug_level = 6;
80+
status_set(" OL ");
81+
status_set("OL BOOST");
82+
status_set("OB ");
83+
status_set(" BOOST");
84+
status_commit();
85+
valueStr = dstate_getinfo("ups.status");
86+
nut_debug_level = 0;
87+
report_0_means_pass(strcmp(valueStr, "OL BOOST OB"));
88+
printf(" test for ups.status: '%s'; any duplicates?\n", NUT_STRARG(valueStr));
89+
90+
/* test case #2, build on top of #1 */
91+
alarm_init();
92+
alarm_set("Test alarm 1");
93+
alarm_set("Test alarm 2");
94+
alarm_set("Test alarm 1");
95+
alarm_commit();
96+
/* Note: normally we re-init and re-set the values */
97+
status_commit();
98+
valueStr = dstate_getinfo("ups.status");
99+
report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB"));
100+
printf(" test for ups.status: '%s'; got alarm?\n", NUT_STRARG(valueStr));
101+
102+
/* test case #3, build on top of #2 */
103+
valueStr = dstate_getinfo("ups.alarm");
104+
/* NOTE: no dedup here! */
105+
report_0_means_pass(strcmp(valueStr, "Test alarm 1 Test alarm 2 Test alarm 1"));
106+
printf(" test for ups.alarm: '%s'; got 3 alarms?\n", NUT_STRARG(valueStr));
107+
108+
/* test case #4, build on top of #1 and #2 */
109+
/* Note: normally we re-init and re-set the values */
110+
status_set("BOO");
111+
status_set("BOO");
112+
status_set("OST");
113+
status_set("OST");
114+
status_set("OOS");
115+
status_set("OOS");
116+
status_commit();
117+
valueStr = dstate_getinfo("ups.status");
118+
nut_debug_level = 0;
119+
report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB BOO OST OOS"));
120+
printf(" test for ups.status: '%s'; any duplicates?\n", NUT_STRARG(valueStr));
121+
122+
/* finish */
123+
printf("test_rules completed. Total cases %d, passed %d, failed %d\n",
124+
cases_passed+cases_failed, cases_passed, cases_failed);
125+
126+
dstate_free();
127+
upsdrv_cleanup();
128+
129+
/* Return 0 (exit-code OK, boolean false) if no tests failed and some ran */
130+
if ( (cases_failed == 0) && (cases_passed > 0) )
131+
return 0;
132+
133+
return 1;
134+
}

0 commit comments

Comments
 (0)