Skip to content

Commit 904fe55

Browse files
authored
Merge 7755827 into c81b489
2 parents c81b489 + 7755827 commit 904fe55

4 files changed

Lines changed: 172 additions & 54 deletions

File tree

NEWS.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,20 @@ https://github.com/networkupstools/nut/milestone/9
175175
[issue #2708]
176176

177177
- `snmp-ups` driver updates:
178+
* Added support for "fun"/"nuf" methods called from mapping tables to
179+
report back to the driver that an argument value was not supported,
180+
so `setvar()` or `instcmd()` can not proceed safely and should return
181+
`STAT_SET_CONVERSION_FAILED` or `STAT_INSTCMD_CONVERSION_FAILED`. [#3017]
178182
* Fixed `ups.test.date` to be semi-static in `apc-mib` mapping, so it
179183
would be queried more than once per driver up-time. [issue #3011]
180184
* Fixed debug-logging around `SU_FLAG_STATIC` entries to clarify when
181185
they get skipped. [issue #3011]
182186

183187
- `usbhid-ups` driver updates:
188+
* Added support for "fun"/"nuf" methods called from mapping tables to
189+
report back to the driver that an argument value was not supported,
190+
so `setvar()` or `instcmd()` can not proceed safely and should return
191+
`STAT_SET_CONVERSION_FAILED` or `STAT_INSTCMD_CONVERSION_FAILED`. [#3017]
184192
* The `cps-hid` subdriver's existing mechanism for fixing broken report
185193
descriptors was extended to cover a newly reported case of nominal UPS
186194
power being incorrectly reported due to an unrealistically low maximum

drivers/snmp-ups.c

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static const char *mibname;
177177
static const char *mibvers;
178178

179179
#define DRIVER_NAME "Generic SNMP UPS driver"
180-
#define DRIVER_VERSION "1.36"
180+
#define DRIVER_VERSION "1.37"
181181

182182
/* driver description structure */
183183
upsdrv_info_t upsdrv_info = {
@@ -2123,7 +2123,9 @@ bool_t load_mib2nut(const char *mib)
21232123
return FALSE;
21242124
}
21252125

2126-
/* find the OID value matching that INFO_* value */
2126+
/* find the OID value matching that INFO_* value
2127+
* Return -1 and errno==EINVAL for unsupported inputs.
2128+
*/
21272129
long su_find_valinfo(info_lkp_t *oid2info, const char* value)
21282130
{
21292131
info_lkp_t *info_lkp;
@@ -2135,14 +2137,19 @@ long su_find_valinfo(info_lkp_t *oid2info, const char* value)
21352137
upsdebugx(1, "%s: found %s (value: %s)",
21362138
__func__, info_lkp->info_value, value);
21372139

2140+
errno = 0;
21382141
return info_lkp->oid_value;
21392142
}
21402143
}
2144+
21412145
upsdebugx(1, "%s: no matching INFO_* value for this OID value (%s)", __func__, value);
2146+
errno = EINVAL;
21422147
return -1;
21432148
}
21442149

2145-
/* String reformatting function */
2150+
/* String reformatting function.
2151+
* Return NULL and errno==EINVAL for unsupported inputs.
2152+
*/
21462153
const char *su_find_strval(info_lkp_t *oid2info, void *value)
21472154
{
21482155
#if WITH_SNMP_LKP_FUN
@@ -2151,19 +2158,27 @@ const char *su_find_strval(info_lkp_t *oid2info, void *value)
21512158
const char *retvalue;
21522159

21532160
upsdebugx(2, "%s: using generic lookup function (string reformatting)", __func__);
2161+
errno = 0;
21542162
retvalue = oid2info->fun_vp2s(value);
2155-
upsdebugx(2, "%s: got value '%s'", __func__, retvalue);
2163+
upsdebugx(2, "%s: got value '%s'%s",
2164+
__func__, retvalue,
2165+
(errno == EINVAL ? ", invalid input" : "")
2166+
);
21562167
return retvalue;
21572168
}
21582169
upsdebugx(1, "%s: no result value for this OID string value (%s)", __func__, (char*)value);
21592170
#else
21602171
NUT_UNUSED_VARIABLE(oid2info);
21612172
upsdebugx(1, "%s: no mapping function for this OID string value (%s)", __func__, (char*)value);
21622173
#endif /* WITH_SNMP_LKP_FUN */
2174+
2175+
errno = EINVAL;
21632176
return NULL;
21642177
}
21652178

2166-
/* find the INFO_* value matching that OID numeric (long) value */
2179+
/* Find the INFO_* value matching that OID numeric (long) value.
2180+
* Return NULL and errno==EINVAL for unsupported inputs.
2181+
*/
21672182
const char *su_find_infoval(info_lkp_t *oid2info, void *raw_value)
21682183
{
21692184
info_lkp_t *info_lkp;
@@ -2175,8 +2190,12 @@ const char *su_find_infoval(info_lkp_t *oid2info, void *raw_value)
21752190
const char *retvalue;
21762191

21772192
upsdebugx(2, "%s: using generic lookup function", __func__);
2193+
errno = 0;
21782194
retvalue = oid2info->fun_vp2s(raw_value);
2179-
upsdebugx(2, "%s: got value '%s'", __func__, retvalue);
2195+
upsdebugx(2, "%s: got value '%s'%s",
2196+
__func__, retvalue,
2197+
(errno == EINVAL ? ", invalid input" : "")
2198+
);
21802199
return retvalue;
21812200
}
21822201
#endif /* WITH_SNMP_LKP_FUN */
@@ -2189,10 +2208,13 @@ const char *su_find_infoval(info_lkp_t *oid2info, void *raw_value)
21892208
upsdebugx(1, "%s: found %s (value: %ld)",
21902209
__func__, info_lkp->info_value, value);
21912210

2211+
errno = 0;
21922212
return info_lkp->info_value;
21932213
}
21942214
}
2215+
21952216
upsdebugx(1, "%s: no matching INFO_* value for this OID value (%ld)", __func__, value);
2217+
errno = EINVAL;
21962218
return NULL;
21972219
}
21982220

