From 37e01e01d92dc60f6427091d90d1c66d58d4118b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 2 Oct 2023 13:15:54 +0200 Subject: [PATCH 01/29] Jenkinsfile-dynamatrix: default a MAKE=make envvar if somehow missing (strange bug for autotools build scenarios) Signed-off-by: Jim Klimov --- Jenkinsfile-dynamatrix | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index c44e565c52..ecc13835f7 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -55,7 +55,7 @@ import org.nut.dynamatrix.*; dynacfgPipeline.disableSlowBuildCIBuild_QEMU = false } - dynacfgPipeline.traceBuildShell_configureEnvvars = false// true + dynacfgPipeline.traceBuildShell_configureEnvvars = false// true dynacfgPipeline.traceBuildShell = false //true dynacfgPipeline.failFast = //true // @@ -98,7 +98,7 @@ import org.nut.dynamatrix.*; //'stageNameFunc': null, //'dynamatrixAxesLabels': [~/^OS_.+/, 'MAKE'], 'dynamatrixAxesLabels': ['OS_FAMILY', 'OS_DISTRO', 'MAKE'], - 'single': '( \${MAKE} shellcheck )', + 'single': '( if [ x"\${MAKE-}" = x ]; then echo "WARNING: MAKE is somehow unset, defaulting!" >&2; MAKE=make; fi; \${MAKE} shellcheck )', 'multi': '(cd tests && SERVICE_FRAMEWORK="selftest" SHELL_PROGS="$SHELL_PROGS" ./nut-driver-enumerator-test.sh )', 'multiLabel': 'SHELL_PROGS', 'skipShells': [ 'zsh', 'tcsh', 'csh' ] @@ -233,7 +233,10 @@ import org.nut.dynamatrix.*; if (!dynacfgPipeline.containsKey('buildPhases')) { dynacfgPipeline.buildPhases = [:] } - dynacfgPipeline.buildPhases['distcheck'] = """( eval \${CONFIG_ENVVARS} time \${MAKE} \${MAKE_OPTS} distcheck DISTCHECK_FLAGS="\${CONFIG_OPTS}" )""" + + // Imported from jenkins-dynamatrix JSL vars/autotools.groovy: + // a workaround for the cases of curiously missing MAKE envvar... + dynacfgPipeline.buildPhases['distcheck'] = """( if [ x"\${MAKE-}" = x ]; then echo "WARNING: MAKE is somehow unset, defaulting!" >&2; MAKE=make; fi; eval \${CONFIG_ENVVARS} time \${MAKE} \${MAKE_OPTS} distcheck DISTCHECK_FLAGS="\${CONFIG_OPTS}" )""" // Note: shellcheck/spellcheck/... require autotools currently // or need to be redefined with respective BUILD_TYPE From c61bfc3934de845e15ed1f49b9ba95afa371a14e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 2 Oct 2023 13:15:54 +0200 Subject: [PATCH 02/29] Jenkinsfile-dynamatrix: default a MAKE=make envvar if somehow missing (strange bug for autotools build scenarios) Signed-off-by: Jim Klimov --- Jenkinsfile-dynamatrix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index ecc13835f7..0d08fa9c98 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -234,9 +234,9 @@ import org.nut.dynamatrix.*; dynacfgPipeline.buildPhases = [:] } - // Imported from jenkins-dynamatrix JSL vars/autotools.groovy: - // a workaround for the cases of curiously missing MAKE envvar... - dynacfgPipeline.buildPhases['distcheck'] = """( if [ x"\${MAKE-}" = x ]; then echo "WARNING: MAKE is somehow unset, defaulting!" >&2; MAKE=make; fi; eval \${CONFIG_ENVVARS} time \${MAKE} \${MAKE_OPTS} distcheck DISTCHECK_FLAGS="\${CONFIG_OPTS}" )""" + // Imported from jenkins-dynamatrix JSL vars/autotools.groovy: + // a workaround for the cases of curiously missing MAKE envvar... + dynacfgPipeline.buildPhases['distcheck'] = """( if [ x"\${MAKE-}" = x ]; then echo "WARNING: MAKE is somehow unset, defaulting!" >&2; MAKE=make; fi; eval \${CONFIG_ENVVARS} time \${MAKE} \${MAKE_OPTS} distcheck DISTCHECK_FLAGS="\${CONFIG_OPTS}" )""" // Note: shellcheck/spellcheck/... require autotools currently // or need to be redefined with respective BUILD_TYPE From 6f5b491d69b6237c33f3f55e728180149f5e7409 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 11:22:37 +0200 Subject: [PATCH 03/29] tests/generic_gpio_utest.c: fix warnings about formatting strings Signed-off-by: Jim Klimov --- tests/generic_gpio_utest.c | 55 ++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/tests/generic_gpio_utest.c b/tests/generic_gpio_utest.c index 542438b021..2f8c0dccf1 100644 --- a/tests/generic_gpio_utest.c +++ b/tests/generic_gpio_utest.c @@ -24,6 +24,7 @@ #include "main.h" #include "dstate.h" #include "attribute.h" +#include "nut_stdint.h" #include "generic_gpio_utest.h" #include @@ -177,22 +178,41 @@ int main(int argc, char **argv) { cases_failed=0; fEof = 1; for(unsigned int i=0; fEof!=EOF; i++) { + char fmt[16]; do { fEof=fscanf(testData, "%s", rules); } while(strcmp("*", rules)); fEof=fscanf(testData, "%s", testType); +#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 + /* To avoid safety warnings, must provide a limit + * here (bufsize - 1), and use fixed format strings + * because scanf() does not support asterisk for + * width specifier; have to create it on the fly. + */ + snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); fEof=fscanf(testData, "%s", rules); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif if(fEof!=EOF) { if(!strcmp(testType, "rules")) { struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); jmp_result = setjmp(env_buffer); if(jmp_result) { /* test case exiting */ generic_gpio_close(upsfdtest); - printf("%s %s test rule %d [%s]\n", pass_fail[get_test_status(upsfdtest, 1)], testType, i, rules); + printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 1)], testType, i, rules); } else { /* run test case */ get_ups_rules(upsfdtest, (unsigned char *)rules); generic_gpio_close(upsfdtest); - printf("%s %s test rule %d [%s]\n", pass_fail[get_test_status(upsfdtest, 0)], testType, i, rules); + printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 0)], testType, i, rules); } } if(!strcmp(testType, "states")) { @@ -208,10 +228,10 @@ int main(int argc, char **argv) { fEof=fscanf(testData, "%d", &expectedStateValue); calculatedStateValue=calc_rule_states(upsfdtest->upsLinesStates, upsfdtest->rules[j]->cRules, upsfdtest->rules[j]->subCount, 0); if(expectedStateValue==calculatedStateValue) { - printf("%s %s test rule %d [%s]\n", pass_fail[0], testType, i, rules); + printf("%s %s test rule %u [%s]\n", pass_fail[0], testType, i, rules); cases_passed++; } else { - printf("%s %s test rule %d [%s] %s", pass_fail[1], testType, i, rules, upsfdtest->rules[j]->stateName); + printf("%s %s test rule %u [%s] %s", pass_fail[1], testType, i, rules, upsfdtest->rules[j]->stateName); for(int k=0; kupsLinesCount; k++) { printf(" %d", upsfdtest->upsLinesStates[k]); } @@ -259,7 +279,7 @@ int main(int argc, char **argv) { if(!strcmp(chargeLow,".") && !strcmp(charge,".") && currCharge!=NULL) failed=1; generic_gpio_close(upsfdtest); } - printf("%s %s test rule %d [%s] ([%s] %s %s (%s)) ([%s] %s %s)\n", + printf("%s %s test rule %u [%s] ([%s] %s %s (%s)) ([%s] %s %s)\n", pass_fail[failed], testType, i, rules, upsStatus, chargeStatus, charge, chargeLow, currUpsStatus, currChargerStatus, currCharge); @@ -275,8 +295,27 @@ int main(int argc, char **argv) { int expecting_failure, failed; char subType[NUT_GPIO_SUBTYPEBUF]; fEof=fscanf(testData, "%d", &expecting_failure); - fEof=fscanf(testData, "%s", chipNameLocal); - fEof=fscanf(testData, "%s", subType); +#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 + /* To avoid safety warnings, must provide a limit + * here (bufsize - 1), and use fixed format strings + * because scanf() does not support asterisk for + * width specifier; have to create it on the fly. + */ + snprintf(fmt, sizeof(fmt), "%%%us", NUT_GPIO_CHIPNAMEBUF-1); + fEof=fscanf(testData, fmt, chipNameLocal); + snprintf(fmt, sizeof(fmt), "%%%us", NUT_GPIO_SUBTYPEBUF-1); + fEof=fscanf(testData, fmt, subType); +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL +#pragma GCC diagnostic pop +#endif jmp_result = setjmp(env_buffer); failed = expecting_failure; if(jmp_result) { /* test case exiting */ @@ -315,7 +354,7 @@ int main(int argc, char **argv) { } upsdrv_cleanup(); } - printf("%s %s %s test rule %d [%s] %s %d\n", + printf("%s %s %s test rule %u [%s] %s %d\n", pass_fail[failed], testType, subType, i, rules, chipNameLocal, expecting_failure); if(!failed) { cases_passed++; From 436ef40985489722dbe01cd8f8a28d44797616e5 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:07:01 +0200 Subject: [PATCH 04/29] common/common.c: fix casting warnings Signed-off-by: Jim Klimov --- common/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/common.c b/common/common.c index 89991619cb..c12587ae1d 100644 --- a/common/common.c +++ b/common/common.c @@ -687,7 +687,7 @@ double difftimeval(struct timeval x, struct timeval y) result.tv_sec = x.tv_sec - y.tv_sec; result.tv_usec = x.tv_usec - y.tv_usec; - d = 0.000001 * result.tv_usec + result.tv_sec; + d = 0.000001 * (double)(result.tv_usec) + (double)(result.tv_sec); return d; } @@ -718,7 +718,7 @@ static usec_t timespec_load(const struct timespec *ts) { if (ts->tv_sec < 0 || ts->tv_nsec < 0) return USEC_INFINITY; - if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + if ((usec_t) ts->tv_sec > (UINT64_MAX - ((uint64_t)(ts->tv_nsec) / NSEC_PER_USEC)) / USEC_PER_SEC) return USEC_INFINITY; return @@ -767,7 +767,7 @@ double difftimespec(struct timespec x, struct timespec y) result.tv_sec = x.tv_sec - y.tv_sec; result.tv_nsec = x.tv_nsec - y.tv_nsec; - d = 0.000000001 * result.tv_nsec + result.tv_sec; + d = 0.000000001 * (double)(result.tv_nsec) + (double)(result.tv_sec); return d; } #endif /* HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC */ @@ -1265,7 +1265,7 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) if (((uintmax_t)ret) > (SIZE_MAX - LARGEBUF)) { goto vupslog_too_long; } - newbufsize = ret + LARGEBUF; + newbufsize = (size_t)ret + LARGEBUF; } /* else: errno, e.g. ERANGE printing: * "...(34 => Result too large)" */ if (nut_debug_level > 0) { From 0d54fb7a38bd85a7eaf8d3b92f73c5c1eb118aec Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:44:26 +0200 Subject: [PATCH 05/29] clients/upssched.c: fix casting warnings Signed-off-by: Jim Klimov --- clients/upssched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/upssched.c b/clients/upssched.c index 4b8e9c4ba9..029736bf07 100644 --- a/clients/upssched.c +++ b/clients/upssched.c @@ -959,7 +959,7 @@ static void start_daemon(TYPE_FD lockfd) if (d > 0 && d < 0.2) { d = (1.0 - d) * 1000000.0; upsdebugx(5, "Enforcing a throttling sleep: %f usec", d); - usleep(d); + usleep((useconds_t)d); } } } From 19245e5992cb6c7c226ca8d43bbb125fec4f2cf3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:44:51 +0200 Subject: [PATCH 06/29] drivers/dummy-ups.c: fix casting warnings Signed-off-by: Jim Klimov --- drivers/dummy-ups.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dummy-ups.c b/drivers/dummy-ups.c index 8a58242bce..3b4be2436c 100644 --- a/drivers/dummy-ups.c +++ b/drivers/dummy-ups.c @@ -130,7 +130,7 @@ void upsdrv_initinfo(void) /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING) - dstate_setaux(item->info_type, item->info_len); + dstate_setaux(item->info_type, (long)item->info_len); } } @@ -578,7 +578,7 @@ static int setvar(const char *varname, const char *val) /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING) - dstate_setaux(item->info_type, item->info_len); + dstate_setaux(item->info_type, (long)item->info_len); } else { From 2a05d516b8bda6d09608e4264e49e24cd4f8715d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:45:50 +0200 Subject: [PATCH 07/29] drivers/main.c: fix portability of chown() used as chgrp() Initial implementation passed -1 as uid to have it not changed. Not all OSes support that behavior. Signed-off-by: Jim Klimov --- drivers/main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/main.c b/drivers/main.c index c48e291ef7..b75ebaf83d 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -2276,19 +2276,27 @@ int main(int argc, char **argv) } else { struct stat statbuf; mode_t mode; - if (chown(sockname, -1, grp->gr_gid)) { - upsdebugx(1, "WARNING: chown failed: %s", + + if (stat(sockname, &statbuf)) { + upsdebugx(1, "WARNING: stat for chown failed: %s", strerror(errno) ); allOk = 0; + } else { + /* Here we do a portable chgrp() essentially: */ + if (chown(sockname, statbuf.st_uid, grp->gr_gid)) { + upsdebugx(1, "WARNING: chown failed: %s", + strerror(errno) + ); + allOk = 0; + } } + /* Refresh file info */ if (stat(sockname, &statbuf)) { /* Logically we'd fail chown above if file - * does not exist or is not accessible, but - * practically we only need stat for chmod - */ - upsdebugx(1, "WARNING: stat failed: %s", + * does not exist or is not accessible */ + upsdebugx(1, "WARNING: stat for chmod failed: %s", strerror(errno) ); allOk = 0; From 2b640e37f805c719ecc307a8e6ac25a2689ae39c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:47:08 +0200 Subject: [PATCH 08/29] drivers/main.c: fix indentation Signed-off-by: Jim Klimov --- drivers/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/main.c b/drivers/main.c index b75ebaf83d..64112635d7 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -1945,10 +1945,10 @@ int main(int argc, char **argv) upslogx(LOG_INFO, "Request to killpower via running driver returned code %d", cmdret); if (cmdret == 0) /* Note: many drivers would abort with - * "shutdown not supported" at this - * point... we would too, but later - * and at a higher time/processing cost. - */ + * "shutdown not supported" at this + * point... we would too, but later + * and at a higher time/processing cost. + */ exit (EXIT_SUCCESS); /* else fall through to legacy handling */ } From 2bcb7031ab58675103fd389fa6784cb3340f8f8d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:49:55 +0200 Subject: [PATCH 09/29] drivers/main.c: fix cmdret=upsdrvquery_oneshot() as a generally ssize_t value Signed-off-by: Jim Klimov --- drivers/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/main.c b/drivers/main.c index 64112635d7..cefb6cdd5c 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -1920,7 +1920,7 @@ int main(int argc, char **argv) * approach (kill sibling if needed, recapture device, * command it...) */ - int cmdret = -1; + ssize_t cmdret = -1; struct timeval tv; /* Post the query and wait for reply */ @@ -1942,7 +1942,7 @@ int main(int argc, char **argv) if (cmdret < 0) { upsdebugx(1, "Socket dialog with the other driver instance: %s", strerror(errno)); } else { - upslogx(LOG_INFO, "Request to killpower via running driver returned code %d", cmdret); + upslogx(LOG_INFO, "Request to killpower via running driver returned code %" PRIiSIZE, cmdret); if (cmdret == 0) /* Note: many drivers would abort with * "shutdown not supported" at this @@ -1966,7 +1966,7 @@ int main(int argc, char **argv) if (cmd && !strcmp(cmd, SIGCMD_RELOAD_OR_ERROR)) #endif /* WIN32 */ { /* Not a signal, but a socket protocol action */ - int cmdret = -1; + ssize_t cmdret = -1; char buf[LARGEBUF]; struct timeval tv; @@ -1982,11 +1982,11 @@ int main(int argc, char **argv) upslog_with_errno(LOG_ERR, "Socket dialog with the other driver instance"); } else { /* TODO: handle buf reply contents */ - upslogx(LOG_INFO, "Request to reload-or-error returned code %d", cmdret); + upslogx(LOG_INFO, "Request to reload-or-error returned code %" PRIiSIZE, cmdret); } /* exit((cmdret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); */ - exit((cmdret < 0) ? 255 : cmdret); + exit(((cmdret < 0) || (((uintmax_t)cmdret) > ((uintmax_t)INT_MAX))) ? 255 : (int)cmdret); } #ifndef WIN32 From 16a5c27dcc05072926fa0d10d4cd977b3f148b79 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:53:18 +0200 Subject: [PATCH 10/29] drivers/upsdrvquery.c: fix casting warnings Signed-off-by: Jim Klimov --- drivers/upsdrvquery.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/upsdrvquery.c b/drivers/upsdrvquery.c index 3f273e5d19..05f54564ce 100644 --- a/drivers/upsdrvquery.c +++ b/drivers/upsdrvquery.c @@ -324,7 +324,7 @@ ssize_t upsdrvquery_read_timeout(udq_pipe_conn_t *conn, struct timeval tv) { ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf) { size_t buflen = strlen(buf); #ifndef WIN32 - int ret; + ssize_t ret; #else DWORD bytesWritten = 0; BOOL result = FALSE; @@ -384,7 +384,7 @@ ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { char *buf; upsdrvquery_read_timeout(conn, tv); gettimeofday(&now, NULL); - if (difftimeval(now, start) > (tv.tv_sec + 0.000001 * tv.tv_usec)) { + if (difftimeval(now, start) > ((double)(tv.tv_sec) + 0.000001 * (double)(tv.tv_usec))) { upsdebugx(5, "%s: requested timeout expired", __func__); break; } @@ -414,7 +414,7 @@ ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { } /* Diminishing timeouts for read() */ - tv.tv_usec -= difftimeval(now, start); + tv.tv_usec -= (suseconds_t)(difftimeval(now, start)); while (tv.tv_usec < 0) { tv.tv_sec--; tv.tv_usec = 1000000 + tv.tv_usec; // Note it is negative @@ -563,7 +563,7 @@ ssize_t upsdrvquery_request( continue; } - if (difftimeval(now, start) > (tv.tv_sec + 0.000001 * tv.tv_usec)) { + if (difftimeval(now, start) > ((double)(tv.tv_sec) + 0.000001 * (double)(tv.tv_usec))) { upsdebugx(5, "%s: timed out waiting for expected response", __func__); return -1; From 858f5ff455cb5c3fb46a88731d4b1a50e0be19bf Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 14:55:38 +0200 Subject: [PATCH 11/29] drivers/clone.c: fix casting warnings Signed-off-by: Jim Klimov --- drivers/clone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clone.c b/drivers/clone.c index c12cc55d4b..9f963b09a6 100644 --- a/drivers/clone.c +++ b/drivers/clone.c @@ -570,7 +570,7 @@ void upsdrv_updateinfo(void) if (ups.timer.shutdown >= 0) { - ups.timer.shutdown -= difftime(now, last_poll); + ups.timer.shutdown -= (suseconds_t)(difftime(now, last_poll)); if (ups.timer.shutdown < 0) { const char *val; @@ -589,7 +589,7 @@ void upsdrv_updateinfo(void) } else if (ups.timer.start >= 0) { if (online) { - ups.timer.start -= difftime(now, last_poll); + ups.timer.start -= (suseconds_t)(difftime(now, last_poll)); } else { ups.timer.start = ondelay; } From e502c2e73b541c5a8fe5fda4144268067b033b02 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 23:20:03 +0200 Subject: [PATCH 12/29] Add a fallback inet_ntop() implementation Needed for tools/nut-scanner/scan_xml_http.c on MinGW cross-builds Signed-off-by: Jim Klimov --- common/wincompat.c | 190 +++++++++++++++++++++++++++++- configure.ac | 51 +++++++- include/wincompat.h | 4 + tools/nut-scanner/scan_xml_http.c | 3 + 4 files changed, 244 insertions(+), 4 deletions(-) diff --git a/common/wincompat.c b/common/wincompat.c index 4d3467e3d5..745b0bf9e3 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -22,6 +22,17 @@ #include "wincompat.h" #include "nut_stdint.h" +#if ! HAVE_INET_PTON +# include +# include +# if HAVE_WINSOCK2_H +# include +# endif +# if HAVE_WS2TCPIP_H +# include +# endif +#endif + #if (0) extern int errno; #endif @@ -204,6 +215,181 @@ const char* inet_ntop(int af, const void* src, char* dst, size_t cnt) } #endif /* HAVE_INET_NTOP */ +#if ! HAVE_INET_PTON +/* Fallback implementation of inet_pton() for systems that lack it, + * such as older versions of Windows (including MinGW builds that do + * not specifically target _WIN32_WINNT or newer). + * + * Based on code attributed to Paul Vixie, 1996, + * sourced from https://stackoverflow.com/a/15370175/4715872 + */ + +#define NS_INADDRSZ sizeof(struct in_addr) /* 4 */ +#define NS_IN6ADDRSZ sizeof(struct in6_addr) /* 16 */ +#define NS_INT16SZ sizeof(uint16_t) /* 2 */ + +static int inet_pton4(const char *src, void *dst) +{ + uint8_t tmp[NS_INADDRSZ], *tp; /* for struct in_addr *dst */ + + int saw_digit = 0; + int octets = 0; + int ch; + + *(tp = tmp) = 0; + + while ((ch = *src++) != '\0') + { + if (ch >= '0' && ch <= '9') + { + uint32_t n = *tp * 10 + (ch - '0'); + + if (saw_digit && *tp == 0) + return 0; + + if (n > 255) + return 0; + + *tp = n; + if (!saw_digit) + { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } + else + return 0; + } + if (octets < 4) + return 0; + + memcpy(dst, tmp, NS_INADDRSZ); + + return 1; +} + +static int inet_pton6(const char *src, void *dst) +{ + static const char xdigits[] = "0123456789abcdef"; + uint8_t tmp[NS_IN6ADDRSZ]; /* for struct in6_addr *dst */ + + uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ); + uint8_t *endp = tp + NS_IN6ADDRSZ; + uint8_t *colonp = NULL; + + const char *curtok = NULL; + int saw_xdigit = 0; + uint32_t val = 0; + int ch; + + /* Leading :: requires some special handling. */ + if (*src == ':') + { + if (*++src != ':') + return 0; + } + + curtok = src; + + while ((ch = tolower(*src++)) != '\0') + { + const char *pch = strchr(xdigits, ch); + if (pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return 0; + saw_xdigit = 1; + continue; + } + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) + return 0; + colonp = tp; + continue; + } + else if (*src == '\0') + { + return 0; + } + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, (char*) tp) > 0) + { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return 0; + } + if (saw_xdigit) + { + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + } + if (colonp != NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return 0; + + for (i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return 0; + + memcpy(dst, tmp, NS_IN6ADDRSZ); + + return 1; +} + +int inet_pton(int af, const char *src, void *dst) +{ + switch (af) + { + case AF_INET: + return inet_pton4(src, dst); + case AF_INET6: + return inet_pton6(src, dst); + default: + return -1; + } +} +#endif /* ! HAVE_INET_PTON */ + /* "system" call seems to handle path with blank name incorrectly */ int win_system(const char * command) { @@ -1448,9 +1634,9 @@ speed_t cfgetospeed(const struct termios *t) return t->c_ospeed; } -#else +#else /* !WIN32 */ /* Just avoid: ISO C forbids an empty translation unit [-Werror=pedantic] */ int main (int argc, char ** argv); -#endif +#endif /* WIN32 */ diff --git a/configure.ac b/configure.ac index 313870565a..6d9976456b 100644 --- a/configure.ac +++ b/configure.ac @@ -1171,8 +1171,55 @@ AS_IF([test x"${ac_cv_func_inet_ntop}" = xyes], [AC_DEFINE([HAVE_INET_NTOP], 1, [defined if system has the inet_ntop() method])], [AC_MSG_WARN([Required C library routine inet_ntop() not found]) AS_CASE([${target_os}], - [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] - ) + [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] + ) + ] + ) + +AC_CACHE_CHECK([for inet_pton() with IPv4 and IPv6 support], + [ac_cv_func_inet_pton], + [AC_LANG_PUSH([C]) + dnl e.g. add "-lws2_32" for mingw builds + dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above + SAVED_LIBS="$LIBS" + LIBS="$LIBS $NETLIBS" + AX_RUN_OR_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#if HAVE_WINDOWS_H +# undef inline +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# if HAVE_WINSOCK2_H +# include +# endif +# if HAVE_WS2TCPIP_H +# include +# endif +#else +# include +#endif +#include +]], + [[/* int inet_pton(int af, const char *src, char *dst); */ +struct in_addr ipv4; +struct in6_addr ipv6; +printf("%i", inet_pton(AF_INET, "1.2.3.4", &ipv4)); +printf("%i", inet_pton(AF_INET6, "::1", &ipv6)) +/* autoconf adds ";return 0;" */ +]])], + [ac_cv_func_inet_pton=yes], [ac_cv_func_inet_pton=no] + ) + AC_LANG_POP([C]) + LIBS="$SAVED_LIBS" +]) +AS_IF([test x"${ac_cv_func_inet_pton}" = xyes], + [AC_DEFINE([HAVE_INET_PTON], 1, [defined if system has the inet_pton() method])], + [AC_MSG_WARN([Required C library routine inet_pton() not found]) + AS_CASE([${target_os}], + [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] + ) ] ) diff --git a/include/wincompat.h b/include/wincompat.h index c2fa2f8c1c..d9b9cc8458 100644 --- a/include/wincompat.h +++ b/include/wincompat.h @@ -99,6 +99,10 @@ const char* inet_ntop(int af, const void* src, char* dst, size_t cnt); # endif #endif +#if ! HAVE_INET_PTON +int inet_pton(int af, const char *src, void *dst); +#endif + /* from the MSDN getaddrinfo documentation : */ #define EAI_AGAIN WSATRY_AGAIN #define EAI_BADFLAGS WSAEINVAL diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index b9ebcdb907..6348a9bad7 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -44,6 +44,9 @@ on Windows 2000 and older versions */ #include #include +# if ! HAVE_INET_PTON +# include "wincompat.h" /* fallback inet_ntop where needed */ +# endif #endif #include From 717a4f34b975e590d7a37b87bf9388e978a1790b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 3 Oct 2023 23:50:55 +0200 Subject: [PATCH 13/29] drivers/apcupsd-ups.c: port bits of poll.h to have this buildable on older WIN32 Signed-off-by: Jim Klimov --- drivers/apcupsd-ups.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/apcupsd-ups.c b/drivers/apcupsd-ups.c index cf6443f385..772b618c95 100644 --- a/drivers/apcupsd-ups.c +++ b/drivers/apcupsd-ups.c @@ -31,7 +31,22 @@ # include /* nfds_t */ #else typedef unsigned long int nfds_t; -#endif + +# ifndef POLLRDNORM +# define POLLRDNORM 0x0100 +# endif +# ifndef POLLRDBAND +# define POLLRDBAND 0x0200 +# endif +# ifndef POLLIN +# define POLLIN (POLLRDNORM | POLLRDBAND) +# endif +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +}; +#endif /* !HAVE_POLL_H */ #include "main.h" #include "apcupsd-ups.h" From a0ab7219c8adb26802e255cf9d47e581706d209d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 5 Oct 2023 00:02:23 +0200 Subject: [PATCH 14/29] include/wincompat.h: comment correct portable arg type for inet_ntop() Signed-off-by: Jim Klimov --- include/wincompat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wincompat.h b/include/wincompat.h index d9b9cc8458..c5178d05c9 100644 --- a/include/wincompat.h +++ b/include/wincompat.h @@ -95,7 +95,7 @@ int sktclose(int fh); */ const char* inet_ntop(int af, const void* src, char* dst, int cnt); # else -const char* inet_ntop(int af, const void* src, char* dst, size_t cnt); +const char* inet_ntop(int af, const void* src, char* dst, size_t /* socklen_t */ cnt); # endif #endif From 5d1236b52cf2b2c72a4560803018f087b2029da4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 5 Oct 2023 00:11:50 +0200 Subject: [PATCH 15/29] m4/ax_run_or_link_ifelse.m4: make more effort to detect undefined-ness of methods Signed-off-by: Jim Klimov --- m4/ax_run_or_link_ifelse.m4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/m4/ax_run_or_link_ifelse.m4 b/m4/ax_run_or_link_ifelse.m4 index 0e36c7efa2..994994b015 100644 --- a/m4/ax_run_or_link_ifelse.m4 +++ b/m4/ax_run_or_link_ifelse.m4 @@ -12,10 +12,16 @@ dnl # [ACTION-IF-CROSS-COMPILING = RUNTIME-ERROR]) dnl # ------------------------------------------------------- AC_DEFUN([AX_RUN_OR_LINK_IFELSE], [ + myCFLAGS="$CFLAGS" + myCXXFLAGS="$CXXFLAGS" + CFLAGS="$myCFLAGS -Werror -Werror=implicit-function-declaration" + CXXFLAGS="$myCXXFLAGS -Werror -Werror=implicit-function-declaration" AC_RUN_IFELSE([$1], [$2], [$3], [ AC_MSG_WARN([Current build is a cross-build, so not running test binaries, just linking them]) AC_LINK_IFELSE([$1], [$2], [$3]) ] ) + CFLAGS="$myCFLAGS" + CXXFLAGS="$myCXXFLAGS" ]) From 6aed0ee139604e0c9a583974504043d4e66a22ee Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 5 Oct 2023 00:19:44 +0200 Subject: [PATCH 16/29] configure.ac: detect availability of struct pollfd Signed-off-by: Jim Klimov --- configure.ac | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/configure.ac b/configure.ac index 6d9976456b..66821dde42 100644 --- a/configure.ac +++ b/configure.ac @@ -1223,6 +1223,51 @@ AS_IF([test x"${ac_cv_func_inet_pton}" = xyes], ] ) +AC_CACHE_CHECK([for struct pollfd], + [ac_cv_struct_pollfd], + [AC_LANG_PUSH([C]) + dnl e.g. add "-lws2_32" for mingw builds + dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above + SAVED_LIBS="$LIBS" + LIBS="$LIBS $NETLIBS" + AX_RUN_OR_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#if HAVE_WINDOWS_H +# undef inline +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# if HAVE_WINSOCK2_H +# include +# endif +# if HAVE_WS2TCPIP_H +# include +# endif +#else +# include +#endif +#include +]], + [[ +struct pollfd pfd; +pfd.fd = 0; +/* autoconf adds ";return 0;" */ +]])], + [ac_cv_struct_pollfd=yes], [ac_cv_struct_pollfd=no] + ) + AC_LANG_POP([C]) + LIBS="$SAVED_LIBS" +]) +AS_IF([test x"${ac_cv_struct_pollfd}" = xyes], + [AC_DEFINE([HAVE_STRUCT_POLLFD], 1, [defined if system has the struct pollfd type])], + [AC_MSG_WARN([Required C library type struct pollfd not found]) + AS_CASE([${target_os}], + [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] + ) + ] + ) + dnl ---------------------------------------------------------------------- dnl Check for python binary program names per language version dnl to embed into scripts and Make rules From 51388550374de04b68b26cdc0d9026e6892373be Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 5 Oct 2023 00:20:11 +0200 Subject: [PATCH 17/29] drivers/apcupsd-ups.c: use detected availability of struct pollfd to define or not the fallback Signed-off-by: Jim Klimov --- drivers/apcupsd-ups.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/apcupsd-ups.c b/drivers/apcupsd-ups.c index 772b618c95..82bc3af631 100644 --- a/drivers/apcupsd-ups.c +++ b/drivers/apcupsd-ups.c @@ -41,11 +41,14 @@ typedef unsigned long int nfds_t; # ifndef POLLIN # define POLLIN (POLLRDNORM | POLLRDBAND) # endif +# if ! HAVE_STRUCT_POLLFD typedef struct pollfd { SOCKET fd; short events; short revents; -}; +} pollfd_t; +# define HAVE_STRUCT_POLLFD 1 +# endif #endif /* !HAVE_POLL_H */ #include "main.h" From 7632ef3d37a891af5532947b4626b3d86d9710af Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 6 Oct 2023 05:30:32 +0200 Subject: [PATCH 18/29] tests/generic_gpio_utest.c: more fscanf() width warnings Signed-off-by: Jim Klimov --- tests/generic_gpio_utest.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/generic_gpio_utest.c b/tests/generic_gpio_utest.c index 2f8c0dccf1..be324d05a4 100644 --- a/tests/generic_gpio_utest.c +++ b/tests/generic_gpio_utest.c @@ -179,10 +179,6 @@ int main(int argc, char **argv) { fEof = 1; for(unsigned int i=0; fEof!=EOF; i++) { char fmt[16]; - do { - fEof=fscanf(testData, "%s", rules); - } while(strcmp("*", rules)); - fEof=fscanf(testData, "%s", testType); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif @@ -198,7 +194,13 @@ int main(int argc, char **argv) { * width specifier; have to create it on the fly. */ snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); - fEof=fscanf(testData, "%s", rules); + do { + fEof=fscanf(testData, fmt, rules); + } while(strcmp("*", rules)); + snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(testType)-1); + fEof=fscanf(testData, fmt, testType); + snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); + fEof=fscanf(testData, fmt, rules); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif From dfbf5e918c6d85b66f629bd598069cc380e435c6 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 6 Oct 2023 15:54:11 +0200 Subject: [PATCH 19/29] Jenkinsfile-dynamatrix: enable tracing for fightwarn branches Signed-off-by: Jim Klimov --- Jenkinsfile-dynamatrix | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index 0d08fa9c98..c2f591a1c7 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -55,8 +55,12 @@ import org.nut.dynamatrix.*; dynacfgPipeline.disableSlowBuildCIBuild_QEMU = false } - dynacfgPipeline.traceBuildShell_configureEnvvars = false// true - dynacfgPipeline.traceBuildShell = false //true + dynacfgPipeline.traceBuildShell_configureEnvvars = false // true + dynacfgPipeline.traceBuildShell = false // true + if ( env?.BRANCH_NAME ==~ /.*fightwarn.*/ ) { + dynacfgPipeline.traceBuildShell_configureEnvvars = true // false + dynacfgPipeline.traceBuildShell = true // false + } dynacfgPipeline.failFast = //true // false From ba9d3da03f2dbcc3735d45afde1821e407581574 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 7 Oct 2023 16:47:34 +0200 Subject: [PATCH 20/29] Jenkinsfile-dynamatrix: warn about lack of dynacfgPipeline.configureEnvvars when we "Investigate envvars" Signed-off-by: Jim Klimov --- Jenkinsfile-dynamatrix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index c2f591a1c7..2a804da0c4 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -253,7 +253,8 @@ import org.nut.dynamatrix.*; def dsbcClone = dsbc.clone() stage('Investigate envvars (Autotools DEBUG)') { - echo "Running default custom build for '${stageNameClone}' ==> ${dsbcClone.toString()}" + echo "Running default custom build for '${stageNameClone}' ==> ${dsbcClone.toString()}" + + (dynacfgPipeline?.configureEnvvars ? "" : " (note: has no dynacfgPipeline.configureEnvvars)") // Trick about endianness via ELF binary header picked up from https://serverfault.com/a/749469/490516 sh label: 'Inspect initial envvars', script: """ hostname; date -u; uname -a echo "LONG_BIT:`getconf LONG_BIT` WORD_BIT:`getconf WORD_BIT`" || true @@ -282,7 +283,8 @@ set | sort -n """ def dsbcClone = dsbc.clone() stage('Investigate envvars (CI_Build DEBUG)') { - echo "Running default custom build for '${stageNameClone}' ==> ${dsbcClone.toString()}" + echo "Running default custom build for '${stageNameClone}' ==> ${dsbcClone.toString()}" + + (dynacfgPipeline?.configureEnvvars ? "" : " (note: has no dynacfgPipeline.configureEnvvars)") // Trick about endianness via ELF binary header picked up from https://serverfault.com/a/749469/490516 sh label: 'Inspect initial envvars', script: """ hostname; date -u; uname -a echo "LONG_BIT:`getconf LONG_BIT` WORD_BIT:`getconf WORD_BIT`" || true From 9b98822a38436207f8d7f40354da3fd8e005dc02 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 7 Oct 2023 15:31:56 +0200 Subject: [PATCH 21/29] tests/generic_gpio_utest.c: avoid NULL deref in printf() on some platforms Signed-off-by: Jim Klimov --- tests/generic_gpio_utest.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/generic_gpio_utest.c b/tests/generic_gpio_utest.c index be324d05a4..93da57399f 100644 --- a/tests/generic_gpio_utest.c +++ b/tests/generic_gpio_utest.c @@ -284,7 +284,9 @@ int main(int argc, char **argv) { printf("%s %s test rule %u [%s] ([%s] %s %s (%s)) ([%s] %s %s)\n", pass_fail[failed], testType, i, rules, upsStatus, chargeStatus, charge, chargeLow, - currUpsStatus, currChargerStatus, currCharge); + NUT_STRARG(currUpsStatus), + NUT_STRARG(currChargerStatus), + NUT_STRARG(currCharge)); if(!failed) { cases_passed++; } else { From a457355a38fee691b386d86104db176874cfd4dc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 8 Oct 2023 16:59:00 +0200 Subject: [PATCH 22/29] Jenkinsfile-dynamatrix: hush down groovy debug verbosity, use BRANCH_NAME patterns as the default toggle to be loud and slow Signed-off-by: Jim Klimov --- Jenkinsfile-dynamatrix | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index 2a804da0c4..c8fcb5b80d 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -57,10 +57,14 @@ import org.nut.dynamatrix.*; dynacfgPipeline.traceBuildShell_configureEnvvars = false // true dynacfgPipeline.traceBuildShell = false // true - if ( env?.BRANCH_NAME ==~ /.*fightwarn.*/ ) { - dynacfgPipeline.traceBuildShell_configureEnvvars = true // false - dynacfgPipeline.traceBuildShell = true // false - } + + //if (false) // <<< (Un-)comment away in select runs/branches + //if (true) // <<< (Un-)comment away in select runs/branches + if ( env?.BRANCH_NAME ==~ /.*fightwarn-verbose.*/ ) + { + dynacfgPipeline.traceBuildShell_configureEnvvars = true // false + dynacfgPipeline.traceBuildShell = true // false + } dynacfgPipeline.failFast = //true // false @@ -1272,14 +1276,15 @@ def stageNameFunc_ShellcheckCustom(DynamatrixSingleBuildConfig dsbc) { /////////////////////////////////////////////////////////////////////////// - // Hacky big switch for a max debug option - if (true) - if (false) - { +// Hacky big switch for a max debug option +//if (true) // <<< (Un-)comment away in select runs/branches +//if (false) // <<< (Un-)comment away in select runs/branches +if ( env?.BRANCH_NAME ==~ /.*verbose.*/ ) +{ dynamatrixGlobalState.enableDebugTrace = true dynamatrixGlobalState.enableDebugErrors = true dynamatrixGlobalState.enableDebugMilestones = true dynamatrixGlobalState.enableDebugMilestonesDetails = true - } +} dynamatrixPipeline(dynacfgBase, dynacfgPipeline) From 935fef2835adf28dcd895b970141e92017595851 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 8 Oct 2023 18:41:09 +0200 Subject: [PATCH 23/29] drivers/main.c: follow TOCTOU analysis suggestions about file permissions check and enforcement Signed-off-by: Jim Klimov --- drivers/main.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/main.c b/drivers/main.c index cefb6cdd5c..919355fda9 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -2257,6 +2257,12 @@ int main(int argc, char **argv) ) { #ifndef WIN32 int allOk = 1; + /* Use file descriptor, not name, to first check and then manipulate permissions: + * https://cwe.mitre.org/data/definitions/367.html + * https://wiki.sei.cmu.edu/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification + */ + TYPE_FD fd = ERROR_FD; + /* Tune group access permission to the pipe, * so that upsd can access it (using the * specified or retained default group): @@ -2273,18 +2279,28 @@ int main(int argc, char **argv) group, strerror(errno) ); allOk = 0; + goto sockname_ownership_finished; } else { struct stat statbuf; mode_t mode; - if (stat(sockname, &statbuf)) { + if (INVALID_FD((fd = open(sockname, O_RDWR | O_APPEND)))) { + upsdebugx(1, "WARNING: opening socket file for stat/chown failed: %s", + strerror(errno) + ); + allOk = 0; + /* Can not proceed with ops below */ + goto sockname_ownership_finished; + } + + if (fstat(fd, &statbuf)) { upsdebugx(1, "WARNING: stat for chown failed: %s", strerror(errno) ); allOk = 0; } else { /* Here we do a portable chgrp() essentially: */ - if (chown(sockname, statbuf.st_uid, grp->gr_gid)) { + if (fchown(fd, statbuf.st_uid, grp->gr_gid)) { upsdebugx(1, "WARNING: chown failed: %s", strerror(errno) ); @@ -2293,7 +2309,7 @@ int main(int argc, char **argv) } /* Refresh file info */ - if (stat(sockname, &statbuf)) { + if (fstat(fd, &statbuf)) { /* Logically we'd fail chown above if file * does not exist or is not accessible */ upsdebugx(1, "WARNING: stat for chmod failed: %s", @@ -2305,7 +2321,7 @@ int main(int argc, char **argv) mode = statbuf.st_mode; mode |= S_IWGRP; mode |= S_IRGRP; - if (chmod(sockname, mode)) { + if (fchmod(fd, mode)) { upsdebugx(1, "WARNING: chmod failed: %s", strerror(errno) ); @@ -2314,6 +2330,12 @@ int main(int argc, char **argv) } } +sockname_ownership_finished: + if (VALID_FD(fd)) { + close(fd); + fd = ERROR_FD; + } + if (allOk) { upsdebugx(1, "Group access for this driver successfully fixed"); } else { From 4fd257e9a82d73524cd3a1f44c8b6fc65ead0e3a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 9 Oct 2023 23:07:17 +0200 Subject: [PATCH 24/29] tests/nutlogtest.c: revise include statements Signed-off-by: Jim Klimov --- tests/nutlogtest.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index 5aaad31ea8..b8b51dcf77 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -3,7 +3,7 @@ * do not crash). * * Copyright (C) - * 2020 Jim Klimov + * 2020-2023 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 @@ -19,6 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "config.h" #include "common.h" int main(void) { From 1aaff29c6706228a1fcae1c933e611f8b6aad441 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 10 Oct 2023 00:09:53 +0200 Subject: [PATCH 25/29] tests/Makefile.am: refer to nutlogtest$(EXEEXT) for clarity in dependencies Signed-off-by: Jim Klimov --- tests/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index c063f6dca2..da1c03e4bf 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,9 +24,9 @@ nutlogtest_LDADD = $(top_builddir)/common/libcommon.la if REQUIRE_NUT_STRARG check_SCRIPTS += nutlogtest-nofail.sh -CLEANFILES += nutlogtest-nofail.sh nutlogtest +CLEANFILES += nutlogtest-nofail.sh nutlogtest$(EXEEXT) nutlogtest -nutlogtest-nofail.sh: nutlogtest +nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @echo '#!/bin/sh' > $@ @echo 'echo "WARNING: Your C library requires workarounds to print NULL values!" >&2' >> $@ @echo 'echo "If nutlogtest below, or generally some NUT program, crashes with" >&2' >> $@ @@ -37,7 +37,7 @@ nutlogtest-nofail.sh: nutlogtest # NOTE: Keep the line above empty! else -TESTS += nutlogtest +TESTS += nutlogtest$(EXEEXT) endif TESTS += nuttimetest From a816677fcf0e2d7a9e8babdb82e1d8354ef19515 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 10 Oct 2023 23:14:51 +0200 Subject: [PATCH 26/29] data/driver.list.in: add CP1350PFCLCD Signed-off-by: Jim Klimov --- data/driver.list.in | 1 + 1 file changed, 1 insertion(+) diff --git a/data/driver.list.in b/data/driver.list.in index d1eb3951e2..8d9b56e0b0 100644 --- a/data/driver.list.in +++ b/data/driver.list.in @@ -236,6 +236,7 @@ "Cyber Power Systems" "ups" "3" "CP1350AVRLCD" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP1500AVRLCD" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP850PFCLCD" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/605 +"Cyber Power Systems" "ups" "3" "CP1350PFCLCD" "USB" "usbhid-ups" # https://alioth-lists.debian.net/pipermail/nut-upsuser/2023-October/013441.html "Cyber Power Systems" "ups" "3" "CP1500PFCLCD" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/cp1500pfclcd/ https://github.com/networkupstools/nut/issues/520 "Cyber Power Systems" "ups" "3" "CPJ500" "USB" "usbhid-ups" # https://www.cyberpower.com/jp/ja/product/sku/cpj500#downloads https://github.com/networkupstools/nut/issues/1403 "Cyber Power Systems" "ups" "3" "CP900AVR" "USB" "usbhid-ups" From 1a153ec3072e6e20887aadcebb3eb71c67a93270 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 10 Oct 2023 22:28:14 +0000 Subject: [PATCH 27/29] tests/generic_gpio_utest.c: avoid "error: variable might be clobbered by longjmp or vfork" [#2092] Signed-off-by: Jim Klimov --- tests/generic_gpio_utest.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/generic_gpio_utest.c b/tests/generic_gpio_utest.c index 93da57399f..329f609a44 100644 --- a/tests/generic_gpio_utest.c +++ b/tests/generic_gpio_utest.c @@ -249,10 +249,15 @@ int main(int argc, char **argv) { char chargeLow[256]; char charge[256]; struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); - int failed = 0; - const char *currUpsStatus=NULL; - const char *currChargerStatus=NULL; - const char *currCharge=NULL; + + /* "volatile" trickery to avoid the likes of: + * error: variable 'failed' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered] + * due to presence of setjmp(). + */ + int volatile failed = 0; + const char * volatile currUpsStatus = NULL; + const char * volatile currChargerStatus = NULL; + const char * volatile currCharge = NULL; get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates=xcalloc(sizeof(int),upsfdtest->upsLinesCount); From a55bcd31d42ff221d5ebdcc071f6f0c1bda382bb Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 10 Oct 2023 22:40:51 +0000 Subject: [PATCH 28/29] tests/generic_gpio_utest.c: cosmetic fixes Signed-off-by: Jim Klimov --- tests/generic_gpio_utest.c | 84 +++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/tests/generic_gpio_utest.c b/tests/generic_gpio_utest.c index 329f609a44..07a06e6d9f 100644 --- a/tests/generic_gpio_utest.c +++ b/tests/generic_gpio_utest.c @@ -55,48 +55,49 @@ void getWithoutUnderscores(char *var) { #define DESCRIPTION "modem and DNS server UPS" int get_test_status(struct gpioups_t *result, int on_fail_path) { - int expecting_failure; - int upsLinesCount; /* no of lines used in rules */ - int upsMaxLine; /* maximum line number referenced in rules */ - int rulesCount; /* rules subitem count: no of NUT states defined in rules*/ - char stateName[12]; /* NUT state name for rules in cRules */ - int subCount; /* element count in translated rules subitem */ - int ruleInt; + int expecting_failure; + int upsLinesCount; /* no of lines used in rules */ + int upsMaxLine; /* maximum line number referenced in rules */ + int rulesCount; /* rules subitem count: no of NUT states defined in rules*/ + char stateName[12]; /* NUT state name for rules in cRules */ + int subCount; /* element count in translated rules subitem */ + int ruleInt; + int i, j; - fEof=fscanf(testData, "%d", &expecting_failure); - if(on_fail_path) { + fEof = fscanf(testData, "%d", &expecting_failure); + if (on_fail_path) { if(expecting_failure) cases_failed++; else cases_passed++; return expecting_failure; } - if(!expecting_failure) { + if (!expecting_failure) { cases_failed++; printf("expecting case to fail\n"); return 1; } - fEof=fscanf(testData, "%d", &upsLinesCount); - if(result->upsLinesCount!=upsLinesCount) { + fEof = fscanf(testData, "%d", &upsLinesCount); + if (result->upsLinesCount!=upsLinesCount) { cases_failed++; printf("expecting upsLinesCount %d, got %d\n", upsLinesCount, result->upsLinesCount); return 1; } - fEof=fscanf(testData, "%d", &upsMaxLine); - if(result->upsMaxLine!=upsMaxLine) { + fEof = fscanf(testData, "%d", &upsMaxLine); + if (result->upsMaxLine!=upsMaxLine) { cases_failed++; printf("expecting rulesCount %d, got %d\n", upsMaxLine, result->upsMaxLine); return 1; } - fEof=fscanf(testData, "%d", &rulesCount); - if(result->rulesCount!=rulesCount) { + fEof = fscanf(testData, "%d", &rulesCount); + if (result->rulesCount!=rulesCount) { cases_failed++; printf("expecting rulesCount %d, got %d\n", rulesCount, result->rulesCount); return 1; } - for(int i=0; irulesCount; i++) { + for (i=0; irulesCount; i++) { fEof=fscanf(testData, "%s", stateName); if(!strcmp(result->rules[i]->stateName,stateName)) { cases_failed++; @@ -109,7 +110,7 @@ int get_test_status(struct gpioups_t *result, int on_fail_path) { printf("expecting subCount %d, got %d for rule %d\n", result->rules[i]->subCount, subCount, i); return 1; } - for(int j=0; jrules[i]->cRules[j]!=ruleInt) { cases_failed++; @@ -125,12 +126,12 @@ int get_test_status(struct gpioups_t *result, int on_fail_path) { void exit(int code) { - if (!done) { - longjmp(env_buffer, 1); - } - else { - _exit(code); - } + if (!done) { + longjmp(env_buffer, 1); + } + else { + _exit(code); + } } int main(int argc, char **argv) { @@ -138,7 +139,8 @@ int main(int argc, char **argv) { char rules[128]; char testType[128]; char testDescFileNameBuf[LARGEBUF]; - char *testDescFileName="generic_gpio_test.txt"; + char *testDescFileName = "generic_gpio_test.txt"; + unsigned int i; test_with_exit=0; @@ -177,7 +179,7 @@ int main(int argc, char **argv) { cases_passed=0; cases_failed=0; fEof = 1; - for(unsigned int i=0; fEof!=EOF; i++) { + for (i=0; fEof!=EOF; i++) { char fmt[16]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push @@ -221,15 +223,17 @@ int main(int argc, char **argv) { int expectedStateValue; int calculatedStateValue; struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); + int j; + get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates=xcalloc(sizeof(int),upsfdtest->upsLinesCount); - for(int j=0; jupsLinesCount; j++) { + for (j=0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } - for(int j=0; jrulesCount; j++) { + for (j=0; j < upsfdtest->rulesCount; j++) { fEof=fscanf(testData, "%d", &expectedStateValue); calculatedStateValue=calc_rule_states(upsfdtest->upsLinesStates, upsfdtest->rules[j]->cRules, upsfdtest->rules[j]->subCount, 0); - if(expectedStateValue==calculatedStateValue) { + if (expectedStateValue==calculatedStateValue) { printf("%s %s test rule %u [%s]\n", pass_fail[0], testType, i, rules); cases_passed++; } else { @@ -249,6 +253,7 @@ int main(int argc, char **argv) { char chargeLow[256]; char charge[256]; struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); + int j; /* "volatile" trickery to avoid the likes of: * error: variable 'failed' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered] @@ -261,17 +266,17 @@ int main(int argc, char **argv) { get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates=xcalloc(sizeof(int),upsfdtest->upsLinesCount); - for(int j=0; jupsLinesCount; j++) { + for (j = 0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } getWithoutUnderscores(upsStatus); getWithoutUnderscores(chargeStatus); getWithoutUnderscores(chargeLow); getWithoutUnderscores(charge); - if(strcmp(chargeLow, ".")) + if (strcmp(chargeLow, ".")) dstate_setinfo("battery.charge.low", "%s", chargeLow); jmp_result = setjmp(env_buffer); - if(jmp_result) { + if (jmp_result) { failed=1; generic_gpio_close(upsfdtest); } else { @@ -292,7 +297,7 @@ int main(int argc, char **argv) { NUT_STRARG(currUpsStatus), NUT_STRARG(currChargerStatus), NUT_STRARG(currCharge)); - if(!failed) { + if (!failed) { cases_passed++; } else { cases_failed++; @@ -352,12 +357,13 @@ int main(int argc, char **argv) { !dstate_getinfo("device.description") || strcmp(dstate_getinfo("device.description"), DESCRIPTION)) failed=1; } if(!strcmp(subType, "updateinfo")) { - for(int k=0; kupsLinesCount; k++) { + int k; + for(k=0; kupsLinesCount; k++) { gpioupsfd->upsLinesStates[k]=-1; } if(expecting_failure) setNextLinesReadToFail(); upsdrv_updateinfo(); - for(int k=0; kupsLinesCount && failed!=1; k++) { + for(k=0; kupsLinesCount && failed!=1; k++) { if(gpioupsfd->upsLinesStates[k]<0) failed=1; } } @@ -365,17 +371,19 @@ int main(int argc, char **argv) { } printf("%s %s %s test rule %u [%s] %s %d\n", pass_fail[failed], testType, subType, i, rules, chipNameLocal, expecting_failure); - if(!failed) { + if (!failed) { cases_passed++; } else { cases_failed++; } - vartab_free(); vartab_h = NULL; + vartab_free(); + vartab_h = NULL; } } } - printf("test_rules completed. Total cases %d, passed %d, failed %d\n", cases_passed+cases_failed, cases_passed, cases_failed); + printf("test_rules completed. Total cases %d, passed %d, failed %d\n", + cases_passed+cases_failed, cases_passed, cases_failed); fclose(testData); done = 1; } From ce37a62bf50e2b3b14b34ba37c6e79ae99d28a52 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 10 Oct 2023 23:14:29 +0000 Subject: [PATCH 29/29] clients/upsclient.c, server/netssl.c, m4/ax_c_pragmas.m4: hush -Wcast-function-type-strict due to void* vs. practical pointers with NSS method pointers [#2084] Signed-off-by: Jim Klimov --- clients/upsclient.c | 7 +++++++ m4/ax_c_pragmas.m4 | 27 +++++++++++++++++++++++++++ server/netssl.c | 7 +++++++ 3 files changed, 41 insertions(+) diff --git a/clients/upsclient.c b/clients/upsclient.c index 22604a9ada..74290cd26f 100644 --- a/clients/upsclient.c +++ b/clients/upsclient.c @@ -909,6 +909,10 @@ static int upscli_sslinit(UPSCONN_t *ups, int verifycert) return -1; } +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type-strict" +#endif if (verifycert) { status = SSL_AuthCertificateHook(ups->ssl, (SSLAuthCertificate)AuthCertificate, CERT_GetDefaultCertDB()); @@ -938,6 +942,9 @@ static int upscli_sslinit(UPSCONN_t *ups, int verifycert) nss_error("upscli_sslinit / SSL_HandshakeCallback"); return -1; } +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) +#pragma GCC diagnostic pop +#endif cert = upscli_find_host_cert(ups->host); if (cert != NULL && cert->certname != NULL) { diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index 14ecd596d3..070d82beee 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -674,6 +674,33 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" (outside functions)]) ]) + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-function-type-strict"], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[void func(void) { +#pragma GCC diagnostic ignored "-Wcast-function-type-strict" +} +]], [])], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict=yes], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict"]) + ]) + + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions)], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wcast-function-type-strict"]], [])], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc=yes], + [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions)]) + ]) + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wstrict-prototypes"], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes], [AC_COMPILE_IFELSE( diff --git a/server/netssl.c b/server/netssl.c index 7557f26624..79c5d3175f 100644 --- a/server/netssl.c +++ b/server/netssl.c @@ -356,6 +356,10 @@ void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg) return; } +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type-strict" +#endif /* Note cast to SSLAuthCertificate to prevent warning due to * bad function prototype in NSS. */ @@ -386,6 +390,9 @@ void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg) nss_error("net_starttls / SSL_ConfigSecureServer"); return; } +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) +#pragma GCC diagnostic pop +#endif status = SSL_ResetHandshake(client->ssl, PR_TRUE); if (status != SECSuccess) {