Skip to content

Commit 6b875cf

Browse files
authored
Merge 9a59218 into dfe6062
2 parents dfe6062 + 9a59218 commit 6b875cf

9 files changed

Lines changed: 124 additions & 4 deletions

File tree

‎NEWS.adoc‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,16 @@ https://github.com/networkupstools/nut/milestone/9
6868
for this name": the way to extract IP address string was not portable
6969
and misfired on some platforms, and the way to print had a theoretical
7070
potential for buffer overflow. [#2915]
71-
72-
- `usbhid-ups` updates:
71+
* sanity-check `NUMBER` values that they actually resolve as a `double`
72+
or `long int`; report an un-flagged type as `STRING` if not (previously
73+
blindly defaulted to `NUMBER` always). Debug-print presence of the
74+
`IMMUTABLE` flag in `netget.c::get_type()`, and actually consider it
75+
in the `netset.c::set_var()` method to abort early. Socket protocol
76+
used between a driver and data server to exchange device state was
77+
updated to pass `IMMUTABLE` flag, but this change should not impact
78+
the NUT network protocol as published in RFC 9271. [issue #266, PR #2549]
79+
80+
- `usbhid-ups` driver updates:
7381
* The `cps-hid` subdriver's existing mechanism for fixing broken report
7482
descriptors was extended to cover a newly reported case of nominal UPS
7583
power being incorrectly reported due to an unrealistically low maximum

‎UPGRADING.adoc‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ Changes from 2.8.3 to 2.8.4
2626

2727
- PLANNED: Keep track of any further API clean-up?
2828
29+
- The `netset.c::set_var()` was updated to consider the `IMMUTABLE` flag on
30+
values to reject writing into them quickly. This is currently expected
31+
to only impact `override.*` values in vanilla NUT codebase, and should
32+
not impact the NUT network protocol as published in RFC 9271 (only the
33+
socket protocol used between a driver and data server to exchange device
34+
state). [issue #266, PR #2549]
35+
36+
- The `netset.c::get_type()` was updated to sanity-check `NUMBER`-flagged
37+
values that the strings actually resolve into `double` or `long int`
38+
values. Some codebase does not flag its values properly and warnings
39+
can be emitted (to be reported for upstream NUT to fix these use-cases).
40+
[issue #266, PR #2549]
41+
2942
Changes from 2.8.2 to 2.8.3
3043
---------------------------
3144

‎common/state.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,11 @@ void state_setflags(st_tree_t *root, const char *var, size_t numflags, char **fl
536536

537537
for (i = 0; i < numflags; i++) {
538538

539+
if (!strcasecmp(flag[i], "IMMUTABLE")) {
540+
sttmp->flags |= ST_FLAG_IMMUTABLE;
541+
continue;
542+
}
543+
539544
if (!strcasecmp(flag[i], "RW")) {
540545
sttmp->flags |= ST_FLAG_RW;
541546
continue;

‎docs/net-protocol.txt‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ exponents, and comma for thousands separator are forbidden.
156156
For example: "1200.20" is valid, while "1,200.20" and "1200,20" and "1.2e4"
157157
are invalid.
158158

159+
Also note that internally NUT programs can flag variables as 'IMMUTABLE':
160+
a value of such variable can not be changed after it was initially set
161+
(this is used e.g. for "override" settings where the device is known to
162+
provide bogus readings). The flag is not currently exposed with `GET`
163+
commands, but can be a reason for a `SET` to fail.
159164

160165
This replaces the old "VARTYPE" command.
161166

‎docs/nut.dict‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
personal_ws-1.1 en 3470 utf-8
1+
personal_ws-1.1 en 3472 utf-8
22
AAC
33
AAS
44
ABI
@@ -2568,8 +2568,10 @@ nde
25682568
nds
25692569
netcat
25702570
netclient
2571+
netget
25712572
netmask
25722573
netserver
2574+
netset
25732575
netsh
25742576
netsnmp
25752577
netvision

‎docs/sock-protocol.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ flags are supported. Also note that they are not crammed together in
112112

113113
This also replaces any previous flags for a given variable.
114114

115-
Currently supported flags include `RW`, `STRING` and `NUMBER`
115+
Currently supported flags include `IMMUTABLE`, `RW`, `STRING` and `NUMBER`
116116
(detailed in the NUT Network Protocol documentation); unrecognized values
117117
are quietly ignored.
118118

‎drivers/dstate.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,9 @@ static int st_tree_dump_conn_one_node(st_tree_t *node, conn_t *conn)
646646
/* build the list */
647647
snprintf(flist, sizeof(flist), "%s", node->var);
648648

649+
if (node->flags & ST_FLAG_IMMUTABLE) {
650+
snprintfcat(flist, sizeof(flist), " IMMUTABLE");
651+
}
649652
if (node->flags & ST_FLAG_RW) {
650653
snprintfcat(flist, sizeof(flist), " RW");
651654
}

‎server/netget.c‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "state.h"
2525
#include "desc.h"
2626
#include "neterr.h"
27+
#include "nut_stdint.h"
2728

2829
#include "netget.h"
2930

@@ -138,6 +139,19 @@ static void get_type(nut_ctype_t *client, const char *upsname, const char *var)
138139

139140
snprintf(buf, sizeof(buf), "TYPE %s %s", upsname, var);
140141

142+
if (node->flags & ST_FLAG_IMMUTABLE) {
143+
#if defined DEBUG && DEBUG
144+
/* Properly exposing this needs also an update to
145+
* docs/net-protocol.txt (promote the paragraph
146+
* provided as a note currently) and to the NUT RFC
147+
* https://www.rfc-editor.org/info/rfc9271
148+
*/
149+
snprintfcat(buf, sizeof(buf), " IMMUTABLE");
150+
#endif
151+
upsdebugx(3, "%s: UPS[%s] variable %s is IMMUTABLE",
152+
__func__, upsname, var);
153+
}
154+
141155
if (node->flags & ST_FLAG_RW)
142156
snprintfcat(buf, sizeof(buf), " RW");
143157

@@ -162,6 +176,66 @@ static void get_type(nut_ctype_t *client, const char *upsname, const char *var)
162176
__func__, upsname, var);
163177
}
164178

179+
/* Sanity-check current contents */
180+
if (node->val && *(node->val)) {
181+
double d;
182+
long l;
183+
int ok = 1;
184+
size_t len = strlen(node->val);
185+
186+
errno = 0;
187+
if (!str_to_double_strict(node->val, &d, 10)) {
188+
upsdebugx(3, "%s: UPS[%s] variable %s is flagged a NUMBER but not (exclusively) a double: %s",
189+
__func__, upsname, var, node->val);
190+
upsdebug_with_errno(4, "%s: val=%f len=%" PRIuSIZE,
191+
__func__, d, len);
192+
ok = 0;
193+
}
194+
195+
if (!ok) {
196+
/* did not parse as a float... range issues or NaN? */
197+
errno = 0;
198+
ok = 1;
199+
if (!str_to_long_strict(node->val, &l, 10)) {
200+
upsdebugx(3, "%s: UPS[%s] variable %s is flagged a NUMBER but not (exclusively) a long int: %s",
201+
__func__, upsname, var, node->val);
202+
upsdebug_with_errno(4, "%s: val=%ld len=%" PRIuSIZE,
203+
__func__, l, len);
204+
ok = 0;
205+
}
206+
}
207+
208+
#if defined DEBUG && DEBUG
209+
/* Need to figure out an "aux" value here (length of current
210+
* string at least?) and propagate the flag into where netset
211+
* would see it. Maybe this sanity-check should move into the
212+
* core state.c logic, so dstate setting would already remember
213+
* the defaulted flag (and maybe set another to clarify it is
214+
* a guess). Currently that code does not concern itself with
215+
* sanity-checks, it seems!
216+
*/
217+
if (!ok && !(node->flags & ST_FLAG_NUMBER)) {
218+
upsdebugx(3, "%s: assuming UPS[%s] variable %s is a STRING after all, by contents; "
219+
"value='%s' len='%" PRIuSIZE "' aux='%ld'",
220+
__func__, upsname, var, node->val, len, node->aux);
221+
222+
sendback(client, "%s STRING:%ld\n", buf, node->aux);
223+
return;
224+
}
225+
#endif
226+
227+
if (!ok) {
228+
/* FIXME: Should this return an error?
229+
* Value was explicitly flagged as a NUMBER but is not by content.
230+
* Note that state_addinfo() does not sanity-check; but
231+
* netset.c::set_var() does though (for protocol clients).
232+
*/
233+
upslogx(LOG_WARNING, "%s: UPS[%s] variable %s is flagged as a NUMBER but is not "
234+
"by contents (please report as a bug to NUT project)): %s",
235+
__func__, upsname, var, node->val);
236+
}
237+
}
238+
165239
sendback(client, "%s NUMBER\n", buf);
166240
}
167241

‎server/netset.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var,
152152
}
153153
}
154154

155+
/* FIXME: Consider null/non-null values for strings
156+
* See note on sstate_getnode() idea above.
157+
*/
158+
if (sstate_getflags(ups, var) & ST_FLAG_IMMUTABLE) {
159+
upsdebugx(3, "%s: UPS [%s]: value of %s is already set and immutable",
160+
__func__, ups->name, var);
161+
send_err(client, NUT_ERR_READONLY);
162+
return;
163+
}
164+
155165
/* must be OK now */
156166

157167
snprintf(cmd, sizeof(cmd), "SET %s \"%s\"",

0 commit comments

Comments
 (0)