@@ -2838,6 +2860,7 @@ bool_t daisychain_init(void)
28382860
{
28392861
#if WITH_SNMP_LKP_FUN
28402862
devices_count = -1;
2863+
errno = 0;
28412864
/* First test if we have a generic lookup function
28422865
* FIXME: Check if the field type is a string?
28432866
*/
@@ -2849,11 +2872,14 @@ bool_t daisychain_init(void)
28492872
upsdebugx(2, "%s: using generic string-to-long lookup function", __func__);
28502873
if (TRUE == nut_snmp_get_str(su_info_p->OID, buf, sizeof(buf), su_info_p->oid2info)) {
28512874
devices_count = su_info_p->oid2info->nuf_s2l(buf);
2852-
upsdebugx(2, "%s: got value '%ld'", __func__, devices_count);
2875+
upsdebugx(2, "%s: got value '%ld'%s",
2876+
__func__, devices_count,
2877+
(errno == EINVAL ? ", invalid input" : "")
2878+
);
28532879
}
28542880
}
28552881

2856-
if (devices_count == -1) {
2882+
if (devices_count == -1 || errno == EINVAL) {
28572883
#endif /* WITH_SNMP_LKP_FUN */
28582884

28592885
if (nut_snmp_get_int(su_info_p->OID, &devices_count) == TRUE) {
@@ -3659,10 +3685,13 @@ bool_t su_ups_get(snmp_info_t *su_info_p)
36593685
* @varname: name of variable or command to set the OID from
36603686
* @val: value for settings, NULL for commands
36613687
3662-
* Returns
3663-
* STAT_SET_HANDLED if OK,
3664-
* STAT_SET_INVALID or STAT_SET_UNKNOWN if the command / setting is not supported
3665-
* STAT_SET_FAILED otherwise
3688+
* Returns respectively (for instcmd or setvar activity):
3689+
* STAT_INSTCMD_HANDLED or STAT_SET_HANDLED if OK,
3690+
* STAT_*_CONVERSION_FAILED if the value was invalid
3691+
* (not a number when expected one,
3692+
* not a key in mapping table when used)
3693+
* STAT_*_INVALID or STAT_*_UNKNOWN if the command / setting is not supported
3694+
* STAT_*_FAILED otherwise
36663695
*/
36673696
static int su_setOID(int mode, const char *varname, const char *val)
36683697
{
@@ -3755,7 +3784,7 @@ static int su_setOID(int mode, const char *varname, const char *val)
37553784
upsdebugx(2, "daisychain %s for device.0 are not yet supported!",
37563785
(mode==SU_MODE_INSTCMD)?"command":"setting");
37573786
free(tmp_varname);
3758-
return STAT_SET_INVALID;
3787+
return (mode==SU_MODE_INSTCMD ? STAT_INSTCMD_INVALID : STAT_SET_INVALID);
37593788
}
37603789

37613790
/* Check if it is outlet / outlet.group, or standard variable */
@@ -3822,7 +3851,7 @@ static int su_setOID(int mode, const char *varname, const char *val)
38223851
/* out of bound item number */
38233852
upsdebugx(2, "%s: item is out of bound (%i / %i)",
38243853
__func__, item_number, total_items);
3825-
return STAT_SET_INVALID;
3854+
return (mode==SU_MODE_INSTCMD ? STAT_INSTCMD_INVALID : STAT_SET_INVALID);
38263855
}
38273856
/* find back the item template */
38283857
item_varname = (char *)xmalloc(SU_INFOSIZE);
@@ -3891,8 +3920,9 @@ static int su_setOID(int mode, const char *varname, const char *val)
38913920
tmp_info_p->OID, "%i", item_number);
38923921
}
38933922
}
3894-
/* else, don't return STAT_SET_INVALID for mode==SU_MODE_SETVAR since we
3895-
* can be setting a server side variable! */
3923+
/* else, don't return STAT_SET_INVALID for mode==SU_MODE_SETVAR
3924+
* since we can be setting a server side variable - but
3925+
* note this consideration does not apply to instcmd's! */
38963926
else {
38973927
if (mode==SU_MODE_INSTCMD) {
38983928
free_info(su_info_p);
@@ -3917,15 +3947,15 @@ static int su_setOID(int mode, const char *varname, const char *val)
39173947
if (tmp_varname != NULL)
39183948
free(tmp_varname);
39193949

3920-
return STAT_SET_UNKNOWN;
3950+
return (mode==SU_MODE_INSTCMD ? STAT_INSTCMD_UNKNOWN : STAT_SET_UNKNOWN);
39213951
}
39223952

39233953
/* set value into the device, using the provided one, or the default one otherwise */
39243954
if (mode==SU_MODE_INSTCMD) {
39253955
/* Sanity check: commands should either have a value or a default */
39263956
if ( (val == NULL) && (su_info_p->dfl == NULL) ) {
39273957
upsdebugx(1, "%s: cannot execute command '%s': a provided or default value is needed!", __func__, varname);
3928-
return STAT_SET_INVALID;
3958+
return STAT_INSTCMD_INVALID;
39293959
}
39303960
upslog_INSTCMD_POWERSTATE_CHECKED(varname, val);
39313961
}
@@ -3937,19 +3967,24 @@ static int su_setOID(int mode, const char *varname, const char *val)
39373967
if (mode==SU_MODE_INSTCMD) {
39383968
if ( !str_to_long(val ? val : su_info_p->dfl, &value, 10) ) {
39393969
upsdebugx(1, "%s: cannot execute command '%s': value is not a number!", __func__, varname);
3940-
return STAT_SET_INVALID;
3970+
return STAT_INSTCMD_CONVERSION_FAILED;
39413971
}
39423972
}
39433973
else {
39443974
/* non string data may imply a value lookup */
39453975
if (su_info_p->oid2info) {
39463976
value = su_find_valinfo(su_info_p->oid2info, val ? val : su_info_p->dfl);
3977+
if (value == -1 && errno == EINVAL) {
3978+
upsdebugx(1, "%s: cannot set '%s': value %s is not supported by lookup mapping!",
3979+
__func__, varname, NUT_STRARG(val ? val : su_info_p->dfl));
3980+
return STAT_SET_CONVERSION_FAILED;
3981+
}
39473982
}
39483983
else {
39493984
/* Convert value and apply multiplier */
39503985
if ( !str_to_long(val, &value, 10) ) {
39513986
upsdebugx(1, "%s: cannot set '%s': value is not a number!", __func__, varname);
3952-
return STAT_SET_INVALID;
3987+
return STAT_SET_CONVERSION_FAILED;
39533988
}
39543989
value = (long)((double)value / su_info_p->info_len);
39553990
}
@@ -3965,23 +4000,26 @@ static int su_setOID(int mode, const char *varname, const char *val)
39654000

39664001
/* Process result */
39674002
if (status == FALSE) {
3968-
if (mode==SU_MODE_INSTCMD)
4003+
if (mode==SU_MODE_INSTCMD) {
39694004
upsdebugx(1, "%s: cannot execute command '%s'", __func__, varname);
3970-
else
4005+
retval = STAT_INSTCMD_FAILED;
4006+
}
4007+
else {
39714008
upsdebugx(1, "%s: cannot set value %s on OID %s", __func__, val, su_info_p->OID);
3972-
3973-
retval = STAT_SET_FAILED;
4009+
retval = STAT_SET_FAILED;
4010+
}
39744011
}
39754012
else {
3976-
retval = STAT_SET_HANDLED;
3977-
if (mode==SU_MODE_INSTCMD)
4013+
if (mode==SU_MODE_INSTCMD) {
39784014
upsdebugx(1, "%s: successfully sent command %s", __func__, varname);
3979-
else {
4015+
retval = STAT_INSTCMD_HANDLED;
4016+
} else {
39804017
upsdebugx(1, "%s: successfully set %s to \"%s\"", __func__, varname, val);
39814018

39824019
/* update info array: call dstate_setinfo, since flags and aux are
39834020
* already published, and this saves us some processing */
39844021
dstate_setinfo(varname, "%s", val);
4022+
retval = STAT_SET_HANDLED;
39854023
}
39864024
}
39874025

@@ -4003,12 +4041,7 @@ int su_setvar(const char *varname, const char *val)
40034041

40044042
ret = su_setOID(SU_MODE_SETVAR, varname, val);
40054043

4006-
if (ret == STAT_SET_FAILED)
4007-
upslog_SET_FAILED(varname, val);
4008-
else if (ret == STAT_SET_UNKNOWN)
4009-
upslog_SET_UNKNOWN(varname, val);
4010-
else if (ret == STAT_SET_INVALID)
4011-
upslog_SET_INVALID(varname, val);
4044+
upslog_SET_RESULT(ret, varname, extradata);
40124045

40134046
return ret;
40144047
}
@@ -4047,12 +4080,7 @@ int su_instcmd(const char *cmdname, const char *extradata)
40474080

40484081
ret = su_setOID(SU_MODE_INSTCMD, cmdname, extradata);
40494082

4050-
if (ret == STAT_INSTCMD_FAILED)
4051-
upslog_INSTCMD_FAILED(cmdname, extradata);
4052-
else if (ret == STAT_INSTCMD_UNKNOWN)
4053-
upslog_INSTCMD_UNKNOWN(cmdname, extradata);
4054-
else if (ret == STAT_INSTCMD_INVALID)
4055-
upslog_INSTCMD_INVALID(cmdname, extradata);
4083+
upslog_INSTCMD_RESULT(ret, cmdname, extradata);
40564084

40574085
return ret;
40584086
}

drivers/upshandler.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,23 @@ struct ups_handler
210210
__func__, NUT_STRARG(cmdname), NUT_STRARG(extra)); \
211211
} while(0)
212212

