From 2c1823a552ab397ca6ffa055f14e882e0f5055b2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 30 May 2024 20:02:51 +0200 Subject: [PATCH 01/19] common/common.c, include/common.h, tests/nutlogtest.c, NEWS.adoc: introduce snprintf_dynamic() and related methods [#2450] Mitigate the inherent insecurity of dynamically constructed formatting strings vs. a fixed vararg list with its amounts and types of variables printed by this or that method and pre-compiled in the program. * minimize_formatting_string() with caller-specified buffer; * minimize_formatting_string_staticbuf() for one-shot use-cases; * validate_formatting_string() to compare a dynamic and expected formatting strings; * vsnprintf_dynamic(), vsnprintfcat_dynamic() for practical applications (with fixed va_list argument); * snprintf_dynamic(), snprintfcat_dynamic(), mkstr_dynamic() for practical applications (with ... variadic arguments); * added vsnprintfcat() with fixed va_list argument, for good measure. Signed-off-by: Jim Klimov --- NEWS.adoc | 4 + common/common.c | 326 ++++++++++++++++++++++++++++++++++++++++++++- include/common.h | 34 ++++- tests/nutlogtest.c | 49 ++++++- 4 files changed, 397 insertions(+), 16 deletions(-) diff --git a/NEWS.adoc b/NEWS.adoc index ee34f0eb3e..96f5b242da 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -121,6 +121,10 @@ https://github.com/networkupstools/nut/milestone/11 `NUT_PIDPATH` environment variable in certain use-cases (such as tests). [#2407] + - common code hardening: added sanity-checking for dynamically constructed or + selected formatting strings with variable-argument list methods (typically + used with log printing, `dstate` setting, etc.) [#2450] + - revised `nut.exe` (the NUT for Windows wrapper for all-in-one service) to be more helpful with command-line use (report that it failed to start as a service, have a help message, pass debug verbosity to launched NUT diff --git a/common/common.c b/common/common.c index 72a8f03ef3..c35d40ed5c 100644 --- a/common/common.c +++ b/common/common.c @@ -1,7 +1,7 @@ /* common.c - common useful functions Copyright (C) 2000 Russell Kroll - Copyright (C) 2021-2022 Jim Klimov + Copyright (C) 2021-2024 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -606,9 +606,8 @@ int sendsignalfn(const char *pidfn, const char * sig) } #endif /* WIN32 */ -int snprintfcat(char *dst, size_t size, const char *fmt, ...) +int vsnprintfcat(char *dst, size_t size, const char *fmt, va_list ap) { - va_list ap; size_t len = strlen(dst); int ret; @@ -619,7 +618,6 @@ int snprintfcat(char *dst, size_t size, const char *fmt, ...) return -1; } - va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif @@ -634,7 +632,6 @@ int snprintfcat(char *dst, size_t size, const char *fmt, ...) #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif - va_end(ap); dst[size] = '\0'; @@ -655,6 +652,31 @@ int snprintfcat(char *dst, size_t size, const char *fmt, ...) return (int)len + ret; } +int snprintfcat(char *dst, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + ret = vsnprintfcat(dst, size, fmt, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + return ret; +} + /* lazy way to send a signal if the program uses the PIDPATH */ #ifndef WIN32 int sendsignal(const char *progname, int sig) @@ -1284,6 +1306,300 @@ void nut_report_config_flags(void) ); } +char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt) +{ + /* Return the bare-bone formatting string contained in "fmt" + * as "%" characters followed immediately by ASCII letters, + * or null if "fmt" is null (empty string if it has no "%"), + * or "buf" is null, or "buflen" is too short. + * Allows to compare different formatting strings to check + * if they describe the same expected amounts of arguments + * and their types. + * Uses a caller-specified buffer and returns a pointer to + * it, or NULL upon errors. + */ + const char *p; + char *b, inEscape; + size_t i; + + if (!fmt || !buf || buflen == 0) + return NULL; + + for (b = buf, p = fmt, i = 0, inEscape = 0; + (*p != '\0' && i < buflen); + p++ + ) { + if (*p == '%') { + if (*(p+1) == '%') { + /* Escaped percent character, not a variable indicator; skip it right away */ + p++; + } else { + inEscape = 1; + *b++ = *p; + i++; + } + continue; + } + + if (inEscape) { + /* Did we hit a printf format conversion character? + * Or another character that is critical for stack + * intepretation as a variable argument list? + * https://cplusplus.com/reference/cstdio/printf/ + */ + + if (*p == 'l' || *p == 'L' || *p == 'h' || *p == 'z' || *p == 'j' || *p == 't') { + /* Integer/pointer type size modifiers, e.g. + * long (long...) something, or a short int (h) + * size_t (z), intmax_t (j), ptrdiff_t (t) + */ + *b++ = *p; + i++; + continue; + } + + if (*p == '*') { + /* Field length will be in another vararg on the stack */ + *b++ = *p; + i++; + continue; + } + + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '*') { + /* Assume a conversion character (standards-dependent) */ + inEscape = 0; + *b++ = *p; + i++; + } + } + } + + if (inEscape) { + upsdebugx(1, "%s: error parsing '%s' as a formatting string - " + "got a dangling percent character", __func__, fmt); + } + + *b = '\0'; + return buf; +} + +char * minimize_formatting_string_staticbuf(const char *fmt) +{ + /* Return the bare-bone formatting string contained in "fmt" + * as "%" characters followed immediately by ASCII letters, + * or null if "fmt" is null (empty string if it has no "%"). + * Allows to compare different formatting strings to check + * if they describe the same expected amounts of arguments + * and their types. + * Returns a pointer to a static buffer; callers should + * xstrdup() and free() the returned value where applicable + * (e.g. if there is a need to compare several strings), or + * just use minimize_formatting_string() with their own + * buffers right away. + */ + + static char buf[LARGEBUF]; + + return minimize_formatting_string(buf, sizeof(buf), fmt); +} + +int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference) +{ + /* Work around the insecurity of dynamic formatting strings (created + * or selected at run-time and potentially mis-matching the stack of + * subsequent varargs) by checking that the dynamic formatting string + * to be used in practice matches the reference expectation. Compiler + * is in position to statically check that the actual varargs match + * that reference during build. + * Returns 0 if the two reference strings minimize to the same value, + * or a negative value (and sets errno) in case of errors: + * -1 for memory-related errors + * -2 for minimize_formatting_string() returning NULL + * (also likely memory errors) + * -3 and errno=EINVAL for successfully checked formatting strings + * that were found to be not equivalent + */ + if (!fmt_dynamic || !fmt_reference) { + errno = EFAULT; + return -1; + } else { + /* Prepare buffers for minimized formatting strings. + * To err on the safe side, size them same as originals. + */ + size_t lenD = strlen(fmt_dynamic) + 1; + size_t lenR = strlen(fmt_reference) + 1; + char *bufD = xcalloc(lenD, sizeof(char)), *bufR = xcalloc(lenR, sizeof(char)); + + if (!bufD || !bufR) { + if (bufD) + free(bufD); + if (bufR) + free(bufR); + errno = ENOMEM; + return -1; + } + + if (!minimize_formatting_string(bufD, lenD, fmt_dynamic) + || !minimize_formatting_string(bufR, lenR, fmt_reference) + ) { + free(bufD); + free(bufR); + errno = ERANGE; + return -2; + } + + if (!strcmp(bufD, bufR)) { + /* Two strings compared as equals, good to go */ + free(bufD); + free(bufR); + return 0; + } + + /* FIXME: Check for functional equivalence, e.g. format chars + * "x", "X", "i", "d", "u" ("o", "c"?) all describe an int, + * and "g", "G", "f", "F", "E" are doubles. + * Cross-check with standards about automatic expansion of + * byte-size for many of these types when passed in varargs. + */ + + /* This be should not be fatal right here, but may be in the caller logic */ + upsdebugx(1, "%s: dynamic formatting string '%s' is not equivalent to expected '%s'", + __func__, fmt_dynamic, fmt_reference); + free(bufD); + free(bufR); + errno = EINVAL; + return -3; + } +} + +int vsnprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) +{ + if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + return -1; + } else { +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + return vsnprintfcat(dst, size, fmt_dynamic, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + } +} + +int snprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt_reference); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + ret = vsnprintfcat_dynamic(dst, size, fmt_dynamic, fmt_reference, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + return ret; +} + +int vsnprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) +{ + if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + return -1; + } else { +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + return vsnprintf(dst, size, fmt_dynamic, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + } +} + +int snprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt_reference); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + ret = vsnprintf_dynamic(dst, size, fmt_dynamic, fmt_reference, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + return ret; +} + +char * mkstr_dynamic(const char *fmt_dynamic, const char *fmt_reference, ...) +{ + /* Practical helper with a static buffer which we can use for setting + * values as a "%s" string e.g. in calls to dstate_setinfo(), etc. + * Sets buffer to empty string in case of errors. + */ + static char buf[LARGEBUF]; + va_list ap; + int ret; + + va_start(ap, fmt_reference); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + /* Note: this code intentionally uses a caller-provided format string */ + ret = vsnprintf_dynamic(buf, sizeof(buf), fmt_dynamic, fmt_reference, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + if (ret < 0) { + buf[0] = '\0'; + } + + return buf; +} + static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) { int ret, errno_orig = errno; diff --git a/include/common.h b/include/common.h index 32e0ee2041..95f7559f5c 100644 --- a/include/common.h +++ b/include/common.h @@ -1,6 +1,8 @@ /* common.h - prototypes for the common useful functions - Copyright (C) 2000 Russell Kroll + Copyright (C) + 2000 Russell Kroll + 2020-2024 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -228,9 +230,6 @@ int sendsignal(const char *progname, int sig); int sendsignal(const char *progname, const char * sig); #endif -int snprintfcat(char *dst, size_t size, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); - /* Report maximum platform value for the pid_t */ pid_t get_max_pid_t(void); @@ -365,6 +364,33 @@ void *xcalloc(size_t number, size_t size); void *xrealloc(void *ptr, size_t size); char *xstrdup(const char *string); +int vsnprintfcat(char *dst, size_t size, const char *fmt, va_list ap); +int snprintfcat(char *dst, size_t size, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +/* Mitigate the inherent insecurity of dynamically constructed formatting + * strings vs. a fixed vararg list with its amounts and types of variables + * printed by this or that method and pre-compiled in the program. + */ +char *minimize_formatting_string(char *buf, size_t buflen, const char *fmt); +char *minimize_formatting_string_staticbuf(const char *fmt); +int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference); + +int vsnprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list va); +int snprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + +int vsnprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list va); +int snprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + +/* Practical helper with a static buffer which we can use for setting + * values as a "%s" string e.g. in calls to dstate_setinfo(), etc. + * Sets buffer to empty string in case of errors. + */ +char * mkstr_dynamic(const char *fmt_dynamic, const char *fmt_reference, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + /**** REGEX helper methods ****/ /* helper function: version of strcmp that tolerates NULL diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index b8b51dcf77..1e5139f461 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -24,16 +24,17 @@ #include "common.h" int main(void) { - const char *s1 = "!NULL"; - const char *s2 = NULL; + const char *s1 = "!NULL"; + const char *s2 = NULL; + int ret = 0; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-overflow" #endif - upsdebugx(0, "D: checking with libc handling of NULL (can segfault for some libc implementations):"); - upsdebugx(0, "D: '%s' vs '%s'", s1, s2); + upsdebugx(0, "D: checking with libc handling of NULL (can segfault for some libc implementations):"); + upsdebugx(0, "D: '%s' vs '%s'", s1, s2); /* This explicitly does not work with -Wformat, due to verbatim NULL without a var: * nutlogtest.c:20:5: error: reading through null pointer (argument 4) [-Werror=format=] @@ -43,7 +44,7 @@ int main(void) { * upsdebugx(0, "D: '%s' vs '%s'", NUT_STRARG((char *)NULL), (char *)NULL); */ - upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); + upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); #ifdef NUT_STRARG #undef NUT_STRARG @@ -59,11 +60,45 @@ int main(void) { * 45 | upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); * | ^~ */ - upsdebugx(0, "D: checking that macro wrap trick works: '%s' vs '%s'", NUT_STRARG(s2), s2); + upsdebugx(0, "D: checking that macro wrap trick works: '%s' vs '%s'", NUT_STRARG(s2), s2); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic pop #endif - return 0; + if (1) { /* scoping */ + char *dynfmt = "Test '%s'", *p; + char buf[LARGEBUF]; + + if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%s", "Single string via dynamic format") > 0) { + upsdebugx(0, "D: >>> %s", buf); + if (!strcmp(buf, "Test 'Single string via dynamic format'")) { + upsdebugx(0, "D: snprintf_dynamic() prepared a dynamically formatted string with expected content"); + } else { + upsdebugx(0, "E: snprintf_dynamic() failed to prepare a dynamically formatted string: got unexpected content"); + ret++; + } + } else { + upsdebugx(0, "E: snprintf_dynamic() failed to prepare a dynamically formatted string: returned empty or error"); + ret++; + } + + if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%s%d", "Single string via dynamic format", 1) < 0) { + upsdebugx(0, "D: snprintf_dynamic() correctly reports mis-matched formats"); + } else { + upsdebugx(0, "E: snprintf_dynamic() wrongly reports well-matched formats"); + ret++; + } + + /* Note extra non-type chars in "expected" format are stripped */ + p = mkstr_dynamic(dynfmt, " %.4s %%", "Single string inlined by mkstr_dynamic()"); + upsdebugx(0, ">>> %s", NUT_STRARG(p)); + if (!p || *p == '\0' || strcmp(p, "Test 'Single string inlined by mkstr_dynamic()'")) { + upsdebugx(0, "E: mkstr_dynamic() failed to prepare a dynamically formatted string: got unexpected content"); + } else { + upsdebugx(0, "D: mkstr_dynamic() prepared a dynamically formatted string with expected content"); + } + } + + return ret; } From ebcb0eb4347781b90e1cdc65aebb77b9c75e6aa6 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 31 May 2024 14:16:48 +0200 Subject: [PATCH 02/19] drivers/dstate.{c,h}: add vdstate_setinfo(), vdstate_addenum() and versions for hardened dynamic format string support [#2450] Signed-off-by: Jim Klimov --- drivers/dstate.c | 84 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/dstate.h | 6 ++++ 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/drivers/dstate.c b/drivers/dstate.c index e91ef7ac4d..a59fee9bfd 100644 --- a/drivers/dstate.c +++ b/drivers/dstate.c @@ -1191,13 +1191,11 @@ int dstate_poll_fds(struct timeval timeout, TYPE_FD arg_extrafd) * COMMON ******************************************************************/ -int dstate_setinfo(const char *var, const char *fmt, ...) +int vdstate_setinfo(const char *var, const char *fmt, va_list ap) { int ret; char value[ST_MAX_VALUE_LEN]; - va_list ap; - va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif @@ -1211,7 +1209,6 @@ int dstate_setinfo(const char *var, const char *fmt, ...) #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif - va_end(ap); ret = state_setinfo(&dtree_root, var, value); @@ -1222,10 +1219,9 @@ int dstate_setinfo(const char *var, const char *fmt, ...) return ret; } -int dstate_addenum(const char *var, const char *fmt, ...) +int dstate_setinfo(const char *var, const char *fmt, ...) { int ret; - char value[ST_MAX_VALUE_LEN]; va_list ap; va_start(ap, fmt); @@ -1238,12 +1234,62 @@ int dstate_addenum(const char *var, const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif - vsnprintf(value, sizeof(value), fmt, ap); + ret = vdstate_setinfo(var, fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); + return ret; +} + +int dstate_setinfo_dynamic(const char *var, const char *fmt_dynamic, const char *fmt_reference, ...) +{ + if (!var || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + return -1; + } else { + int ret; + va_list ap; + + va_start(ap, fmt_reference); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + ret = vdstate_setinfo(var, fmt_dynamic, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + return ret; + } +} + +int vdstate_addenum(const char *var, const char *fmt, va_list ap) +{ + int ret; + char value[ST_MAX_VALUE_LEN]; + +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + vsnprintf(value, sizeof(value), fmt, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + ret = state_addenum(dtree_root, var, value); if (ret == 1) { @@ -1253,6 +1299,30 @@ int dstate_addenum(const char *var, const char *fmt, ...) return ret; } +int dstate_addenum(const char *var, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY +#pragma GCC diagnostic ignored "-Wformat-security" +#endif + ret = vdstate_addenum(var, fmt, ap); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif + va_end(ap); + + return ret; +} + int dstate_addrange(const char *var, const int min, const int max) { int ret; diff --git a/drivers/dstate.h b/drivers/dstate.h index 2fa754defa..7cd2cbabe3 100644 --- a/drivers/dstate.h +++ b/drivers/dstate.h @@ -64,10 +64,16 @@ typedef struct conn_s { char * dstate_init(const char *prog, const char *devname); int dstate_poll_fds(struct timeval timeout, TYPE_FD extrafd); +int vdstate_setinfo(const char *var, const char *fmt, va_list ap); int dstate_setinfo(const char *var, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +int dstate_setinfo_dynamic(const char *var, const char *fmt_dynamic, const char *fmt_reference, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +int vdstate_addenum(const char *var, const char *fmt, va_list ap); int dstate_addenum(const char *var, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +int dstate_addenum_dynamic(const char *var, const char *fmt_dynamic, const char *fmt_reference, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); int dstate_addrange(const char *var, const int min, const int max); void dstate_setflags(const char *var, int flags); void dstate_addflags(const char *var, const int addflags); From eee056889041f989fef8e1c551a82960cc658c90 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 31 May 2024 14:41:41 +0200 Subject: [PATCH 03/19] docs/developers.txt, docs/new-drivers.txt, docs/nut.dict: document hardened *_dynamic() string methods [#2450] Signed-off-by: Jim Klimov --- docs/developers.txt | 17 +++++++++++++++++ docs/new-drivers.txt | 14 ++++++++++++++ docs/nut.dict | 5 ++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/developers.txt b/docs/developers.txt index 2916544343..1c9c6651eb 100644 --- a/docs/developers.txt +++ b/docs/developers.txt @@ -20,6 +20,23 @@ since that's an easy way to open yourself up to an exploit. Don't use `strcat()`. We have a neat wrapper for `snprintf()` called `snprintfcat()` that allows you to append to `char *` with a format string and all the usual string length checking of `snprintf()` routine. +There is also a `vsnprintfcat()` (with a single `va_list` argument) for +API completeness. + +In a few cases you can use a formatting string coming from a mapping +table or constructed during run-time. This is generally not safe (due +to references into the stack when handling the variable argument list), +and modern compilers warn against doing so. While it is possible to +quiesce the warnings with pragmas, it is better to play safe with the +"dynamic" versions of methods provided by NUT -- they allow to combine +both compile-time checks of expected formatting string vs. types of data +in the method arguments, and run-time equivalence of the actual dynamic +formatting string to those expectations. Such hardened methods include +`snprintf_dynamic()`, `vsnprintf_dynamic()`, `snprintfcat_dynamic()`, +`vsnprintfcat_dynamic()`, and `mkstr_dynamic()` which returns a `char *` +to its statically allocated buffer. Common string operations in drivers +in this case can benefit from similar `dstate_setinfo_dynamic()` or +`dstate_addenum_dynamic()` methods. Error reporting ~~~~~~~~~~~~~~~ diff --git a/docs/new-drivers.txt b/docs/new-drivers.txt index 8503a38287..440c615557 100644 --- a/docs/new-drivers.txt +++ b/docs/new-drivers.txt @@ -198,6 +198,20 @@ values right there: dstate_setinfo("ups.model", "Mega-Zapper %d", rating); +In a few cases you can use a formatting string coming from a mapping +table or constructed during run-time. This is generally not safe (due +to references into the stack when handling the variable argument list), +and modern compilers warn against doing so. While it is possible to +quiesce the warnings with pragmas, it is better to play safe with the +"dynamic" versions of methods provided by NUT -- they allow to combine +both compile-time checks of expected formatting string vs. types of data +in the method arguments, and run-time equivalence of the actual dynamic +formatting string to those expectations. In this case, you would use +`dstate_setinfo_dynamic()` with a coding pattern similar to the following: + + char *fmt = "Mega-Zapper %d"; + dstate_setinfo_dynamic("ups.model", fmt, "%d", rating); + Setting flags ~~~~~~~~~~~~~ diff --git a/docs/nut.dict b/docs/nut.dict index f6feb857ec..6aab86918a 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3165 utf-8 +personal_ws-1.1 en 3168 utf-8 AAC AAS ABI @@ -2302,6 +2302,7 @@ mirrorlist mis misconfigured mkdir +mkstr mmZ mmap mn @@ -3085,6 +3086,8 @@ vivo vo voltronic vscode +vsnprintf +vsnprintfcat wDescriptorLength waitbeforereconnect wakeup From 6f1e257978f860d00c4c1a81c6f75a489a532276 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 31 May 2024 15:49:21 +0200 Subject: [PATCH 04/19] common/common.c, tests/nutlogtest.c: minimize_formatting_string(): collapse known different formats for same data type into same char to ease sanity-check comparisons [#2450] Signed-off-by: Jim Klimov --- common/common.c | 97 ++++++++++++++++++++++++++++++++-------------- tests/nutlogtest.c | 26 +++++++++++++ 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/common/common.c b/common/common.c index c35d40ed5c..19b9c435d1 100644 --- a/common/common.c +++ b/common/common.c @@ -1346,31 +1346,77 @@ char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt) * Or another character that is critical for stack * intepretation as a variable argument list? * https://cplusplus.com/reference/cstdio/printf/ + * Note that some widths are only required with + * C99 and C++11 standards, and may be not available + * before. Still, since we rely on macro names from + * those standards (or inspired by them) like PRIiMAX + * or PRIuSIZE, defined (if missing in OS headers) + * by our "nut_stdint.h". */ - - if (*p == 'l' || *p == 'L' || *p == 'h' || *p == 'z' || *p == 'j' || *p == 't') { - /* Integer/pointer type size modifiers, e.g. - * long (long...) something, or a short int (h) - * size_t (z), intmax_t (j), ptrdiff_t (t) - */ - *b++ = *p; - i++; - continue; - } - - if (*p == '*') { - /* Field length will be in another vararg on the stack */ - *b++ = *p; - i++; - continue; + switch (*p) { + /* We care about integer/pointer type size "width" modifiers, e.g.: */ + case 'l': /* long (long) int */ + case 'L': /* long double */ + case 'h': /* short int/char */ +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined _STDC_C99) || (defined __C99FEATURES__) /* C99+ build mode */ || (defined PRIiMAX && defined PRIiSIZE) + /* Technically, double "ll" and "hh" are also new */ + case 'z': /* size_t */ + case 'j': /* intmax_t */ + case 't': /* ptrdiff_t */ +#endif + /* and here field length will be in another vararg on the stack: */ + case '*': + *b++ = *p; + i++; + continue; + + /* Known conversion characters, collapse some numeric format + * specifiers to unambiguous basic type for later comparisons */ + case 'd': + case 'i': + inEscape = 0; + *b++ = 'i'; + i++; + continue; + + case 'u': + case 'o': + case 'x': + case 'X': + inEscape = 0; + *b++ = 'u'; + i++; + continue; + + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined _STDC_C99) || (defined __C99FEATURES__) /* C99+ build mode */ + case 'F': + case 'a': + case 'A': +#endif + inEscape = 0; + *b++ = 'f'; + i++; + continue; + + case 'c': + case 's': + case 'p': + case 'n': + inEscape = 0; + *b++ = *p; + i++; + continue; } - if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '*') { - /* Assume a conversion character (standards-dependent) */ - inEscape = 0; - *b++ = *p; - i++; - } + /* Assume and skip a flags/width/precision character + * (non-POSIX standards-dependent), inconsequential + * for printf style stack parsing and memory-safety. + */ } } @@ -1455,13 +1501,6 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc return 0; } - /* FIXME: Check for functional equivalence, e.g. format chars - * "x", "X", "i", "d", "u" ("o", "c"?) all describe an int, - * and "g", "G", "f", "F", "E" are doubles. - * Cross-check with standards about automatic expansion of - * byte-size for many of these types when passed in varargs. - */ - /* This be should not be fatal right here, but may be in the caller logic */ upsdebugx(1, "%s: dynamic formatting string '%s' is not equivalent to expected '%s'", __func__, fmt_dynamic, fmt_reference); diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index 1e5139f461..d46d9b5dd5 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -70,6 +70,7 @@ int main(void) { char *dynfmt = "Test '%s'", *p; char buf[LARGEBUF]; + nut_debug_level = 1; if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%s", "Single string via dynamic format") > 0) { upsdebugx(0, "D: >>> %s", buf); if (!strcmp(buf, "Test 'Single string via dynamic format'")) { @@ -95,10 +96,35 @@ int main(void) { upsdebugx(0, ">>> %s", NUT_STRARG(p)); if (!p || *p == '\0' || strcmp(p, "Test 'Single string inlined by mkstr_dynamic()'")) { upsdebugx(0, "E: mkstr_dynamic() failed to prepare a dynamically formatted string: got unexpected content"); + ret++; } else { upsdebugx(0, "D: mkstr_dynamic() prepared a dynamically formatted string with expected content"); } } + if (1) { /* scoping */ + char **p, + *fmtFloat[] = { "%f", " %A", " %0.1E%% ", NULL }, + *fmtNotFloat[] = { "%f%", "%m", "$f", NULL }; + + for (p = &(fmtFloat[0]); *p; p++) { + if (validate_formatting_string(*p, "Voltage: %G is not %%d") < 0) { + upsdebugx(0, "E: validate_formatting_string() expecting %%f equivalent failed for: '%s'", *p); + ret++; + } else { + upsdebugx(0, "D: validate_formatting_string() expecting %%f equivalent passed for: '%s'", *p); + } + } + + for (p = &(fmtNotFloat[0]); *p; p++) { + if (validate_formatting_string("%f", *p) < 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%f failed (as it should have) for: '%s'", *p); + } else { + upsdebugx(0, "E: validate_formatting_string() expecting %%f passed (but should not have) for: '%s'", *p); + ret++; + } + } + } + return ret; } From a64e7b4ea9615ac550a17b88ada0a7ffded41225 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 00:14:56 +0200 Subject: [PATCH 05/19] common/common.c, include/common.h, drivers/dstate.c, tests/nutlogtest.c: introduce verbosity option to validate_formatting_string() and minimize_formatting_string() [#2450] Signed-off-by: Jim Klimov --- common/common.c | 27 +++++++++++++++------------ drivers/dstate.c | 2 +- include/common.h | 10 +++++++--- tests/nutlogtest.c | 4 ++-- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/common/common.c b/common/common.c index 19b9c435d1..b98de2a126 100644 --- a/common/common.c +++ b/common/common.c @@ -1306,7 +1306,7 @@ void nut_report_config_flags(void) ); } -char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt) +char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt, int verbosity) { /* Return the bare-bone formatting string contained in "fmt" * as "%" characters followed immediately by ASCII letters, @@ -1421,15 +1421,16 @@ char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt) } if (inEscape) { - upsdebugx(1, "%s: error parsing '%s' as a formatting string - " - "got a dangling percent character", __func__, fmt); + if (verbosity >= 0) + upsdebugx(verbosity, "%s: error parsing '%s' as a formatting string - " + "got a dangling percent character", __func__, fmt); } *b = '\0'; return buf; } -char * minimize_formatting_string_staticbuf(const char *fmt) +char * minimize_formatting_string_staticbuf(const char *fmt, int verbosity) { /* Return the bare-bone formatting string contained in "fmt" * as "%" characters followed immediately by ASCII letters, @@ -1446,10 +1447,10 @@ char * minimize_formatting_string_staticbuf(const char *fmt) static char buf[LARGEBUF]; - return minimize_formatting_string(buf, sizeof(buf), fmt); + return minimize_formatting_string(buf, sizeof(buf), fmt, verbosity); } -int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference) +int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference, int verbosity) { /* Work around the insecurity of dynamic formatting strings (created * or selected at run-time and potentially mis-matching the stack of @@ -1485,8 +1486,8 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc return -1; } - if (!minimize_formatting_string(bufD, lenD, fmt_dynamic) - || !minimize_formatting_string(bufR, lenR, fmt_reference) + if (!minimize_formatting_string(bufD, lenD, fmt_dynamic, verbosity) + || !minimize_formatting_string(bufR, lenR, fmt_reference, verbosity) ) { free(bufD); free(bufR); @@ -1502,8 +1503,10 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc } /* This be should not be fatal right here, but may be in the caller logic */ - upsdebugx(1, "%s: dynamic formatting string '%s' is not equivalent to expected '%s'", - __func__, fmt_dynamic, fmt_reference); + if (verbosity >= 0) + upsdebugx(verbosity, + "%s: dynamic formatting string '%s' is not equivalent to expected '%s'", + __func__, fmt_dynamic, fmt_reference); free(bufD); free(bufR); errno = EINVAL; @@ -1513,7 +1516,7 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc int vsnprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) { - if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { return -1; } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL @@ -1560,7 +1563,7 @@ int snprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const c int vsnprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) { - if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { return -1; } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL diff --git a/drivers/dstate.c b/drivers/dstate.c index a59fee9bfd..b1abc8501e 100644 --- a/drivers/dstate.c +++ b/drivers/dstate.c @@ -1245,7 +1245,7 @@ int dstate_setinfo(const char *var, const char *fmt, ...) int dstate_setinfo_dynamic(const char *var, const char *fmt_dynamic, const char *fmt_reference, ...) { - if (!var || validate_formatting_string(fmt_dynamic, fmt_reference) < 0) { + if (!var || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { return -1; } else { int ret; diff --git a/include/common.h b/include/common.h index 95f7559f5c..e3bc6c9acf 100644 --- a/include/common.h +++ b/include/common.h @@ -371,10 +371,14 @@ int snprintfcat(char *dst, size_t size, const char *fmt, ...) /* Mitigate the inherent insecurity of dynamically constructed formatting * strings vs. a fixed vararg list with its amounts and types of variables * printed by this or that method and pre-compiled in the program. + * Verbosity is passed to upsdebugx(); a negative value should keep it quiet + * (e.g. when code deliberately checks for suitable formatting constraints). + * Consumers like the *_dynamic() methods here and in dstate typically use + * "1" to make errors in code visible with any effort to troubleshoot them. */ -char *minimize_formatting_string(char *buf, size_t buflen, const char *fmt); -char *minimize_formatting_string_staticbuf(const char *fmt); -int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference); +char *minimize_formatting_string(char *buf, size_t buflen, const char *fmt, int verbosity); +char *minimize_formatting_string_staticbuf(const char *fmt, int verbosity); +int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference, int verbosity); int vsnprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list va); int snprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, ...) diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index d46d9b5dd5..cbc597e0ac 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -108,7 +108,7 @@ int main(void) { *fmtNotFloat[] = { "%f%", "%m", "$f", NULL }; for (p = &(fmtFloat[0]); *p; p++) { - if (validate_formatting_string(*p, "Voltage: %G is not %%d") < 0) { + if (validate_formatting_string(*p, "Voltage: %G is not %%d", 1) < 0) { upsdebugx(0, "E: validate_formatting_string() expecting %%f equivalent failed for: '%s'", *p); ret++; } else { @@ -117,7 +117,7 @@ int main(void) { } for (p = &(fmtNotFloat[0]); *p; p++) { - if (validate_formatting_string("%f", *p) < 0) { + if (validate_formatting_string("%f", *p, 1) < 0) { upsdebugx(0, "D: validate_formatting_string() expecting %%f failed (as it should have) for: '%s'", *p); } else { upsdebugx(0, "E: validate_formatting_string() expecting %%f passed (but should not have) for: '%s'", *p); From 06711d977b300d50288cb19f917e376567e0d003 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 00:16:01 +0200 Subject: [PATCH 06/19] common/common.c: vsnprintf_dynamic(): NULL "dst" or its "size" are a valid use-case for vsnprintf() [#2450] Signed-off-by: Jim Klimov --- common/common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/common.c b/common/common.c index b98de2a126..95a9f5ce63 100644 --- a/common/common.c +++ b/common/common.c @@ -1563,7 +1563,10 @@ int snprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const c int vsnprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) { - if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { + /* NOTE: Not checking for NULL "dst" or its "size", this is a valid + * use-case for vsnprintf() to gauge how long the string would be. + */ + if (validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { return -1; } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL From 8f3f609ee4074054db59891f4f88baf6f15972c4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 22:47:41 +0200 Subject: [PATCH 07/19] drivers/nutdrv_qx_bestups.c: bestups_model(): fix bogus sprintf() for an unknown model [#2450] Signed-off-by: Jim Klimov --- drivers/nutdrv_qx_bestups.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nutdrv_qx_bestups.c b/drivers/nutdrv_qx_bestups.c index 7f1cd45b44..94de756661 100644 --- a/drivers/nutdrv_qx_bestups.c +++ b/drivers/nutdrv_qx_bestups.c @@ -517,7 +517,7 @@ static int bestups_model(item_t *item, char *value, const size_t valuelen) /* Unknown devices */ } else { - snprintf(value, valuelen, item->dfl, "Unknown (%s)", item->value); + snprintf(value, valuelen, "Unknown (%s)", item->value); upslogx(LOG_INFO, "Unknown model detected - please report this ID: '%s'", item->value); } From 5a3986ee390b6c69ed663a1e18c2081c89e09678 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 22:48:33 +0200 Subject: [PATCH 08/19] Harden NUT work with strings: comment which use-cases we DID NOT switch to snprintf_dynamic() instead of hushing potential flaws with macros [#2450] Signed-off-by: Jim Klimov --- clients/upsimage.c | 6 ++++++ clients/upssched.c | 4 ++++ clients/upsset.c | 3 +++ drivers/belkinunv.c | 3 +++ drivers/bestfortress.c | 3 +++ drivers/mge-utalk.c | 5 ++++- drivers/nutdrv_atcl_usb.c | 4 ++++ drivers/richcomm_usb.c | 4 ++++ drivers/serial.c | 21 +++++++++++++++++++++ 9 files changed, 52 insertions(+), 1 deletion(-) diff --git a/clients/upsimage.c b/clients/upsimage.c index d49156c5b0..276852de92 100644 --- a/clients/upsimage.c +++ b/clients/upsimage.c @@ -321,6 +321,12 @@ static void noimage(const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) */ + /* FIXME: Actually, almost only fixed strings, no formatting + * needed here: one use-case of having a format, and another + * with externally prepared snprintf(). */ vsnprintf(msg, sizeof(msg), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/clients/upssched.c b/clients/upssched.c index 9a8d00dd46..ee00287445 100644 --- a/clients/upssched.c +++ b/clients/upssched.c @@ -410,6 +410,10 @@ static int send_to_one(conn_t *conn, const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) */ + /* FIXME: Actually, only fixed strings, no formatting here. */ vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/clients/upsset.c b/clients/upsset.c index f9f94228c9..06c2a40c33 100644 --- a/clients/upsset.c +++ b/clients/upsset.c @@ -278,6 +278,9 @@ static void error_page(const char *next, const char *title, #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) quite extensively. */ vsnprintf(msg, sizeof(msg), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/belkinunv.c b/drivers/belkinunv.c index 0c82865321..4dd4977c19 100644 --- a/drivers/belkinunv.c +++ b/drivers/belkinunv.c @@ -744,6 +744,9 @@ static void updatestatus(int smode, const char *fmt, ...) { #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) a few times */ vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/bestfortress.c b/drivers/bestfortress.c index 8c650abb60..5b400c2405 100644 --- a/drivers/bestfortress.c +++ b/drivers/bestfortress.c @@ -217,6 +217,9 @@ static int upssend(const char *fmt,...) { #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) */ ret = vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/mge-utalk.c b/drivers/mge-utalk.c index dca2a14fe6..00ee2da208 100644 --- a/drivers/mge-utalk.c +++ b/drivers/mge-utalk.c @@ -732,7 +732,7 @@ static void extract_info(const char *buf, const mge_info_item_t *item, NOTE: MGE counts bytes/chars the opposite way as C, see mge-utalk manpage. If status commands send two data items, these are separated by a space, so - the elements of the second item are in buf[16..9]. + the elements of the second item are in buf[16..9]. */ static int get_ups_status(void) @@ -903,6 +903,9 @@ static ssize_t mge_command(char *reply, size_t replylen, const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) quite intensively */ ret = vsnprintf(command, sizeof(command), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/nutdrv_atcl_usb.c b/drivers/nutdrv_atcl_usb.c index 92d0559012..06d8d99136 100644 --- a/drivers/nutdrv_atcl_usb.c +++ b/drivers/nutdrv_atcl_usb.c @@ -180,6 +180,10 @@ static void usb_comm_fail(const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) */ + /* FIXME: Actually, only fixed strings, no formatting here. */ ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/richcomm_usb.c b/drivers/richcomm_usb.c index ce8b3bd33d..e261103049 100644 --- a/drivers/richcomm_usb.c +++ b/drivers/richcomm_usb.c @@ -210,6 +210,10 @@ static void usb_comm_fail(const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used locally with + * fixed strings (and args) */ + /* FIXME: Actually, only fixed strings, no formatting here. */ ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop diff --git a/drivers/serial.c b/drivers/serial.c index fdff4b15fc..1e7ba0838a 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -355,6 +355,9 @@ static ssize_t send_formatted(TYPE_FD_SER fd, const char *fmt, va_list va, useco #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, technically this one is only used + * locally with args whose validity other methods may check */ ret = vsnprintf(buf, sizeof(buf), fmt, va); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop @@ -384,6 +387,12 @@ ssize_t ser_send_pace(TYPE_FD_SER fd, useconds_t d_usec, const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used from drivers with + * fixed strings (and args). + * TODO: Propose a ser_send_pace_dynamic() in case non-static + * format strings appear? Currently there are none. + */ ret = send_formatted(fd, fmt, ap, d_usec); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop @@ -411,6 +420,12 @@ ssize_t ser_send(TYPE_FD_SER fd, const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used from drivers with + * fixed strings (and args). + * TODO: Propose a ser_send_dynamic() in case non-static + * format strings appear? Currently there are none. + */ ret = send_formatted(fd, fmt, ap, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop @@ -606,6 +621,12 @@ void ser_comm_fail(const char *fmt, ...) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif + /* Note: Not converting to hardened NUT methods with dynamic + * format string checking, this one is used from drivers with + * fixed strings (and args). + * TODO: Propose a ser_comm_fail_dynamic() in case non-static + * format strings appear? Currently there are none. + */ ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop From 6946774df6d8c330f2a9487762e2691a77cb88ce Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 22:46:46 +0200 Subject: [PATCH 09/19] Harden NUT work with strings by switching to snprintf_dynamic() instead of hushing potential flaws with macros [#2450] Found by pragmas to clean up, with :; git grep -En 'Wformat-(sec|nonlit)' Signed-off-by: Jim Klimov --- clients/upsclient.c | 54 ++--- clients/upsimage.c | 18 +- clients/upsmon.c | 17 +- drivers/apc_modbus.c | 41 +--- drivers/apcupsd-ups.c | 18 +- drivers/bcmxcp.c | 16 +- drivers/bestfortress.c | 16 +- drivers/blazer.c | 32 +-- drivers/blazer_ser.c | 2 +- drivers/blazer_usb.c | 2 +- drivers/huawei-ups2000.c | 18 +- drivers/liebert-esp2.c | 47 +---- drivers/nutdrv_qx.c | 16 +- drivers/nutdrv_qx_bestups.c | 90 ++------ drivers/nutdrv_qx_blazer-common.c | 20 +- drivers/nutdrv_qx_masterguard.c | 22 +- drivers/nutdrv_qx_mecer.c | 30 +-- drivers/nutdrv_qx_voltronic-qs-hex.c | 88 +------- drivers/nutdrv_qx_voltronic-qs.c | 16 +- drivers/nutdrv_qx_voltronic.c | 304 +++------------------------ drivers/powerp-bin.c | 18 +- drivers/powerp-txt.c | 16 +- drivers/snmp-ups.c | 228 +++++--------------- drivers/usbhid-ups.c | 16 +- 24 files changed, 179 insertions(+), 966 deletions(-) diff --git a/clients/upsclient.c b/clients/upsclient.c index 74290cd26f..cee424a61a 100644 --- a/clients/upsclient.c +++ b/clients/upsclient.c @@ -554,16 +554,6 @@ const char *upscli_strerror(UPSCONN_t *ups) char sslbuf[UPSCLI_ERRBUF_LEN]; #endif -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - if (!ups) { return upscli_errlist[UPSCLI_ERR_INVALIDARG].str; } @@ -582,9 +572,10 @@ const char *upscli_strerror(UPSCONN_t *ups) return upscli_errlist[ups->upserror].str; case 1: /* add message from system's strerror */ - snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + snprintf_dynamic( + ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, - strerror(ups->syserrno)); + "%s", strerror(ups->syserrno)); return ups->errbuf; case 2: /* SSL error */ @@ -592,13 +583,15 @@ const char *upscli_strerror(UPSCONN_t *ups) err = ERR_get_error(); if (err) { ERR_error_string(err, sslbuf); - snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + snprintf_dynamic( + ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, - sslbuf); + "%s", sslbuf); } else { - snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + snprintf_dynamic( + ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, - "peer disconnected"); + "%s", "peer disconnected"); } #elif defined(WITH_NSS) /* WITH_OPENSSL */ if (PR_GetErrorTextLength() < UPSCLI_ERRBUF_LEN) { @@ -615,16 +608,13 @@ const char *upscli_strerror(UPSCONN_t *ups) return ups->errbuf; case 3: /* parsing (parseconf) error */ - snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + snprintf_dynamic( + ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, - ups->pc_ctx.errmsg); + "%s", ups->pc_ctx.errmsg); return ups->errbuf; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif - /* fallthrough */ snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, "Unknown error flag %d", @@ -1316,23 +1306,9 @@ static void build_cmd(char *buf, size_t bufsize, const char *cmdname, format = " %s"; } - /* snprintfcat would tie us to common */ - - len = strlen(buf); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(buf + len, bufsize - len, format, - pconf_encode(arg[i], enc, sizeof(enc))); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintfcat_dynamic( + buf, bufsize, format, + "%s", pconf_encode(arg[i], enc, sizeof(enc))); } len = strlen(buf); diff --git a/clients/upsimage.c b/clients/upsimage.c index 276852de92..7e7deec06a 100644 --- a/clients/upsimage.c +++ b/clients/upsimage.c @@ -275,20 +275,10 @@ static void drawbar( gdImageFilledRectangle(im, 25, bar_y, width - 25, scale_height, bar_color); - /* stick the text version of the value at the bottom center */ -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(text, sizeof(text), format, value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + /* stick the text version of the value at the bottom center + * expected format is one of imgvar[] entries for "double value" + */ + snprintf_dynamic(text, sizeof(text), format, "%f", value); gdImageString(im, gdFontMediumBold, (width - (int)(strlen(text))*gdFontMediumBold->w)/2, height - gdFontMediumBold->h, diff --git a/clients/upsmon.c b/clients/upsmon.c index 1e64c564a7..33953de966 100644 --- a/clients/upsmon.c +++ b/clients/upsmon.c @@ -378,21 +378,12 @@ static void do_notify(const utype_t *ups, int ntype) if (notifylist[i].type == ntype) { upsdebugx(2, "%s: ntype 0x%04x (%s)", __func__, ntype, notifylist[i].name); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(msg, sizeof(msg), + + snprintf_dynamic(msg, sizeof(msg), notifylist[i].msg ? notifylist[i].msg : notifylist[i].stockmsg, + "%s", ups ? ups->sys : ""); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + notify(msg, notifylist[i].flags, notifylist[i].name, upsname); diff --git a/drivers/apc_modbus.c b/drivers/apc_modbus.c index 8aafce1479..655d6da26c 100644 --- a/drivers/apc_modbus.c +++ b/drivers/apc_modbus.c @@ -32,7 +32,7 @@ #include #define DRIVER_NAME "NUT APC Modbus driver" -#define DRIVER_VERSION "0.10" +#define DRIVER_VERSION "0.11" #if defined NUT_MODBUS_HAS_USB @@ -389,16 +389,8 @@ static int _apc_modbus_double_to_nut(const apc_modbus_value_t *value, char *outp if (value->format != NULL) format = value->format; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif - res = snprintf(output, output_len, format, double_value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + res = snprintf_dynamic(output, output_len, format, "%f", double_value); + if (res < 0 || (size_t)res >= output_len) { return 0; } @@ -432,16 +424,8 @@ static int _apc_modbus_power_to_nut(const apc_modbus_value_t *value, char *outpu if (value->format != NULL) format = value->format; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif - res = snprintf(output, output_len, format, double_value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + res = snprintf_dynamic(output, output_len, format, "%f", double_value); + if (res < 0 || (size_t)res >= output_len) { return 0; } @@ -1059,27 +1043,18 @@ static int _apc_modbus_update_value(apc_modbus_register_t *regs_info, const uint } dstate_setinfo(regs_info->nut_variable_name, "%s", nutvbuf); } else { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif assert(regs_info->value_type <= apc_modbus_value_types_max); switch (regs_info->value_type) { case APC_VT_STRING: - dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.string_value); + dstate_setinfo_dynamic(regs_info->nut_variable_name, regs_info->value_format, "%s", value.data.string_value); break; case APC_VT_INT: - dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.int_value); + dstate_setinfo_dynamic(regs_info->nut_variable_name, regs_info->value_format, "%" PRIi64, value.data.int_value); break; case APC_VT_UINT: - dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.uint_value); + dstate_setinfo_dynamic(regs_info->nut_variable_name, regs_info->value_format, "%" PRIu64, value.data.uint_value); break; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif } dstate_flags = 0; diff --git a/drivers/apcupsd-ups.c b/drivers/apcupsd-ups.c index 9f4b71bc20..303b2ac7a7 100644 --- a/drivers/apcupsd-ups.c +++ b/drivers/apcupsd-ups.c @@ -57,7 +57,7 @@ typedef struct pollfd { #include "nut_stdint.h" #define DRIVER_NAME "apcupsd network client UPS driver" -#define DRIVER_VERSION "0.72" +#define DRIVER_VERSION "0.73" #define POLL_INTERVAL_MIN 10 @@ -163,22 +163,10 @@ static void process(char *item,char *data) } else { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif /* default_value acts as a format string in this case */ - dstate_setinfo(nut_data[i].info_type, + dstate_setinfo_dynamic(nut_data[i].info_type, nut_data[i].default_value, - atof(data)*nut_data[i].info_len); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + "%f", atof(data)*nut_data[i].info_len); } break; } diff --git a/drivers/bcmxcp.c b/drivers/bcmxcp.c index 475316c217..12764c56be 100644 --- a/drivers/bcmxcp.c +++ b/drivers/bcmxcp.c @@ -118,7 +118,7 @@ TODO List: #include "bcmxcp.h" #define DRIVER_NAME "BCMXCP UPS driver" -#define DRIVER_VERSION "0.34" +#define DRIVER_VERSION "0.35" #define MAX_NUT_NAME_LENGTH 128 #define NUT_OUTLET_POSITION 7 @@ -897,19 +897,7 @@ void decode_meter_map_entry(const unsigned char *entry, const unsigned char form fValue = get_float(entry); /* Format is packed BCD */ snprintf(sFormat, 31, "%%%d.%df", ((format & 0xf0) >> 4), (format & 0x0f)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, 127, sFormat, fValue); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, 127, sFormat, "%f", fValue); } else if (format == 0xe2) { /* Seconds */ diff --git a/drivers/bestfortress.c b/drivers/bestfortress.c index 5b400c2405..e10a81c911 100644 --- a/drivers/bestfortress.c +++ b/drivers/bestfortress.c @@ -35,7 +35,7 @@ #endif #define DRIVER_NAME "Best Fortress UPS driver" -#define DRIVER_VERSION "0.09" +#define DRIVER_VERSION "0.10" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -185,19 +185,7 @@ static inline void setinfo_float (const char *key, const char * fmt, const char strncpy (buf, s, len); buf[len] = 0; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo (key, fmt, factor * (double)(atoi (buf))); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + dstate_setinfo_dynamic (key, fmt, "%f", factor * (double)(atoi (buf))); } static int upssend(const char *fmt,...) { diff --git a/drivers/blazer.c b/drivers/blazer.c index af224fb5bb..c6512176d2 100644 --- a/drivers/blazer.c +++ b/drivers/blazer.c @@ -204,7 +204,6 @@ static int blazer_status(const char *cmd) } for (i = 0, val = strtok_r(buf+1, " ", &last); status[i].var; i++, val = strtok_r(NULL, " \r\n", &last)) { - if (!val) { upsdebugx(2, "%s: parsing failed", __func__); return -1; @@ -215,20 +214,7 @@ static int blazer_status(const char *cmd) continue; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(status[i].var, status[i].fmt, status[i].conv(val, NULL)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif - + dstate_setinfo_dynamic(status[i].var, status[i].fmt, "%f", status[i].conv(val, NULL)); } if (!val) { @@ -344,7 +330,6 @@ static int blazer_rating(const char *cmd) } for (i = 0, val = strtok_r(buf+1, " ", &last); rating[i].var; i++, val = strtok_r(NULL, " \r\n", &last)) { - if (!val) { upsdebugx(2, "%s: parsing failed", __func__); return -1; @@ -355,20 +340,7 @@ static int blazer_rating(const char *cmd) continue; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(rating[i].var, rating[i].fmt, rating[i].conv(val, NULL)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif - + dstate_setinfo_dynamic(rating[i].var, rating[i].fmt, "%f", rating[i].conv(val, NULL)); } return 0; diff --git a/drivers/blazer_ser.c b/drivers/blazer_ser.c index 5f830e3e6a..8bdc2c423f 100644 --- a/drivers/blazer_ser.c +++ b/drivers/blazer_ser.c @@ -31,7 +31,7 @@ #include "blazer.h" #define DRIVER_NAME "Megatec/Q1 protocol serial driver" -#define DRIVER_VERSION "1.62" +#define DRIVER_VERSION "1.63" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/drivers/blazer_usb.c b/drivers/blazer_usb.c index 7cc5c8c039..a0693806c9 100644 --- a/drivers/blazer_usb.c +++ b/drivers/blazer_usb.c @@ -37,7 +37,7 @@ #endif #define DRIVER_NAME "Megatec/Q1 protocol USB driver" -#define DRIVER_VERSION "0.19" +#define DRIVER_VERSION "0.20" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/drivers/huawei-ups2000.c b/drivers/huawei-ups2000.c index ce9cb2bbae..ab448b631f 100644 --- a/drivers/huawei-ups2000.c +++ b/drivers/huawei-ups2000.c @@ -51,7 +51,7 @@ #include "timehead.h" /* fallback gmtime_r() variants if needed (e.g. some WIN32) */ #define DRIVER_NAME "NUT Huawei UPS2000 (1kVA-3kVA) RS-232 Modbus driver" -#define DRIVER_VERSION "0.06" +#define DRIVER_VERSION "0.07" #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #define MODBUS_SLAVE_ID 1 @@ -627,20 +627,8 @@ static int ups2000_update_info(void) return 1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(ups2000_var[i].name, ups2000_var[i].fmt, - (float) val / ups2000_var[i].scaling); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + dstate_setinfo_dynamic(ups2000_var[i].name, ups2000_var[i].fmt, + "%f", (float) val / ups2000_var[i].scaling); } return 0; } diff --git a/drivers/liebert-esp2.c b/drivers/liebert-esp2.c index 10b67b789e..03136a9b6f 100644 --- a/drivers/liebert-esp2.c +++ b/drivers/liebert-esp2.c @@ -28,7 +28,7 @@ #define IsBitSet(val, bit) ((val) & (1 << (bit))) #define DRIVER_NAME "Liebert ESP-II serial UPS driver" -#define DRIVER_VERSION "0.07" +#define DRIVER_VERSION "0.08" #define UPS_SHUTDOWN_DELAY 12 /* it means UPS will be shutdown 120 sec */ #define SHUTDOWN_CMD_LEN 8 @@ -400,19 +400,8 @@ void upsdrv_updateinfo(void) intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(vartab[i].var, vartab[i].fmt, multi[vartab[i].multindex] * intval); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + + dstate_setinfo_dynamic(vartab[i].var, vartab[i].fmt, "%f", multi[vartab[i].multindex] * intval); } if (num_inphases==3){ @@ -444,19 +433,8 @@ void upsdrv_updateinfo(void) intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(cmdin_p[i].var, cmdin_p[i].fmt, multi[cmdin_p[i].multindex] * intval); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + + dstate_setinfo_dynamic(cmdin_p[i].var, cmdin_p[i].fmt, "%f", multi[cmdin_p[i].multindex] * intval); } for (i = 0; cmdout_p[i].var; i++) { @@ -468,19 +446,8 @@ void upsdrv_updateinfo(void) intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(cmdout_p[i].var, cmdout_p[i].fmt, multi[cmdout_p[i].multindex] * intval); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + + dstate_setinfo_dynamic(cmdout_p[i].var, cmdout_p[i].fmt, "%f", multi[cmdout_p[i].multindex] * intval); } status_init(); diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index a50728a356..713992527e 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -58,7 +58,7 @@ #define DRIVER_NAME "Generic Q* Serial driver" #endif /* QX_USB */ -#define DRIVER_VERSION "0.36" +#define DRIVER_VERSION "0.37" #ifdef QX_SERIAL #include "serial.h" @@ -4403,19 +4403,7 @@ int ups_infoval_set(item_t *item) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, sizeof(value), item->dfl, strtod(value, NULL)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, sizeof(value), item->dfl, "%f", strtod(value, NULL)); } } diff --git a/drivers/nutdrv_qx_bestups.c b/drivers/nutdrv_qx_bestups.c index 94de756661..dc4ee1b919 100644 --- a/drivers/nutdrv_qx_bestups.c +++ b/drivers/nutdrv_qx_bestups.c @@ -30,7 +30,7 @@ #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_bestups.h" -#define BESTUPS_VERSION "BestUPS 0.07" +#define BESTUPS_VERSION "BestUPS 0.08" /* Support functions */ static int bestups_claim(void); @@ -375,19 +375,7 @@ static int bestups_process_setvar(item_t *item, char *value, const size_t valuel } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->command, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->command, "%f", val); return 0; } @@ -422,16 +410,6 @@ static int bestups_process_bbb_status_bit(item_t *item, char *value, const size_ /* Identify UPS manufacturer */ static int bestups_manufacturer(item_t *item, char *value, const size_t valuelen) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - /* Best Power devices */ if ( !strcmp(item->value, "AX1") || @@ -440,7 +418,7 @@ static int bestups_manufacturer(item_t *item, char *value, const size_t valuelen !strcmp(item->value, "PR2") || !strcmp(item->value, "PRO") ) { - snprintf(value, valuelen, item->dfl, "Best Power"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Best Power"); return 0; } @@ -450,16 +428,12 @@ static int bestups_manufacturer(item_t *item, char *value, const size_t valuelen !strcmp(item->value, "520") || !strcmp(item->value, "620") ) { - snprintf(value, valuelen, item->dfl, "Sola Australia"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Sola Australia"); return 0; } /* Unknown devices */ - snprintf(value, valuelen, item->dfl, "Unknown"); - -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Unknown"); return 0; } @@ -469,38 +443,28 @@ static int bestups_model(item_t *item, char *value, const size_t valuelen) { item_t *unskip; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - /* Best Power devices */ if (!strcmp(item->value, "AX1")) { - snprintf(value, valuelen, item->dfl, "Axxium Rackmount"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Axxium Rackmount"); } else if (!strcmp(item->value, "FOR")) { - snprintf(value, valuelen, item->dfl, "Fortress"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Fortress"); } else if (!strcmp(item->value, "FTC")) { - snprintf(value, valuelen, item->dfl, "Fortress Telecom"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Fortress Telecom"); } else if (!strcmp(item->value, "PR2")) { - snprintf(value, valuelen, item->dfl, "Patriot Pro II"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Patriot Pro II"); inverted_bbb_bit = 1; } else if (!strcmp(item->value, "PRO")) { - snprintf(value, valuelen, item->dfl, "Patriot Pro"); + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Patriot Pro"); inverted_bbb_bit = 1; /* Sola Australia devices */ @@ -550,10 +514,6 @@ static int bestups_model(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif - return 0; } @@ -570,19 +530,7 @@ static int bestups_batt_runtime(item_t *item, char *value, const size_t valuelen /* Battery runtime is reported by the UPS in minutes, NUT expects seconds */ runtime = strtod(item->value, NULL) * 60; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, runtime); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", runtime); return 0; } @@ -676,7 +624,7 @@ static int bestups_get_pins_shutdown_mode(item_t *item, char *value, const size_ static int bestups_voltage_settings(item_t *item, char *value, const size_t valuelen) { long index; - int val; + int val; const char *nominal_voltage; const struct { const int low; /* Low voltage -> input.transfer.low / input.transfer.boost.low */ @@ -771,19 +719,7 @@ static int bestups_voltage_settings(item_t *item, char *value, const size_t valu } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%d", val); return 0; } diff --git a/drivers/nutdrv_qx_blazer-common.c b/drivers/nutdrv_qx_blazer-common.c index 2ff16bc3bb..cd4ea4a0ff 100644 --- a/drivers/nutdrv_qx_blazer-common.c +++ b/drivers/nutdrv_qx_blazer-common.c @@ -242,16 +242,6 @@ int blazer_process_setvar(item_t *item, char *value, const size_t valuelen) /* Preprocess instant commands */ int blazer_process_command(item_t *item, char *value, const size_t valuelen) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - if (!strcasecmp(item->info_type, "shutdown.return")) { /* Sn: Shutdown after n minutes and then turn on when mains is back @@ -264,7 +254,7 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) * (thus the default of ondelay=3 mins) */ long offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10), - ondelay = strtol(dstate_getinfo("ups.delay.start"), NULL, 10) / 60; + ondelay = strtol(dstate_getinfo("ups.delay.start"), NULL, 10) / 60; char buf[SMALLBUF] = ""; if (ondelay <= 0) { @@ -303,7 +293,7 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) } - snprintf(value, valuelen, item->command, buf); + snprintf_dynamic(value, valuelen, item->command, "%s", buf); } else if (!strcasecmp(item->info_type, "shutdown.stayoff")) { @@ -326,7 +316,7 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) snprintf(buf, sizeof(buf), "%02ld", offdelay / 60); } - snprintf(value, valuelen, item->command, buf); + snprintf_dynamic(value, valuelen, item->command, "%s", buf); } else if (!strcasecmp(item->info_type, "test.battery.start")) { @@ -348,10 +338,6 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif - return 0; } diff --git a/drivers/nutdrv_qx_masterguard.c b/drivers/nutdrv_qx_masterguard.c index 85a0cae0f6..815035ca57 100644 --- a/drivers/nutdrv_qx_masterguard.c +++ b/drivers/nutdrv_qx_masterguard.c @@ -26,7 +26,7 @@ #include #include "nut_stdint.h" -#define MASTERGUARD_VERSION "Masterguard 0.02" +#define MASTERGUARD_VERSION "Masterguard 0.03" /* series (for un-SKIP) */ static char masterguard_my_series = '?'; @@ -600,29 +600,19 @@ static int masterguard_setvar(item_t *item, char *value, const size_t valuelen) upsdebugx(2, "setvar: unknown dfl %s", item->dfl); return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif + switch (t) { case 'd': - snprintf(value, valuelen, item->command, i); + snprintf_dynamic(value, valuelen, item->command, "%ld", i); break; case 'f': - snprintf(value, valuelen, item->command, f); + snprintf_dynamic(value, valuelen, item->command, "%f", f); break; case 's': - snprintf(value, valuelen, item->command, s); + snprintf_dynamic(value, valuelen, item->command, "%s", s); break; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + return 0; ill: upsdebugx(2, "setvar: illegal %s value %s", item->dfl, value); diff --git a/drivers/nutdrv_qx_mecer.c b/drivers/nutdrv_qx_mecer.c index e4702944ca..a4fc1415d5 100644 --- a/drivers/nutdrv_qx_mecer.c +++ b/drivers/nutdrv_qx_mecer.c @@ -25,7 +25,7 @@ #include "nutdrv_qx_mecer.h" -#define MECER_VERSION "Mecer 0.08" +#define MECER_VERSION "Mecer 0.09" /* Support functions */ static int mecer_claim(void); @@ -215,19 +215,7 @@ static int voltronic_p98_protocol(item_t *item, char *value, const size_t valuel return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, "Voltronic Power P98"); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", "Voltronic Power P98"); return 0; } @@ -274,19 +262,7 @@ static int mecer_process_test_battery(item_t *item, char *value, const size_t va } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->command, buf); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->command, "%s", buf); return 0; } diff --git a/drivers/nutdrv_qx_voltronic-qs-hex.c b/drivers/nutdrv_qx_voltronic-qs-hex.c index 9485fe0e18..9f303f46e8 100644 --- a/drivers/nutdrv_qx_voltronic-qs-hex.c +++ b/drivers/nutdrv_qx_voltronic-qs-hex.c @@ -25,7 +25,7 @@ #include "nutdrv_qx_voltronic-qs-hex.h" -#define VOLTRONIC_QS_HEX_VERSION "Voltronic-QS-Hex 0.10" +#define VOLTRONIC_QS_HEX_VERSION "Voltronic-QS-Hex 0.11" /* Support functions */ static int voltronic_qs_hex_claim(void); @@ -323,19 +323,7 @@ static int voltronic_qs_hex_protocol(item_t *item, char *value, const size_t val return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, item->value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", item->value); /* Unskip items supported only by devices that implement 'T' protocol */ @@ -368,19 +356,7 @@ static int voltronic_qs_hex_input_output_voltage(item_t *item, char *value, cons val = strtol(item->value, &str_end, 16) * strtol(str_end, NULL, 16) / 51; ret = val / 256.0; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, ret); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", ret); return 0; } @@ -393,19 +369,7 @@ static int voltronic_qs_hex_load(item_t *item, char *value, const size_t valuele return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, strtol(item->value, NULL, 16)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%ld", strtol(item->value, NULL, 16)); return 0; } @@ -427,19 +391,7 @@ static int voltronic_qs_hex_frequency(item_t *item, char *value, const size_t va ret = val2 / val1; ret = ret > 99.9 ? 99.9 : ret; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, ret); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", ret); return 0; } @@ -448,6 +400,7 @@ static int voltronic_qs_hex_frequency(item_t *item, char *value, const size_t va static int voltronic_qs_hex_battery_voltage(item_t *item, char *value, const size_t valuelen) { long val1, val2; + double val3; char *str_end; if (strspn(item->value, "0123456789ABCDEFabcdef ") != strlen(item->value)) { @@ -457,20 +410,9 @@ static int voltronic_qs_hex_battery_voltage(item_t *item, char *value, const siz val1 = strtol(item->value, &str_end, 16); val2 = strtol(str_end, NULL, 16); + val3 = (val1 * val2) / 510.0; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, (val1 * val2) / 510.0); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", val3); return 0; } @@ -538,19 +480,7 @@ static int voltronic_qs_hex_process_ratings_bits(item_t *item, char *value, cons return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, ret); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", ret); return 0; } diff --git a/drivers/nutdrv_qx_voltronic-qs.c b/drivers/nutdrv_qx_voltronic-qs.c index d0a3cb2f7e..2732f13d2c 100644 --- a/drivers/nutdrv_qx_voltronic-qs.c +++ b/drivers/nutdrv_qx_voltronic-qs.c @@ -25,7 +25,7 @@ #include "nutdrv_qx_voltronic-qs.h" -#define VOLTRONIC_QS_VERSION "Voltronic-QS 0.09" +#define VOLTRONIC_QS_VERSION "Voltronic-QS 0.10" /* Support functions */ static int voltronic_qs_claim(void); @@ -204,19 +204,7 @@ static int voltronic_qs_protocol(item_t *item, char *value, const size_t valuele if (ret == -1) { upsdebugx(2, "%s: invalid protocol [%s]", __func__, item->value); } else { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, item->value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", item->value); } return ret; diff --git a/drivers/nutdrv_qx_voltronic.c b/drivers/nutdrv_qx_voltronic.c index 23e932f5c6..1208d3ef37 100644 --- a/drivers/nutdrv_qx_voltronic.c +++ b/drivers/nutdrv_qx_voltronic.c @@ -25,7 +25,7 @@ #include "nutdrv_qx.h" #include "nutdrv_qx_voltronic.h" -#define VOLTRONIC_VERSION "Voltronic 0.08" +#define VOLTRONIC_VERSION "Voltronic 0.09" /* Support functions */ static int voltronic_claim(void); @@ -1921,19 +1921,7 @@ static int voltronic_process_setvar(item_t *item, char *value, const size_t valu } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->command, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->command, "%f", val); return 0; } @@ -2069,19 +2057,7 @@ static int voltronic_process_command(item_t *item, char *value, const size_t val } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->command, buf); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->command, "%s", buf); return 0; } @@ -2396,19 +2372,7 @@ static int voltronic_capability(item_t *item, char *value, const size_t valuelen if (!val) return -1; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", val); /* This item doesn't have a NUT var and we were not asked by the user to change its value */ if ((item->qxflags & QX_FLAG_NONUT) && !getval(item->info_type)) @@ -2429,27 +2393,15 @@ static int voltronic_capability(item_t *item, char *value, const size_t valuelen /* *SETVAR* Set UPS capability options */ static int voltronic_capability_set(item_t *item, char *value, const size_t valuelen) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif if (!strcasecmp(value, "yes")) { - snprintf(value, valuelen, item->command, "E"); + snprintf_dynamic(value, valuelen, item->command, "%s", "E"); return 0; } if (!strcasecmp(value, "no")) { - snprintf(value, valuelen, item->command, "D"); + snprintf_dynamic(value, valuelen, item->command, "%s", "D"); return 0; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ upslogx(LOG_ERR, "%s: given value [%s] is not acceptable. Enter either 'yes' or 'no'.", item->info_type, value); @@ -2502,27 +2454,15 @@ static int voltronic_capability_set_nonut(item_t *item, char *value, const size_ return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif if (!strcasecmp(value, "disabled")) { - snprintf(value, valuelen, item->command, "D"); + snprintf_dynamic(value, valuelen, item->command, "%s", "D"); } else if (!strcasecmp(value, "enabled")) { - snprintf(value, valuelen, item->command, "E"); + snprintf_dynamic(value, valuelen, item->command, "%s", "E"); } else { /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ upslogx(LOG_ERR, "%s: [%s] is not within acceptable values [enabled/disabled]", item->info_type, value); return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif return 0; } @@ -2574,19 +2514,7 @@ static int voltronic_eco_volt(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, strtod(item->value, NULL)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", strtod(item->value, NULL)); outvoltnom = dstate_getinfo("output.voltage.nominal"); @@ -2752,19 +2680,7 @@ static int voltronic_eco_freq(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, strtod(item->value, NULL)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", strtod(item->value, NULL)); /* Unskip input.transfer.{high,low} setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); @@ -2812,19 +2728,7 @@ static int voltronic_bypass(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", val); /* No user-provided value to change.. */ if (!getval(item->info_type)) @@ -2861,19 +2765,7 @@ static int voltronic_batt_numb(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, (int)battery_number); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%d", (int)battery_number); /* No user-provided value to change.. */ if (!getval(item->info_type)) @@ -2904,19 +2796,7 @@ static int voltronic_batt_runtime(item_t *item, char *value, const size_t valuel /* Battery runtime is reported by the UPS in minutes, NUT expects seconds */ runtime = strtod(item->value, NULL) * 60; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, runtime); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", runtime); return 0; } @@ -2981,19 +2861,7 @@ static int voltronic_fault(item_t *item, char *value, const size_t valuelen) upslogx(LOG_INFO, "Checking for faults.."); if (!strcasecmp(item->value, "OK")) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, "No fault found"); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", "No fault found"); upslogx(LOG_INFO, "%s", value); item->qxflags |= QX_FLAG_SKIP; return 0; @@ -3342,19 +3210,7 @@ static int voltronic_fault(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, alarm); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", alarm); upslogx(LOG_INFO, "Fault found: %s", alarm); item->qxflags |= QX_FLAG_SKIP; @@ -3833,23 +3689,11 @@ static int voltronic_mode(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif if (alarm && !strcasecmp(item->info_type, "ups.alarm")) { - snprintf(value, valuelen, item->dfl, alarm); + snprintf_dynamic(value, valuelen, item->dfl, "%s", alarm); } else if (status && !strcasecmp(item->info_type, "ups.status")) { - snprintf(value, valuelen, item->dfl, status); + snprintf_dynamic(value, valuelen, item->dfl, "%s", status); } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif return 0; } @@ -4045,19 +3889,7 @@ static int voltronic_output_powerfactor(item_t *item, char *value, const size_t /* UPS report a value expressed in % so -> output.powerfactor*100 e.g. opf = 0,8 -> ups = 80 */ opf = strtod(item->value, NULL) * 0.01; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, opf); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", opf); return 0; } @@ -4071,19 +3903,7 @@ static int voltronic_serial_numb(item_t *item, char *value, const size_t valuele return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, item->value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", item->value); return 0; } @@ -4117,26 +3937,14 @@ static int voltronic_outlet(item_t *item, char *value, const size_t valuelen) } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif if (strstr(item->info_type, "switchable")) { - snprintf(value, valuelen, item->dfl, switchable); + snprintf_dynamic(value, valuelen, item->dfl, "%s", switchable); } else if (strstr(item->info_type, "status")) { - snprintf(value, valuelen, item->dfl, status); + snprintf_dynamic(value, valuelen, item->dfl, "%s", status); } else { /* Don't know what happened */ return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif /* Unskip outlet.n.delay.shutdown */ snprintf(buf, sizeof(buf), "outlet.%c.delay.shutdown", number); @@ -4190,19 +3998,7 @@ static int voltronic_outlet_delay(item_t *item, char *value, const size_t valuel /* UPS reports minutes, NUT expects seconds */ val = strtod(item->value, NULL) * 60; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, val); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%f", val); /* Unskip outlet.n.delay.shutdown setvar */ snprintf(buf, sizeof(buf), "outlet.%c.delay.shutdown", number); @@ -4232,19 +4028,7 @@ static int voltronic_outlet_delay_set(item_t *item, char *value, const size_t va /* From seconds to minute */ delay = delay / 60; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->command, (int)delay); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->command, "%d", (int)delay); return 0; } @@ -4268,19 +4052,7 @@ static int voltronic_p31b(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, item->info_rw[(size_t)val].value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", item->info_rw[(size_t)val].value); return 0; } @@ -4330,19 +4102,7 @@ static int voltronic_p31g(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, item->info_rw[(size_t)val].value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%s", item->info_rw[(size_t)val].value); work_range_type = val; @@ -4421,19 +4181,7 @@ static int voltronic_phase(item_t *item, char *value, const size_t valuelen) return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, (int)angle); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(value, valuelen, item->dfl, "%d", (int)angle); return 0; } diff --git a/drivers/powerp-bin.c b/drivers/powerp-bin.c index 0c7da014a0..79ab63349b 100644 --- a/drivers/powerp-bin.c +++ b/drivers/powerp-bin.c @@ -35,7 +35,7 @@ #include -#define POWERPANEL_BIN_VERSION "Powerpanel-Binary 0.5" +#define POWERPANEL_BIN_VERSION "Powerpanel-Binary 0.50" typedef struct { unsigned char start; @@ -305,20 +305,8 @@ static int powpan_setvar(const char *varname, const char *val) continue; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(command, sizeof(command), vartab[i].set, - vartab[i].map[type][j].command); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(command, sizeof(command), vartab[i].set, + "%c", vartab[i].map[type][j].command); if ((powpan_command(command, 4) == 3) && (!memcmp(powpan_answer, command, 3))) { dstate_setinfo(varname, "%s", val); diff --git a/drivers/powerp-txt.c b/drivers/powerp-txt.c index 0390a7ca64..5bf80d6a9d 100644 --- a/drivers/powerp-txt.c +++ b/drivers/powerp-txt.c @@ -36,7 +36,7 @@ #include -#define POWERPANEL_TEXT_VERSION "Powerpanel-Text 0.6" +#define POWERPANEL_TEXT_VERSION "Powerpanel-Text 0.60" typedef struct { float i_volt; @@ -207,19 +207,7 @@ static int powpan_setvar(const char *varname, const char *val) return STAT_SET_HANDLED; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(command, sizeof(command), vartab[i].set, atoi(val)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(command, sizeof(command), vartab[i].set, "%d", atoi(val)); if ((powpan_command(command) == 2) && (!strcasecmp(powpan_answer, "#0"))) { dstate_setinfo(varname, "%s", val); diff --git a/drivers/snmp-ups.c b/drivers/snmp-ups.c index d6e2f6a89b..216ce91011 100644 --- a/drivers/snmp-ups.c +++ b/drivers/snmp-ups.c @@ -174,7 +174,7 @@ static const char *mibname; static const char *mibvers; #define DRIVER_NAME "Generic SNMP UPS driver" -#define DRIVER_VERSION "1.31" +#define DRIVER_VERSION "1.32" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -665,19 +665,7 @@ void upsdrv_initups(void) cur_info_p->OID = (char *)xmalloc(SU_INFOSIZE); snprintf((char*)cur_info_p->info_type, SU_INFOSIZE, "%s", su_info_p->info_type); /* Use the daisychain master (0) / 1rst device index */ -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, 0); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, "%i", 0); } else { upsdebugx(2, "Found entry, not a template %s", su_info_p->OID); @@ -1872,19 +1860,7 @@ static bool_t match_model_OID(void) cur_info_p->OID = (char *)xmalloc(SU_INFOSIZE); snprintf((char*)cur_info_p->info_type, SU_INFOSIZE, "%s", su_info_p->info_type); /* Use the daisychain master (0) / 1rst device index */ -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, 0); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, "%i", 0); } else { upsdebugx(2, "Found entry, not a template %s", su_info_p->OID); @@ -2396,33 +2372,21 @@ static int base_snmp_template_index(const snmp_info_t *su_info_p) { /* not initialised yet */ for (base_index = 0 ; base_index < 2 ; base_index++) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif /* Test if this template also includes daisychain, in which case * we just use the current device index */ if (is_multiple_template(su_info_p->OID) == TRUE) { if (su_info_p->flags & SU_TYPE_DAISY_1) { - snprintf(test_OID, sizeof(test_OID), su_info_p->OID, + snprintf_dynamic(test_OID, sizeof(test_OID), su_info_p->OID, "%i%i", current_device_number + device_template_offset, base_index); } else { - snprintf(test_OID, sizeof(test_OID), su_info_p->OID, + snprintf_dynamic(test_OID, sizeof(test_OID), su_info_p->OID, "%i%i", base_index, current_device_number + device_template_offset); } } else { - snprintf(test_OID, sizeof(test_OID), su_info_p->OID, base_index); + snprintf_dynamic(test_OID, sizeof(test_OID), su_info_p->OID, "%i", base_index); } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif if (nut_snmp_get(test_OID) != NULL) { if (su_info_p->flags & SU_FLAG_ZEROINVALID) { @@ -2479,19 +2443,8 @@ static int guesstimate_template_count(snmp_info_t *su_info_p) } /* Determine if OID index starts from 0 or 1? */ -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(test_OID, sizeof(test_OID), OID_template, base_index); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(test_OID, sizeof(test_OID), OID_template, "%i", base_index); + if (nut_snmp_get(test_OID) == NULL) { base_index++; } @@ -2506,19 +2459,7 @@ static int guesstimate_template_count(snmp_info_t *su_info_p) /* Now, actually iterate */ for (base_count = 0 ; ; base_count++) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(test_OID, sizeof(test_OID), OID_template, base_index + base_count); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(test_OID, sizeof(test_OID), OID_template, "%i", base_index + base_count); if (nut_snmp_get(test_OID) == NULL) break; } @@ -2604,20 +2545,8 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ /* Device 1 ("device.0", whole daisychain) needs no * special processing */ cur_nut_index = cur_template_number; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - su_info_p->info_type, cur_nut_index); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + su_info_p->info_type, "%i", cur_nut_index); } } else if (!strncmp(type, "outlet", 6)) /* Outlet and outlet groups templates */ @@ -2625,15 +2554,6 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ /* Get the index of the current template instance */ cur_nut_index = cur_template_number; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif /* Special processing for daisychain */ if (daisychain_enabled == TRUE) { /* Device(s) 1-N (master + slave(s)) need to append 'device.x' */ @@ -2643,18 +2563,19 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ strcat(&tmp_buf[0], su_info_p->info_type); upsdebugx(4, "FORMATTING STRING = %s", &tmp_buf[0]); - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - &tmp_buf[0], current_device_number, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + &tmp_buf[0], "%i%i", + current_device_number, cur_nut_index); } else { /* FIXME: daisychain-whole, what to do? */ - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - su_info_p->info_type, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + su_info_p->info_type, "%i", cur_nut_index); } } else { - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - su_info_p->info_type, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + su_info_p->info_type, "%i", cur_nut_index); } } else if (!strncmp(type, "ambient", 7)) @@ -2679,18 +2600,19 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ strcat(&tmp_buf[0], su_info_p->info_type); upsdebugx(4, "FORMATTING STRING = %s", &tmp_buf[0]); - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - &tmp_buf[0], current_device_number, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + &tmp_buf[0], "%i%i", + current_device_number, cur_nut_index); } else { /* FIXME: daisychain-whole, what to do? */ - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - su_info_p->info_type, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + su_info_p->info_type, "%i", cur_nut_index); } } else { - snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, - su_info_p->info_type, cur_nut_index); + snprintf_dynamic((char*)cur_info_p.info_type, SU_INFOSIZE, + su_info_p->info_type, "%i", cur_nut_index); } } else @@ -2700,14 +2622,14 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ if ((cur_info_p.dfl != NULL) && (strstr(su_info_p->dfl, "%i") != NULL)) { cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE); - snprintf((char *)cur_info_p.dfl, SU_INFOSIZE, su_info_p->dfl, cur_nut_index); + snprintf_dynamic((char *)cur_info_p.dfl, SU_INFOSIZE, su_info_p->dfl, "%i", cur_nut_index); } if (cur_info_p.OID != NULL) { /* Special processing for daisychain */ if (!strncmp(type, "device", 6)) { if (current_device_number > 0) { - snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, current_device_number + device_template_offset); + snprintf_dynamic((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, "%i", current_device_number + device_template_offset); } /*else * FIXME: daisychain-whole, what to do? @@ -2720,26 +2642,30 @@ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_ * the formatting info for it are in 1rst or 2nd position */ if (daisychain_enabled == TRUE) { if (su_info_p->flags & SU_TYPE_DAISY_1) { - snprintf((char *)cur_info_p.OID, SU_INFOSIZE, - su_info_p->OID, current_device_number + device_template_offset, cur_template_number); + snprintf_dynamic((char *)cur_info_p.OID, SU_INFOSIZE, + su_info_p->OID, "%i%i", + current_device_number + device_template_offset, + cur_template_number); } else if (su_info_p->flags & SU_TYPE_DAISY_2) { - snprintf((char *)cur_info_p.OID, SU_INFOSIZE, - su_info_p->OID, cur_template_number + device_template_offset, + snprintf_dynamic((char *)cur_info_p.OID, SU_INFOSIZE, + su_info_p->OID, "%i%i", + cur_template_number + device_template_offset, current_device_number - device_template_offset); } else { /* Note: no device daisychain templating (SU_TYPE_DAISY_MASTER_ONLY)! */ - snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, cur_template_number); + snprintf_dynamic((char *)cur_info_p.OID, SU_INFOSIZE, + su_info_p->OID, "%i", + cur_template_number); } } else { - snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, cur_template_number); + snprintf_dynamic((char *)cur_info_p.OID, SU_INFOSIZE, + su_info_p->OID, "%i", + cur_template_number); } } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif /* add instant commands to the info database. */ if (SU_TYPE(su_info_p) == SU_TYPE_CMD) { @@ -3072,19 +2998,8 @@ static int process_phase_data(const char* type, long *nb_phases, snmp_info_t *su * formatting string) that needs to be adapted! */ if (strchr(tmp_info_p->OID, '%') != NULL) { upsdebugx(2, "Found template, need to be adapted"); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char*)tmpOID, SU_INFOSIZE, tmp_info_p->OID, current_device_number + device_template_offset); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char*)tmpOID, SU_INFOSIZE, tmp_info_p->OID, + "%i", current_device_number + device_template_offset); } else { /* Otherwise, just point at what we found */ @@ -3428,20 +3343,8 @@ bool_t su_ups_get(snmp_info_t *su_info_p) __func__, tmp_info_p->OID); /* adapt the OID */ if (su_info_p->OID != NULL) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char *)tmp_info_p->OID, SU_INFOSIZE, su_info_p->OID, - current_device_number + device_template_offset); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char *)tmp_info_p->OID, SU_INFOSIZE, su_info_p->OID, + "%i", current_device_number + device_template_offset); upsdebugx(3, "%s: OID %s adapted into %s", __func__, su_info_p->OID, tmp_info_p->OID); @@ -3925,20 +3828,8 @@ static int su_setOID(int mode, const char *varname, const char *val) (strstr(tmp_info_p->dfl, "%i") != NULL)) { su_info_p->dfl = (char *)xmalloc(SU_INFOSIZE); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf((char *)su_info_p->dfl, SU_INFOSIZE, tmp_info_p->dfl, - item_number); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic((char *)su_info_p->dfl, SU_INFOSIZE, tmp_info_p->dfl, + "%i", item_number); } /* adapt the OID */ if (su_info_p->OID != NULL) { @@ -3955,15 +3846,6 @@ static int su_setOID(int mode, const char *varname, const char *val) * these outlet | outlet groups also include formatting info, * so we have to check if the daisychain is enabled, and if * the formatting info for it are in 1rst or 2nd position */ -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif if (daisychain_enabled == TRUE) { /* Note: daisychain_enabled == TRUE means that we have * daisychain template. However: @@ -3978,20 +3860,22 @@ static int su_setOID(int mode, const char *varname, const char *val) daisychain_offset = 1; if (su_info_p->flags & SU_TYPE_DAISY_1) { - snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, - daisychain_device_number - daisychain_offset, item_number); + snprintf_dynamic((char *)su_info_p->OID, SU_INFOSIZE, + tmp_info_p->OID, "%i%i", + daisychain_device_number - daisychain_offset, + item_number); } else { - snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, - item_number, daisychain_device_number - daisychain_offset); + snprintf_dynamic((char *)su_info_p->OID, SU_INFOSIZE, + tmp_info_p->OID, "%i%i", + item_number, + daisychain_device_number - daisychain_offset); } } else { - snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, item_number); + snprintf_dynamic((char *)su_info_p->OID, SU_INFOSIZE, + tmp_info_p->OID, "%i", item_number); } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif } /* else, don't return STAT_SET_INVALID for mode==SU_MODE_SETVAR since we * can be setting a server side variable! */ diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index 0b312c92e5..35661359a9 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -29,7 +29,7 @@ */ #define DRIVER_NAME "Generic HID driver" -#define DRIVER_VERSION "0.54" +#define DRIVER_VERSION "0.55" #define HU_VAR_WAITBEFORERECONNECT "waitbeforereconnect" @@ -2303,19 +2303,7 @@ static int ups_infoval_set(hid_info_t *item, double value) dstate_setinfo(item->info_type, "%s", nutvalue); } else { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - dstate_setinfo(item->info_type, item->dfl, value); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + dstate_setinfo_dynamic(item->info_type, item->dfl, "%f", value); } return 1; From 84404b99dcb6df8a85e009753bf71c3fda8df559 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 23:02:46 +0200 Subject: [PATCH 10/19] drivers/nutdrv_qx_bestups.c: bestups_batt_packs(): range-check and properly cast the value, and harden with snprintf_dynamic() [#2450] Signed-off-by: Jim Klimov --- drivers/nutdrv_qx_bestups.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/nutdrv_qx_bestups.c b/drivers/nutdrv_qx_bestups.c index dc4ee1b919..c7d4882f8e 100644 --- a/drivers/nutdrv_qx_bestups.c +++ b/drivers/nutdrv_qx_bestups.c @@ -539,25 +539,20 @@ static int bestups_batt_runtime(item_t *item, char *value, const size_t valuelen static int bestups_batt_packs(item_t *item, char *value, const size_t valuelen) { item_t *unskip; + long l; if (strspn(item->value, "0123456789 ") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, strtol(item->value, NULL, 10)); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + l = strtol(item->value, NULL, 10); + if (l < 0 || l > INT_MAX) { + upsdebugx(2, "%s: value out of range [%s: %s]", __func__, item->info_type, item->value); + return -1; + } + + snprintf_dynamic(value, valuelen, item->dfl, "%d", (int)l); /* Unskip battery.packs setvar */ unskip = find_nut_info("battery.packs", QX_FLAG_SETVAR, 0); From 56b9a727e1703fd4f6348fc7f3fa3db7dd2c9fec Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 23:03:27 +0200 Subject: [PATCH 11/19] drivers/nutdrv_qx_bestups.c: bestups_get_pins_shutdown_mode(): comment the odd conversion, and harden with snprintf_dynamic() [#2450] Signed-off-by: Jim Klimov --- drivers/nutdrv_qx_bestups.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/nutdrv_qx_bestups.c b/drivers/nutdrv_qx_bestups.c index c7d4882f8e..e8033dffeb 100644 --- a/drivers/nutdrv_qx_bestups.c +++ b/drivers/nutdrv_qx_bestups.c @@ -585,19 +585,12 @@ static int bestups_get_pins_shutdown_mode(item_t *item, char *value, const size_ } pins_shutdown_mode = (int)l; -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif - snprintf(value, valuelen, item->dfl, pins_shutdown_mode); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + /* NOTE: Mapping table has "%.0f" for R/W of this concept's value, + * meaning zero digits after the decimal point (could as well be + * an int right away?) + * TODO: Someone with the device should check replacement by "%d". + */ + snprintf_dynamic(value, valuelen, item->dfl, "%.0f", (double)pins_shutdown_mode); /* We were not asked by the user to change the value */ if ((item->qxflags & QX_FLAG_NONUT) && !getval(item->info_type)) From c4cfa87a42c58546335fdd06a98bb1df7ff3632e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 1 Jun 2024 23:23:24 +0200 Subject: [PATCH 12/19] drivers/nutdrv_qx_blazer-common.c: blazer_process_command() for "test.battery.start" might vary by applicable formatting strings [#2450] Signed-off-by: Jim Klimov --- drivers/nutdrv_qx_blazer-common.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/nutdrv_qx_blazer-common.c b/drivers/nutdrv_qx_blazer-common.c index cd4ea4a0ff..4736dc00c8 100644 --- a/drivers/nutdrv_qx_blazer-common.c +++ b/drivers/nutdrv_qx_blazer-common.c @@ -329,7 +329,26 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) delay = delay / 60; - snprintf(value, valuelen, item->command, delay); + /* In various mapping tables, "%02d" is prevalent; actual + * value is range-checked above to fit into a typical int + */ + if (validate_formatting_string(item->command, "%d", -1) >= 0) { + /* The most likely case, should not cause debug-log + * noise for most end-users when missing the check */ + snprintf_dynamic(value, valuelen, item->command, "%d", (int)delay); + } else { + if (validate_formatting_string(item->command, "", -1) >= 0) { + /* A few mappings seem to just request the test + * without parameters, so the second check is + * for that eventuality + */ + snprintf(value, valuelen, "%s", item->command); + } else { + /* Finally try the actual long int (complaining + * with default verbosity==1 if a bad fit) */ + snprintf_dynamic(value, valuelen, item->command, "%ld", delay); + } + } } else { From 3b7a01bdeba4656272599c5c6b535d38bab45f92 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 01:38:31 +0200 Subject: [PATCH 13/19] tools/nut-scanner/nutscan-serial.c: Harden NUT work with strings by switching to snprintf_dynamic() instead of hushing potential flaws with macros [#2450] Signed-off-by: Jim Klimov --- tools/nut-scanner/Makefile.am | 4 ++-- tools/nut-scanner/nutscan-serial.c | 16 ++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/tools/nut-scanner/Makefile.am b/tools/nut-scanner/Makefile.am index db2e645b09..03502c49d9 100644 --- a/tools/nut-scanner/Makefile.am +++ b/tools/nut-scanner/Makefile.am @@ -89,7 +89,7 @@ endif HAVE_WINDOWS # object .so names would differ) # # libnutscan version information -libnutscan_la_LDFLAGS += -version-info 2:5:0 +libnutscan_la_LDFLAGS += -version-info 2:6:0 # libnutscan exported symbols regex # WARNING: Since the library includes parts of libcommon (as much as needed @@ -100,7 +100,7 @@ libnutscan_la_LDFLAGS += -version-info 2:5:0 # copies of "nut_debug_level" making fun of our debug-logging attempts. # One solution to tackle if needed for those cases would be to make some # dynamic/shared libnutcommon (etc.) -libnutscan_la_LDFLAGS += -export-symbols-regex '^(nutscan_|nut_debug_level|s_upsdebugx|max_threads|curr_threads|nut_report_config_flags|upsdebugx_report_search_paths|nut_prepare_search_paths)' +libnutscan_la_LDFLAGS += -export-symbols-regex '^(nutscan_|nut_debug_level|s_upsdebugx|max_threads|curr_threads|nut_report_config_flags|upsdebugx_report_search_paths|nut_prepare_search_paths|snprintf_dynamic)' libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include \ $(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers diff --git a/tools/nut-scanner/nutscan-serial.c b/tools/nut-scanner/nutscan-serial.c index a98b4dcb29..ddcac3450a 100644 --- a/tools/nut-scanner/nutscan-serial.c +++ b/tools/nut-scanner/nutscan-serial.c @@ -198,22 +198,10 @@ char ** nutscan_get_serial_ports_list(const char *ports_range) } for (current_port = start_port; current_port <= stop_port; current_port++) { -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic push -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif -#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY -#pragma GCC diagnostic ignored "-Wformat-security" -#endif /* We actually have a format string in the name, * see the device_portname[] definition above */ - snprintf(str_tmp, sizeof(str_tmp), cur_device->name, - current_port); -#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL -#pragma GCC diagnostic pop -#endif + snprintf_dynamic(str_tmp, sizeof(str_tmp), cur_device->name, + "%c", current_port); ports_list = add_port(ports_list, str_tmp); } From d00e73766d31116266c15caa418bda081f243b3e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 01:39:57 +0200 Subject: [PATCH 14/19] tools/nut-scanner/nutscan-serial.c: add /dev/cua* patterns for different platforms Signed-off-by: Jim Klimov --- tools/nut-scanner/nutscan-serial.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/nut-scanner/nutscan-serial.c b/tools/nut-scanner/nutscan-serial.c index ddcac3450a..4f939418ef 100644 --- a/tools/nut-scanner/nutscan-serial.c +++ b/tools/nut-scanner/nutscan-serial.c @@ -61,6 +61,8 @@ static device_portname_t device_portname[] = { #endif #ifdef NUT_PLATFORM_SOLARIS { "/dev/tty%c", 'a', 'z' }, + { "/dev/cua/%c", 'a', 'z' }, + { "/dev/cua%c", '0', '9' }, #endif #ifdef NUT_PLATFORM_AIX { "/dev/tty%c", '0', '9' }, @@ -68,6 +70,13 @@ static device_portname_t device_portname[] = { #ifdef NUT_PLATFORM_LINUX { "/dev/ttyS%c", '0', '9' }, { "/dev/ttyUSB%c", '0', '9' }, + { "/dev/cua%c", '0', '9' }, +#endif +#ifdef NUT_PLATFORM_OPENBSD + { "/dev/cua0%c", '0', '9' }, + { "/dev/cua0%c", 'a', 'f' }, + { "/dev/cuac%c", '0', '7' }, + { "/dev/cuaU%c", '0', '3' }, #endif #ifdef NUT_PLATFORM_MS_WINDOWS { "COM%c", '1', '9'}, From c18ccdb538e18da62bcdfa01f536db4df1c539ca Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 03:04:17 +0200 Subject: [PATCH 15/19] common/common.c: minimize_formatting_string(): warn in doc that this may produce invalid printf-style strings and not complain (garbage in = garbage out) [#2450] Signed-off-by: Jim Klimov --- common/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/common.c b/common/common.c index 95a9f5ce63..5e2d221f92 100644 --- a/common/common.c +++ b/common/common.c @@ -1317,6 +1317,10 @@ char * minimize_formatting_string(char *buf, size_t buflen, const char *fmt, int * and their types. * Uses a caller-specified buffer and returns a pointer to * it, or NULL upon errors. + * WARNING: Does not try to be a pedantically correct printf + * style parser and allows foolishness like "%llhhG" which + * the real methods would reject (and which would fail any + * conparison with e.g. "%G" proper). */ const char *p; char *b, inEscape; From 900d64d6fb2563312089cb535c06020bc0eec3a9 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 03:05:41 +0200 Subject: [PATCH 16/19] tests/nutlogtest.c, common/common.c: validate_formatting_string(): tolerate dynamic formats that are sub-strings and beginnings of reference (wasteful but survivable) [#2450] Signed-off-by: Jim Klimov --- common/common.c | 46 +++++++++++++++++++++++++++- tests/nutlogtest.c | 75 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 9 deletions(-) diff --git a/common/common.c b/common/common.c index 5e2d221f92..03aed57690 100644 --- a/common/common.c +++ b/common/common.c @@ -1463,7 +1463,10 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc * is in position to statically check that the actual varargs match * that reference during build. * Returns 0 if the two reference strings minimize to the same value, - * or a negative value (and sets errno) in case of errors: + * a positive value if they are sufficiently compatible (but not equal): + * 1 dynamic format is the beginning of reference format + * (and there are some ignored left-over arguments) + * ...or a negative value (and sets errno) in case of errors: * -1 for memory-related errors * -2 for minimize_formatting_string() returning NULL * (also likely memory errors) @@ -1480,6 +1483,7 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc size_t lenD = strlen(fmt_dynamic) + 1; size_t lenR = strlen(fmt_reference) + 1; char *bufD = xcalloc(lenD, sizeof(char)), *bufR = xcalloc(lenR, sizeof(char)); + size_t lenBufD; if (!bufD || !bufR) { if (bufD) @@ -1506,6 +1510,46 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc return 0; } + /* Does the reference format start with the complete + * value of the dynamic format? (so bufR is same or + * longer than bufD, and with operation just ignoring + * extra passed arguments, if any) + */ + + /* First, strip dangling non-conversion characters */ + lenBufD = strlen(bufD); + while (lenBufD > 0) { + switch (bufD[lenBufD-1]) { + case '*': + case 'i': + case 'u': + case 'f': + case 'c': + case 's': + case 'p': + case 'n': + break; + + default: + lenBufD--; + bufD[lenBufD] = '\0'; + continue; + } + break; + } + + if (!strncmp(bufD, bufR, strlen(bufD))) { + if (verbosity >= 0) + upsdebugx(verbosity, + "%s: dynamic formatting string '%s' (normalized as '%s') " + "is a subset of expected '%s' (normalized as '%s'); " + "ignoring some passed arguments but okay", + __func__, fmt_dynamic, bufD, fmt_reference, bufR); + free(bufD); + free(bufR); + return 1; + } + /* This be should not be fatal right here, but may be in the caller logic */ if (verbosity >= 0) upsdebugx(verbosity, diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index cbc597e0ac..9cdb87e598 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -84,12 +84,26 @@ int main(void) { ret++; } - if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%s%d", "Single string via dynamic format", 1) < 0) { +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat" +#endif + if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%d", "Single string via dynamic format", 1) < 0) { upsdebugx(0, "D: snprintf_dynamic() correctly reports mis-matched formats"); } else { upsdebugx(0, "E: snprintf_dynamic() wrongly reports well-matched formats"); ret++; } +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +# pragma GCC diagnostic pop +#endif + + if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%s%d", "Single string via dynamic format, plus ignored garbage", 1) < 0) { + upsdebugx(0, "E: snprintf_dynamic() wrongly reports well-matched formats"); + ret++; + } else { + upsdebugx(0, "D: snprintf_dynamic() correctly reports mis-matched formats"); + } /* Note extra non-type chars in "expected" format are stripped */ p = mkstr_dynamic(dynfmt, " %.4s %%", "Single string inlined by mkstr_dynamic()"); @@ -103,24 +117,69 @@ int main(void) { } if (1) { /* scoping */ + int res; char **p, *fmtFloat[] = { "%f", " %A", " %0.1E%% ", NULL }, - *fmtNotFloat[] = { "%f%", "%m", "$f", NULL }; + *fmtNotFloat[] = { "%s", NULL }, + /* TODO: Add conversion? More methods? */ + *fmtConvertFloatOKAY[] = { "", "%f%", "%m", "$f", NULL }, + *fmtConvertFloatTODO[] = { "%lf", "%d", NULL }, + *fmtConvertIntOKAY[] = { "", NULL }, + *fmtConvertIntTODO[] = { "%ld", "%lld", "%hd", NULL } + ; for (p = &(fmtFloat[0]); *p; p++) { - if (validate_formatting_string(*p, "Voltage: %G is not %%d", 1) < 0) { - upsdebugx(0, "E: validate_formatting_string() expecting %%f equivalent failed for: '%s'", *p); + if ((res = validate_formatting_string(*p, "Voltage: %G is not %%d", 1)) < 0) { + upsdebugx(0, "E: validate_formatting_string() expecting %%f equivalent failed (%i) for: '%s'", res, *p); ret++; } else { - upsdebugx(0, "D: validate_formatting_string() expecting %%f equivalent passed for: '%s'", *p); + upsdebugx(0, "D: validate_formatting_string() expecting %%f equivalent passed (%i) for: '%s'", res, *p); } } for (p = &(fmtNotFloat[0]); *p; p++) { - if (validate_formatting_string("%f", *p, 1) < 0) { - upsdebugx(0, "D: validate_formatting_string() expecting %%f failed (as it should have) for: '%s'", *p); + if ((res = validate_formatting_string(*p, "%f", 1)) < 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%f failed (%i) (as it should have) for: '%s'", res, *p); + } else { + upsdebugx(0, "E: validate_formatting_string() expecting %%f passed (%i) (but should not have) for: '%s'", res, *p); + ret++; + } + } + + /* Auto-conversion or other non-exact equivalence */ + for (p = &(fmtConvertFloatOKAY[0]); *p; p++) { + if ((res = validate_formatting_string(*p, "%f", 1)) > 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%f passed (%i) (non-exactly) for: '%s'", res, *p); + } else { + upsdebugx(0, "E: validate_formatting_string() expecting %%f failed (%i) for: '%s'", res, *p); + ret++; + } + } + + for (p = &(fmtConvertIntOKAY[0]); *p; p++) { + if ((res = validate_formatting_string(*p, "%d", 1)) > 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%f passed (%i) (non-exactly) for: '%s'", res, *p); + } else { + upsdebugx(0, "E: validate_formatting_string() expecting %%f failed (%i) for: '%s'", res, *p); + ret++; + } + } + + /* TODO: Make such cases safely fit */ + for (p = &(fmtConvertFloatTODO[0]); *p; p++) { + if ((res = validate_formatting_string(*p, "%f", 1)) < 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%f failed (%i) (as it should have) for: '%s'", res, *p); + } else { + upsdebugx(0, "E: validate_formatting_string() expecting %%f passed (%i) (but should not have) for: '%s'", res, *p); + ret++; + } + } + + for (p = &(fmtConvertIntTODO[0]); *p; p++) { + if ((res = validate_formatting_string(*p, "%d", 1)) < 0) { + upsdebugx(0, "D: validate_formatting_string() expecting %%d failed (%i) (as it should have) for: '%s'", res, *p); } else { - upsdebugx(0, "E: validate_formatting_string() expecting %%f passed (but should not have) for: '%s'", *p); + upsdebugx(0, "E: validate_formatting_string() expecting %%d passed (%i) (but should not have) for: '%s'", res, *p); ret++; } } From 8ccaa272d5f8e2ba0c5617a768946ccd11122d02 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 12:49:12 +0200 Subject: [PATCH 17/19] m4/ax_c_pragmas.m4: detect support for plain "-Wformat" and for "-Wformat-extra-args" [#2450] Signed-off-by: Jim Klimov --- m4/ax_c_pragmas.m4 | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index d274b129bc..271b81d57f 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -176,6 +176,60 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wdeprecated-declarations"]) ]) + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat"], + [ax_cv__pragma__gcc__diags_ignored_format], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[void func(void) { +#pragma GCC diagnostic ignored "-Wformat" +} +]], [])], + [ax_cv__pragma__gcc__diags_ignored_format=yes], + [ax_cv__pragma__gcc__diags_ignored_format=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat"]) + ]) + + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat" (outside functions)], + [ax_cv__pragma__gcc__diags_ignored_format_besidefunc], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat"]], [])], + [ax_cv__pragma__gcc__diags_ignored_format_besidefunc=yes], + [ax_cv__pragma__gcc__diags_ignored_format_besidefunc=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_besidefunc" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat" (outside functions)]) + ]) + + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-nonliteral"], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[void func(void) { +#pragma GCC diagnostic ignored "-Wformat-extra-args" +} +]], [])], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args=yes], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_extra_args" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_EXTRA_ARGS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-extra-args"]) + ]) + + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-extra-args" (outside functions)], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args_besidefunc], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-extra-args"]], [])], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args_besidefunc=yes], + [ax_cv__pragma__gcc__diags_ignored_format_extra_args_besidefunc=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_extra_args_besidefunc" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_EXTRA_ARGS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-extra-args" (outside functions)]) + ]) + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-nonliteral"], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral], [AC_COMPILE_IFELSE( From 41ce7c7c6906e0324434ec5fdac6f5ff30c545a3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 2 Jun 2024 12:52:11 +0200 Subject: [PATCH 18/19] tests/nutlogtest.c: use support for plain "-Wformat" and for "-Wformat-extra-args" in pragmas to quiesce "bogus-looking" test cases [#2450] Signed-off-by: Jim Klimov --- tests/nutlogtest.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index 9cdb87e598..4ba0ce3427 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -84,9 +84,13 @@ int main(void) { ret++; } -#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat" +#endif +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_EXTRA_ARGS) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-extra-args" #endif if (snprintf_dynamic(buf, sizeof(buf), dynfmt, "%d", "Single string via dynamic format", 1) < 0) { upsdebugx(0, "D: snprintf_dynamic() correctly reports mis-matched formats"); @@ -94,7 +98,10 @@ int main(void) { upsdebugx(0, "E: snprintf_dynamic() wrongly reports well-matched formats"); ret++; } -#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_EXTRA_ARGS) +# pragma GCC diagnostic pop +#endif +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT) # pragma GCC diagnostic pop #endif From ca46f800a7ca08fd82217c42d652ac1c55b63fa3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 4 Jun 2024 10:48:28 +0200 Subject: [PATCH 19/19] include/common.h, common/common.c, drivers/dstate.c, drivers/nutdrv_qx_blazer-common.c: define macros for minimize_formatting_string() and validate_formatting_string() verbosity argument values [#2450] Custom builds that do not want to require setting driver/tool debug levels can re-define their NUT_DYNAMICFORMATTING_DEBUG_LEVEL to e.g. 0 and see any formatting discrepancies instantly. Signed-off-by: Jim Klimov --- common/common.c | 4 ++-- drivers/dstate.c | 2 +- drivers/nutdrv_qx_blazer-common.c | 7 +++---- include/common.h | 10 ++++++++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/common/common.c b/common/common.c index 03aed57690..0b1ea1854f 100644 --- a/common/common.c +++ b/common/common.c @@ -1564,7 +1564,7 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc int vsnprintfcat_dynamic(char *dst, size_t size, const char *fmt_dynamic, const char *fmt_reference, va_list ap) { - if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { + if (!dst || size == 0 || validate_formatting_string(fmt_dynamic, fmt_reference, NUT_DYNAMICFORMATTING_DEBUG_LEVEL) < 0) { return -1; } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL @@ -1614,7 +1614,7 @@ int vsnprintf_dynamic(char *dst, size_t size, const char *fmt_dynamic, const cha /* NOTE: Not checking for NULL "dst" or its "size", this is a valid * use-case for vsnprintf() to gauge how long the string would be. */ - if (validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { + if (validate_formatting_string(fmt_dynamic, fmt_reference, NUT_DYNAMICFORMATTING_DEBUG_LEVEL) < 0) { return -1; } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL diff --git a/drivers/dstate.c b/drivers/dstate.c index b1abc8501e..2c4132df9e 100644 --- a/drivers/dstate.c +++ b/drivers/dstate.c @@ -1245,7 +1245,7 @@ int dstate_setinfo(const char *var, const char *fmt, ...) int dstate_setinfo_dynamic(const char *var, const char *fmt_dynamic, const char *fmt_reference, ...) { - if (!var || validate_formatting_string(fmt_dynamic, fmt_reference, 1) < 0) { + if (!var || validate_formatting_string(fmt_dynamic, fmt_reference, NUT_DYNAMICFORMATTING_DEBUG_LEVEL) < 0) { return -1; } else { int ret; diff --git a/drivers/nutdrv_qx_blazer-common.c b/drivers/nutdrv_qx_blazer-common.c index 4736dc00c8..2fea030569 100644 --- a/drivers/nutdrv_qx_blazer-common.c +++ b/drivers/nutdrv_qx_blazer-common.c @@ -332,12 +332,11 @@ int blazer_process_command(item_t *item, char *value, const size_t valuelen) /* In various mapping tables, "%02d" is prevalent; actual * value is range-checked above to fit into a typical int */ - if (validate_formatting_string(item->command, "%d", -1) >= 0) { - /* The most likely case, should not cause debug-log - * noise for most end-users when missing the check */ + if (validate_formatting_string(item->command, "%d", NUT_DYNAMICFORMATTING_DEBUG_LEVEL_SILENT) >= 0) { + /* The most likely case, should not cause much overhead */ snprintf_dynamic(value, valuelen, item->command, "%d", (int)delay); } else { - if (validate_formatting_string(item->command, "", -1) >= 0) { + if (validate_formatting_string(item->command, "", NUT_DYNAMICFORMATTING_DEBUG_LEVEL_SILENT) >= 0) { /* A few mappings seem to just request the test * without parameters, so the second check is * for that eventuality diff --git a/include/common.h b/include/common.h index e3bc6c9acf..97ec6881ee 100644 --- a/include/common.h +++ b/include/common.h @@ -376,6 +376,16 @@ int snprintfcat(char *dst, size_t size, const char *fmt, ...) * Consumers like the *_dynamic() methods here and in dstate typically use * "1" to make errors in code visible with any effort to troubleshoot them. */ +/* Verbosity built into the methods which call the *_formatting_*() and + * pass this value as the verbosity variable argument. It is anticipated + * that some custom builds can define it to e.g. 0 to see discrepancies + * at run-time without enabling any debug verbosity: */ +#ifndef NUT_DYNAMICFORMATTING_DEBUG_LEVEL +# define NUT_DYNAMICFORMATTING_DEBUG_LEVEL 1 +#endif +/* Verbosity built into consumers that deliberately check the formatting + * strings for this or that outcome and do not want noise in the log: */ +#define NUT_DYNAMICFORMATTING_DEBUG_LEVEL_SILENT -1 char *minimize_formatting_string(char *buf, size_t buflen, const char *fmt, int verbosity); char *minimize_formatting_string_staticbuf(const char *fmt, int verbosity); int validate_formatting_string(const char *fmt_dynamic, const char *fmt_reference, int verbosity);