213+
#define upslog_INSTCMD_CONVERSION_FAILED(cmdname, extra) do { \
214+
upslogx(LOG_INSTCMD_CONVERSION_FAILED, "%s: parameter value [%s] is invalid for command [%s]", \
215+
__func__, NUT_STRARG(extra), NUT_STRARG(cmdname)); \
216+
} while(0)
217+
218+
/* Note: log only faults; nothing for successful handling */
219+
#define upslog_INSTCMD_RESULT(ret, cmdname, extra) do { \
220+
if (ret == STAT_INSTCMD_FAILED) \
221+
upslog_INSTCMD_FAILED(cmdname, extradata); \
222+
else if (ret == STAT_INSTCMD_UNKNOWN) \
223+
upslog_INSTCMD_UNKNOWN(cmdname, extradata); \
224+
else if (ret == STAT_INSTCMD_INVALID) \
225+
upslog_INSTCMD_INVALID(cmdname, extradata); \
226+
else if (ret == STAT_INSTCMD_CONVERSION_FAILED) \
227+
upslog_INSTCMD_CONVERSION_FAILED(cmdname, extradata); \
228+
} while(0)
229+
213230
/* setvar(), setcmd() et al -- note they MUST have an argument: */
214231
#define upsdebug_SET_STARTING(varname, value) do { \
215232
upsdebugx(1, "Starting %s::%s('%s', '%s')", \
@@ -231,4 +248,21 @@ struct ups_handler
231248
__func__, NUT_STRARG(varname), NUT_STRARG(value)); \
232249
} while(0)
233250

251+
#define upslog_SET_CONVERSION_FAILED(cmdname, extra) do { \
252+
upslogx(LOG_SET_CONVERSION_FAILED, "%s: value [%s] is invalid for variable [%s]", \
253+
__func__, NUT_STRARG(extra), NUT_STRARG(cmdname)); \
254+
} while(0)
255+
256+
/* Note: log only faults; nothing for successful handling */
257+
#define upslog_SET_RESULT(ret, cmdname, extra) do { \
258+
if (ret == STAT_SET_FAILED) \
259+
upslog_SET_FAILED(cmdname, extradata); \
260+
else if (ret == STAT_SET_UNKNOWN) \
261+
upslog_SET_UNKNOWN(cmdname, extradata); \
262+
else if (ret == STAT_SET_INVALID) \
263+
upslog_SET_INVALID(cmdname, extradata); \
264+
else if (ret == STAT_SET_CONVERSION_FAILED) \
265+
upslog_SET_CONVERSION_FAILED(cmdname, extradata); \
266+
} while(0)
267+
234268
#endif /* NUT_UPSHANDLER_H */

0 commit comments

Comments
 (0)