From 8cdf9918308cba544a35927a536683959f36f888 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 12:15:52 +0200 Subject: [PATCH 01/18] Revert "UPGRADING.adoc: hush the changes of PR for issue #2523 until it is in the codebase" This reverts commit d710adef2eba7003a0b42ae2d38709a7204befb4: the feature is here now. Signed-off-by: Jim Klimov --- UPGRADING.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UPGRADING.adoc b/UPGRADING.adoc index ae9612c6df..1b8fae5857 100644 --- a/UPGRADING.adoc +++ b/UPGRADING.adoc @@ -43,8 +43,8 @@ Changes from 2.8.2 to 2.8.3 - Numerous changes to `nut-scanner` and symbols that its `libnutscan.so` delivers have caused a library version bump. New methods have been added - in a (hopefully) backwards compatible manner. [issue #2244 and numerous - PRs for it] + and one structure (`nutscan_ipmi_t`) updated in a (hopefully) backwards + compatible manner. [PR #2523, issue #2244 and numerous PRs for it] - Internal API change for `sendsignalpid()` and `sendsignalfn()` methods, which can impact NUT forks which build using `libcommon.la` and similar From 00cf4ec550ade516ed33a1c2d583d7f6dee6dddc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 11:45:16 +0200 Subject: [PATCH 02/18] tools/nut-scanner/scan_ipmi.c, nut-scan.h, nutscan-init.c, nut-scanner.c, NEWS.adoc: implement parallel scanning for remote IPMI controllers [#2523] Signed-off-by: Jim Klimov --- NEWS.adoc | 2 + tools/nut-scanner/nut-scan.h | 19 +- tools/nut-scanner/nut-scanner.c | 1 + tools/nut-scanner/nutscan-init.c | 1 + tools/nut-scanner/scan_ipmi.c | 393 +++++++++++++++++++++++++++++-- 5 files changed, 382 insertions(+), 34 deletions(-) diff --git a/NEWS.adoc b/NEWS.adoc index e674d73787..4d492f0309 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -151,6 +151,8 @@ installed. subnets with too many bits available for the host address part (avoiding millions of scans in the extreme cases). [issue #2244, issue #2511, PR #2509, PR #2513, PR #2517] + * implemented parallel scanning for IPMI bus, otherwise default scan for + all supported buses with `-m auto` takes unbearably long. [#2523] * bumped version of `libnutscan` to 2.5.2, it now includes a few more methods and symbols from `libcommon`. [issue #2244, PR #2509] diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index f87a9e8206..22d951bd8b 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -83,7 +83,7 @@ extern "C" { #ifdef HAVE_PTHREAD # if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) -extern size_t max_threads, curr_threads, max_threads_netxml, max_threads_oldnut, max_threads_netsnmp; +extern size_t max_threads, curr_threads, max_threads_netxml, max_threads_oldnut, max_threads_netsnmp, max_threads_ipmi; # endif # ifdef HAVE_PTHREAD_TRYJOIN @@ -110,16 +110,17 @@ typedef struct nutscan_snmp { } nutscan_snmp_t; /* IPMI structure */ -/* Settings for OutofBand (remote) connection */ +/* Settings for Out-of-Band (remote) connection */ typedef struct nutscan_ipmi { - char* username; /* IPMI 1.5 and 2.0 */ - char* password; /* IPMI 1.5 and 2.0 */ - int authentication_type; /* IPMI 1.5 */ - int cipher_suite_id; /* IPMI 2.0 */ - char* K_g_BMC_key; /* IPMI 2.0, optional key for 2 key auth. */ - int privilege_level; /* for both */ + char* username; /* IPMI 1.5 and 2.0 */ + char* password; /* IPMI 1.5 and 2.0 */ + int authentication_type; /* IPMI 1.5 */ + int cipher_suite_id; /* IPMI 2.0 */ + char* K_g_BMC_key; /* IPMI 2.0, optional key for 2 key auth. */ + int privilege_level; /* for both */ unsigned int workaround_flags; /* for both */ - int ipmi_version; /* IPMI 1.5 or 2.0? */ + int ipmi_version; /* IPMI 1.5 or 2.0? */ + char* peername; /* Hostname or IP for remote scans, NULL for local device bus (populated by scanning methods) */ } nutscan_ipmi_t; /* IPMI auth defines, simply using FreeIPMI defines */ diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index 2e664f6ce1..eea548a650 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -1201,6 +1201,7 @@ int main(int argc, char *argv[]) ipmi_sec.ipmi_version = IPMI_1_5; /* default to IPMI 1.5, if not otherwise specified */ ipmi_sec.cipher_suite_id = 3; /* default to HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 */ ipmi_sec.privilege_level = IPMI_PRIVILEGE_LEVEL_ADMIN; /* should be sufficient */ + ipmi_sec.peername = NULL; /* Set the default values for XML HTTP (run_xml()) */ xml_sec.port_http = 80; diff --git a/tools/nut-scanner/nutscan-init.c b/tools/nut-scanner/nutscan-init.c index 9ef76ad023..d415299aff 100644 --- a/tools/nut-scanner/nutscan-init.c +++ b/tools/nut-scanner/nutscan-init.c @@ -106,6 +106,7 @@ size_t max_threads_netsnmp = 0; /* 10240; */ * Still, some practical limit can be useful (configurable?) * Here 0 means to not apply any special limit (beside max_threads). */ +size_t max_threads_ipmi = 0; /* limits not yet known */ # endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE */ diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 6f9d7fc685..eb00db95fe 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -26,6 +26,7 @@ #include "common.h" #include "nut-scan.h" +#include "nut_stdint.h" #ifdef WITH_IPMI @@ -115,8 +116,23 @@ static char * (*nut_ipmi_ctx_errormsg) (ipmi_ctx_t ctx); static int (*nut_ipmi_ctx_close) (ipmi_ctx_t ctx); static void (*nut_ipmi_ctx_destroy) (ipmi_ctx_t ctx); +/* This variable collects device(s) from a sequential or parallel scan, + * is returned to caller, and cleared to allow subsequent independent scans */ +static nutscan_device_t * dev_ret = NULL; +#ifdef HAVE_PTHREAD +static pthread_mutex_t dev_mutex; +#endif + +/* use explicit booleans */ +#ifndef FALSE +typedef enum ebool { FALSE = 0, TRUE } bool_t; +#else +typedef int bool_t; +#endif + /* Internal functions */ static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec); +static void * nutscan_scan_ipmi_device_thready(void * arg_sec); /* Return 0 on error; visible externally */ int nutscan_load_ipmi_library(const char *libname_path); @@ -246,6 +262,7 @@ int nutscan_load_ipmi_library(const char *libname_path) } return 1; + err: fprintf(stderr, "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", @@ -602,6 +619,40 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t return current_nut_dev; } +/* Wrap calls to nutscan_scan_ipmi_device() into semantics for parallel-able + * scanning. Returns NULL, updates global dev_ret when a scan is successful. + * FREES the caller's copy of "sec" and "peername" in it, if applicable. + */ +static void * nutscan_scan_ipmi_device_thready(void * arg_sec) +{ + nutscan_device_t *dev = NULL; + nutscan_ipmi_t *sec = (nutscan_ipmi_t *)arg_sec; + + if (sec == NULL || sec->peername == NULL) + dev = nutscan_scan_ipmi_device(NULL, NULL); + else + dev = nutscan_scan_ipmi_device(sec->peername, sec); + + if (dev) { +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&dev_mutex); +#endif + dev_ret = nutscan_add_device_to_device(dev_ret, dev); +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&dev_mutex); +#endif + } + + if (sec) { + if (sec->peername) { + free(sec->peername); + } + free(sec); + } + + return NULL; +} + /* General IPMI scan entry point: scan 1 to n devices, local or remote, * for IPMI support * Return NULL on error, or a valid nutscan_device_t otherwise */ @@ -635,27 +686,42 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip * Return NULL on error, or a valid nutscan_device_t otherwise */ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nutscan_ipmi_t * sec) { - nutscan_ip_range_list_iter_t ip; - char * ip_str = NULL; - nutscan_ipmi_t * tmp_sec; - nutscan_device_t * nut_dev = NULL; - nutscan_device_t * current_nut_dev = NULL; + bool_t pass = TRUE; /* Track that we may spawn a scanning thread */ + nutscan_device_t * result = NULL; + nutscan_ipmi_t * tmp_sec = NULL; if (!nutscan_avail_ipmi) { return NULL; } - /* Are we scanning locally, or through the network? */ - if (irl == NULL || irl->ip_ranges == NULL) - { + /* Are we scanning locally, or through the network? + * We assume the list is maintained by our methods, so should not have + * null addresses. But just in case - check for it a little tiny once. + */ + if (irl == NULL || irl->ip_ranges == NULL + || irl->ip_ranges->start_ip == NULL || irl->ip_ranges->end_ip == NULL + ) { upsdebugx(1, "%s: Local PSU scan", __func__); - current_nut_dev = nutscan_scan_ipmi_device(NULL, NULL); - } - else { - /* TODO: Port HAVE_PTHREAD_TRYJOIN etc. from other files? - * Notably, the scans below currently are only sequential - * and so very slow (5 sec per IP timeout by default). - */ + nutscan_scan_ipmi_device_thready(NULL); + } else { + /* Iterate the one or a range of IPs to scan */ + nutscan_ip_range_list_iter_t ip; + char * ip_str = NULL; + +#ifdef HAVE_PTHREAD +# ifdef HAVE_SEMAPHORE + sem_t * semaphore = nutscan_semaphore(); + sem_t semaphore_scantype_inst; + sem_t * semaphore_scantype = &semaphore_scantype_inst; +# endif /* HAVE_SEMAPHORE */ + pthread_t thread; + nutscan_thread_t * thread_array = NULL; + size_t thread_count = 0, i; +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) + size_t max_threads_scantype = max_threads_ipmi; +# endif +#endif + if (irl->ip_ranges_count == 1 && (irl->ip_ranges->start_ip == irl->ip_ranges->end_ip || !strcmp(irl->ip_ranges->start_ip, irl->ip_ranges->end_ip) @@ -666,22 +732,299 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut upsdebugx(1, "%s: Scanning remote PSU for IP address range(s): %s", __func__, nutscan_stringify_ip_ranges(irl)); } + +#ifdef HAVE_PTHREAD + pthread_mutex_init(&dev_mutex, NULL); + +# ifdef HAVE_SEMAPHORE + if (max_threads_scantype > 0) { +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE +#pragma GCC diagnostic ignored "-Wunreachable-code" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + /* Different platforms, different sizes, none fits all... */ + if (SIZE_MAX > UINT_MAX && max_threads_scantype > UINT_MAX) { +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE +#pragma GCC diagnostic pop +#endif + upsdebugx(1, + "WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()", + __func__); + max_threads_scantype = UINT_MAX - 1; + } + + upsdebugx(4, "%s: sem_init() for %" PRIuSIZE " threads", __func__, max_threads_scantype); + if (sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype)) { + upsdebug_with_errno(4, "%s: sem_init() failed", __func__); + } + } +# endif /* HAVE_SEMAPHORE */ + +#endif /* HAVE_PTHREAD */ + ip_str = nutscan_ip_ranges_iter_init(&ip, irl); while (ip_str != NULL) { - tmp_sec = malloc(sizeof(nutscan_ipmi_t)); - memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t)); +#ifdef HAVE_PTHREAD + /* NOTE: With many enough targets to scan, this can crash + * by spawning too many children; add a limit and loop to + * "reap" some already done with their work. And probably + * account them in thread_array[] as something to not wait + * for below in pthread_join()... + */ + +# ifdef HAVE_SEMAPHORE + /* Just wait for someone to free a semaphored slot, + * if none are available, and then/otherwise grab one + */ + if (thread_array == NULL) { + /* Starting point, or after a wait to complete + * all earlier runners */ + if (max_threads_scantype > 0) + sem_wait(semaphore_scantype); + sem_wait(semaphore); + pass = TRUE; + } else { + /* If successful (the lock was acquired), + * sem_wait() and sem_trywait() will return 0. + * Otherwise, -1 is returned and errno is set, + * and the state of the semaphore is unchanged. + */ + int stwST = sem_trywait(semaphore_scantype), stwS = sem_trywait(semaphore); + pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); + upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE + " curr_threads=%" PRIuSIZE + " thread_count=%" PRIuSIZE + " stwST=%d stwS=%d pass=%d", + __func__, max_threads_scantype, + curr_threads, thread_count, + stwST, stwS, pass + ); + } +# else +# ifdef HAVE_PTHREAD_TRYJOIN + /* A somewhat naive and brute-force solution for + * systems without a semaphore.h. This may suffer + * some off-by-one errors, using a few more threads + * than intended (if we race a bit at the wrong time, + * probably up to one per enabled scanner routine). + */ + + /* TOTHINK: Should there be a threadcount_mutex when + * we just read the value in if() and while() below? + * At worst we would overflow the limit a bit due to + * other protocol scanners... + */ + if (curr_threads >= max_threads + || (curr_threads >= max_threads_scantype && max_threads_scantype > 0) + ) { + upsdebugx(2, "%s: already running %" PRIuSIZE " scanning threads " + "(launched overall: %" PRIuSIZE "), " + "waiting until some would finish", + __func__, curr_threads, thread_count); + + while (curr_threads >= max_threads + || (curr_threads >= max_threads_scantype && max_threads_scantype > 0) + ) { + for (i = 0; i < thread_count ; i++) { + int ret; + + if (!thread_array[i].active) continue; + + pthread_mutex_lock(&threadcount_mutex); + upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + ret = pthread_tryjoin_np(thread_array[i].thread, NULL); + switch (ret) { + case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ + upsdebugx(5, "%s: Was thread #%" PRIuSIZE " joined earlier?", __func__, i); + break; + case 0: /* thread exited */ + if (curr_threads > 0) { + curr_threads --; + upsdebugx(4, "%s: Joined a finished thread #%" PRIuSIZE, __func__, i); + } else { + /* threadcount_mutex fault? */ + upsdebugx(0, "WARNING: %s: Accounting of thread count " + "says we are already at 0", __func__); + } + thread_array[i].active = FALSE; + break; + case EBUSY: /* actively running */ + upsdebugx(6, "%s: thread #%" PRIuSIZE " still busy (%i)", + __func__, i, ret); + break; + case EDEADLK: /* Errors with thread interactions... bail out? */ + case EINVAL: /* Errors with thread interactions... bail out? */ + default: /* new pthreads abilities? */ + upsdebugx(5, "%s: thread #%" PRIuSIZE " reported code %i", + __func__, i, ret); + break; + } + pthread_mutex_unlock(&threadcount_mutex); + } + + if (curr_threads >= max_threads + || (curr_threads >= max_threads_scantype && max_threads_scantype > 0) + ) { + usleep (10000); /* microSec's, so 0.01s here */ + } + } + upsdebugx(2, "%s: proceeding with scan", __func__); + } - if ((current_nut_dev = nutscan_scan_ipmi_device(ip_str, tmp_sec)) != NULL) { - /* Store the positive result */ - current_nut_dev = nutscan_add_device_to_device(current_nut_dev, nut_dev); + /* NOTE: No change to default "pass" in this ifdef: + * if we got to this line, we have a slot to use */ +# endif /* HAVE_PTHREAD_TRYJOIN */ +# endif /* HAVE_SEMAPHORE */ +#endif /* HAVE_PTHREAD */ + + if (pass) { + tmp_sec = malloc(sizeof(nutscan_ipmi_t)); + if (tmp_sec == NULL) { + fprintf(stderr, + "Memory allocation error\n"); + return NULL; + } + memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t)); + tmp_sec->peername = ip_str; + +#ifdef HAVE_PTHREAD + if (pthread_create(&thread, NULL, nutscan_scan_ipmi_device_thready, (void*)tmp_sec) == 0) { + nutscan_thread_t *new_thread_array; +# ifdef HAVE_PTHREAD_TRYJOIN + pthread_mutex_lock(&threadcount_mutex); + curr_threads++; +# endif /* HAVE_PTHREAD_TRYJOIN */ + + thread_count++; + new_thread_array = realloc(thread_array, + thread_count * sizeof(nutscan_thread_t)); + if (new_thread_array == NULL) { + upsdebugx(1, "%s: Failed to realloc thread array", __func__); + break; + } + else { + thread_array = new_thread_array; + } + thread_array[thread_count - 1].thread = thread; + thread_array[thread_count - 1].active = TRUE; + +# ifdef HAVE_PTHREAD_TRYJOIN + pthread_mutex_unlock(&threadcount_mutex); +# endif /* HAVE_PTHREAD_TRYJOIN */ + } +#else /* if not HAVE_PTHREAD */ + nutscan_scan_ipmi_device_thready(tmp_sec); +#endif /* if HAVE_PTHREAD */ + + /* Prepare the next iteration; note that + * nutscan_scan_ipmi_device_thready() + * takes care of freeing "tmp_sec" and its + * reference (NOT strdup!) to "ip_str" as + * peername. + */ + ip_str = nutscan_ip_ranges_iter_inc(&ip); + } else { /* if not pass -- all slots busy */ +#ifdef HAVE_PTHREAD +# ifdef HAVE_SEMAPHORE + /* Wait for all current scans to complete */ + if (thread_array != NULL) { + upsdebugx (2, "%s: Running too many scanning threads (%" + PRIuSIZE "), " + "waiting until older ones would finish", + __func__, thread_count); + for (i = 0; i < thread_count ; i++) { + int ret; + if (!thread_array[i].active) { + /* Probably should not get here, + * but handle it just in case */ + upsdebugx(0, "WARNING: %s: Midway clean-up: did not expect thread %" PRIuSIZE " to be not active", + __func__, i); + sem_post(semaphore); + if (max_threads_scantype > 0) + sem_post(semaphore_scantype); + continue; + } + thread_array[i].active = FALSE; + ret = pthread_join(thread_array[i].thread, NULL); + if (ret != 0) { + upsdebugx(0, "WARNING: %s: Midway clean-up: pthread_join() returned code %i", + __func__, ret); + } + sem_post(semaphore); + if (max_threads_scantype > 0) + sem_post(semaphore_scantype); + } + thread_count = 0; + free(thread_array); + thread_array = NULL; + } +# else +# ifdef HAVE_PTHREAD_TRYJOIN + /* TODO: Move the wait-loop for TRYJOIN here? */ +# endif /* HAVE_PTHREAD_TRYJOIN */ +# endif /* HAVE_SEMAPHORE */ +#endif /* HAVE_PTHREAD */ + } /* if: could we "pass" or not? */ + } /* while */ + +#ifdef HAVE_PTHREAD + if (thread_array != NULL) { + upsdebugx(2, "%s: all planned scans launched, waiting for threads to complete", __func__); + for (i = 0; i < thread_count; i++) { + int ret; + + if (!thread_array[i].active) continue; + + ret = pthread_join(thread_array[i].thread, NULL); + if (ret != 0) { + upsdebugx(0, "WARNING: %s: Clean-up: pthread_join() returned code %i", + __func__, ret); + } + thread_array[i].active = FALSE; +# ifdef HAVE_SEMAPHORE + sem_post(semaphore); + if (max_threads_scantype > 0) + sem_post(semaphore_scantype); +# else +# ifdef HAVE_PTHREAD_TRYJOIN + pthread_mutex_lock(&threadcount_mutex); + if (curr_threads > 0) { + curr_threads --; + upsdebugx(5, "%s: Clean-up: Joined a finished thread #%" PRIuSIZE, + __func__, i); + } else { + upsdebugx(0, "WARNING: %s: Clean-up: Accounting of thread count " + "says we are already at 0", __func__); + } + pthread_mutex_unlock(&threadcount_mutex); +# endif /* HAVE_PTHREAD_TRYJOIN */ +# endif /* HAVE_SEMAPHORE */ } - /* Prepare the next iteration */ - ip_str = nutscan_ip_ranges_iter_inc(&ip); + free(thread_array); + upsdebugx(2, "%s: all threads freed", __func__); } - } - - return nutscan_rewind_device(current_nut_dev); + pthread_mutex_destroy(&dev_mutex); + +# ifdef HAVE_SEMAPHORE + if (max_threads_scantype > 0) + sem_destroy(semaphore_scantype); +# endif /* HAVE_SEMAPHORE */ +#endif /* HAVE_PTHREAD */ + } /* end of: scan range of 1+ IP address(es), maybe in parallel */ + + result = nutscan_rewind_device(dev_ret); + dev_ret = NULL; + return result; } #else /* not WITH_IPMI */ From 687dc630b89079ca5187c8977c35ec1b470d21a8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 18:59:54 +0200 Subject: [PATCH 03/18] tools/nut-scanner/scan_*: revise "thready" scanning methods [#2511] * Clearly name "thread-ready" scanning methods that can be used standalone or from pthread_create() constraints * Settle on "thready" methods freeing caller's data (so we do not worry about doing it after the parallel loops, or at a wrong moment before) * Unify code mark-up in the files to facilitate later comparisons * Update some comments Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_eaton_serial.c | 16 +++++-- tools/nut-scanner/scan_nut.c | 24 ++++++++--- tools/nut-scanner/scan_snmp.c | 21 ++++++---- tools/nut-scanner/scan_xml_http.c | 60 +++++++++++++++++---------- 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c index b29bb6de2f..aee6af5c73 100644 --- a/tools/nut-scanner/scan_eaton_serial.c +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -380,7 +380,14 @@ static nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name) return dev; } -static void * nutscan_scan_eaton_serial_device(void * port_arg) +/* Wrap calls to actual implementations of nutscan_scan_eaton_serial_shut(), + * nutscan_scan_eaton_serial_xcp() and/or nutscan_scan_eaton_serial_q1() + * which implement the semantics of parallel-able scanning. + * Returns the device entry, updates global dev_ret when a scan is successful. + * DOES NOT FREE the caller's copy of "port_arg", unlike many similar methods + * in other scanners. + */ +static void * nutscan_scan_eaton_serial_device_thready(void * port_arg) { nutscan_device_t * dev = NULL; char* port_name = (char*) port_arg; @@ -396,6 +403,7 @@ static void * nutscan_scan_eaton_serial_device(void * port_arg) } /* Else try UTalk? */ } + return dev; } @@ -546,7 +554,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) current_port_name = serial_ports_list[current_port_nb]; #ifdef HAVE_PTHREAD - if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device, (void*)current_port_name) == 0) { + if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device_thready, (void*)current_port_name) == 0) { nutscan_thread_t *new_thread_array; # ifdef HAVE_PTHREAD_TRYJOIN pthread_mutex_lock(&threadcount_mutex); @@ -571,8 +579,10 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) # endif /* HAVE_PTHREAD_TRYJOIN */ } #else /* if not HAVE_PTHREAD */ - nutscan_scan_eaton_serial_device(current_port_name); + nutscan_scan_eaton_serial_device_thready(current_port_name); #endif /* if HAVE_PTHREAD */ + + /* Prepare the next iteration */ current_port_nb++; } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 723c8898fb..a29f39a576 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -62,6 +62,8 @@ typedef int bool_t; #endif struct scan_nut_arg { + /* String includes square brackets around host/IP + * address, and/or :port suffix (if customized so): */ char * hostname; useconds_t timeout; }; @@ -137,9 +139,14 @@ int nutscan_load_upsclient_library(const char *libname_path) lt_dlexit(); return 0; } +/* end of dynamic link library stuff */ /* FIXME: SSL support */ -static void * list_nut_devices(void * arg) +/* Performs a (parallel-able) NUT protocol scan of one remote host:port. + * Returns NULL, updates global dev_ret when a scan is successful. + * FREES the caller's copy of "nut_arg" and "hostname" in it, if applicable. + */ +static void * list_nut_devices_thready(void * arg) { struct scan_nut_arg * nut_arg = (struct scan_nut_arg*)arg; char *target_hostname = nut_arg->hostname; @@ -192,6 +199,7 @@ static void * list_nut_devices(void * arg) free(ups); return NULL; } + /* FIXME: check for duplication by getting driver.port and device.serial * for comparison with other busses results */ /* FIXME: @@ -256,6 +264,7 @@ static void * list_nut_devices(void * arg) free(target_hostname); free(nut_arg); free(ups); + return NULL; } @@ -526,7 +535,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons nut_arg->hostname = ip_dest; #ifdef HAVE_PTHREAD - if (pthread_create(&thread, NULL, list_nut_devices, (void*)nut_arg) == 0) { + if (pthread_create(&thread, NULL, list_nut_devices_thready, (void*)nut_arg) == 0) { nutscan_thread_t *new_thread_array; # ifdef HAVE_PTHREAD_TRYJOIN pthread_mutex_lock(&threadcount_mutex); @@ -550,11 +559,16 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ } -#else /* not HAVE_PTHREAD */ - list_nut_devices(nut_arg); +#else /* if not HAVE_PTHREAD */ + list_nut_devices_thready(nut_arg); #endif /* if HAVE_PTHREAD */ - /* Prepare the next iteration */ + /* Prepare the next iteration; note that + * nutscan_scan_ipmi_device_thready() + * takes care of freeing "tmp_sec" and its + * copy (note strdup!) of "ip_str" as + * hostname, possibly suffixed with a port. + */ free(ip_str); ip_str = nutscan_ip_ranges_iter_inc(&ip); } else { /* if not pass -- all slots busy */ diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 2a5358d1ab..6f971f5c5c 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -894,7 +894,11 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) return 1; } -static void * try_SysOID(void * arg) +/* Performs a (parallel-able) SNMP protocol scan of one remote host. + * Returns NULL, updates global dev_ret when a scan is successful. + * FREES the caller's copy of "sec" and "peername" in it, if applicable. + */ +static void * try_SysOID_thready(void * arg) { struct snmp_session snmp_sess; void * handle; @@ -1265,7 +1269,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, tmp_sec->peername = ip_str; #ifdef HAVE_PTHREAD - if (pthread_create(&thread, NULL, try_SysOID, (void*)tmp_sec) == 0) { + if (pthread_create(&thread, NULL, try_SysOID_thready, (void*)tmp_sec) == 0) { nutscan_thread_t *new_thread_array; # ifdef HAVE_PTHREAD_TRYJOIN pthread_mutex_lock(&threadcount_mutex); @@ -1289,14 +1293,17 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ } -#else /* not HAVE_PTHREAD */ - try_SysOID((void *)tmp_sec); +#else /* if not HAVE_PTHREAD */ + try_SysOID_thready((void *)tmp_sec); #endif /* if HAVE_PTHREAD */ - /* Prepare the next iteration */ -/* free(ip_str); */ /* Do not free() here - seems to cause a double-free instead */ + /* Prepare the next iteration; note that + * try_SysOID_thready() + * takes care of freeing "tmp_sec" and its + * reference (NOT strdup!) to "ip_str" as + * peername. + */ ip_str = nutscan_ip_ranges_iter_inc(&ip); -/* free(tmp_sec); */ } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD # ifdef HAVE_SEMAPHORE diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index db94192a26..1e46191d1e 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -182,7 +182,11 @@ static int startelm_cb(void *userdata, int parent, const char *nspace, const cha return result; } -static void * nutscan_scan_xml_http_generic(void * arg) +/* Performs a (parallel-able) NetXML protocol scan of one remote host:port. + * Returns NULL, updates global dev_ret when a scan is successful. + * FREES the caller's copy of "arg" and "hostname" in it, if applicable. + */ +static void * nutscan_scan_xml_http_thready(void * arg) { nutscan_xml_t * sec = (nutscan_xml_t *)arg; char *scanMsg = ""; @@ -221,12 +225,12 @@ static void * nutscan_scan_xml_http_generic(void * arg) usec_timeout = 5000000; /* Driver default : 5sec */ if (!nutscan_avail_xml_http) { - return NULL; + goto end_free; } if ((peerSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { fprintf(stderr, "Error creating socket\n"); - return NULL; + goto end_free; } /* FIXME : Per http://stackoverflow.com/questions/683624/udp-broadcast-on-all-interfaces @@ -237,7 +241,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) sockAddress_udp.sin_family = AF_INET; if (ip == NULL) { upsdebugx(2, - "nutscan_scan_xml_http_generic() : scanning connected network segment(s) " + "nutscan_scan_xml_http_thready() : scanning connected network segment(s) " "with a broadcast, attempt %d of %d with a timeout of %" PRIdMAX " usec", (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); sockAddress_udp.sin_addr.s_addr = INADDR_BROADCAST; @@ -246,7 +250,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) sizeof(sockopt_on)); } else { upsdebugx(2, - "nutscan_scan_xml_http_generic() : scanning IP '%s' with a unicast, " + "nutscan_scan_xml_http_thready() : scanning IP '%s' with a unicast, " "attempt %d of %d with a timeout of %" PRIdMAX " usec", ip, (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); inet_pton(AF_INET, ip, &(sockAddress_udp.sin_addr)); @@ -273,7 +277,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) timeout.tv_sec = usec_timeout / 1000000; timeout.tv_usec = usec_timeout % 1000000; - upsdebugx(5, "nutscan_scan_xml_http_generic() : sent request to %s, " + upsdebugx(5, "nutscan_scan_xml_http_thready() : sent request to %s, " "loop #%d/%d, waiting for responses", (ip ? ip : ""), (i + 1), MAX_RETRIES); while ((ret = select(peerSocket + 1, &fds, NULL, NULL, @@ -283,7 +287,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) int parserFailed; retNum ++; - upsdebugx(5, "nutscan_scan_xml_http_generic() : request to %s, " + upsdebugx(5, "nutscan_scan_xml_http_thready() : request to %s, " "loop #%d/%d, response #%d", (ip ? ip : ""), (i + 1), MAX_RETRIES, retNum); @@ -353,7 +357,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) * Does our driver support the notation? */ nut_dev->port = strdup(buf); upsdebugx(3, - "nutscan_scan_xml_http_generic(): " + "nutscan_scan_xml_http_thready(): " "Adding configuration for driver='%s' port='%s'", nut_dev->driver, nut_dev->port); dev_ret = nutscan_add_device_to_device( @@ -383,7 +387,7 @@ static void * nutscan_scan_xml_http_generic(void * arg) if (ip != NULL) { upsdebugx(2, - "nutscan_scan_xml_http_generic(): we collected one reply " + "nutscan_scan_xml_http_thready(): we collected one reply " "to unicast for %s (repsponse from %s), done", ip, string); goto end; @@ -391,24 +395,35 @@ static void * nutscan_scan_xml_http_generic(void * arg) } /* while select() responses */ if (ip == NULL && dev_ret != NULL) { upsdebugx(2, - "nutscan_scan_xml_http_generic(): we collected one round of replies " + "nutscan_scan_xml_http_thready(): we collected one round of replies " "to broadcast with no errors, done"); goto end; } } } upsdebugx(2, - "nutscan_scan_xml_http_generic(): no replies collected for %s, done", + "nutscan_scan_xml_http_thready(): no replies collected for %s, done", (ip ? ip : "")); goto end; end_abort: upsdebugx(1, - "Had to abort nutscan_scan_xml_http_generic() for %s, see fatal details above", + "Had to abort nutscan_scan_xml_http_thready() for %s, see fatal details above", (ip ? ip : "")); + end: - if (ip != NULL) /* do not free "ip", it comes from caller */ + if (ip != NULL) close(peerSocket); + +end_free: + /* free resources which come from the caller + * (in parallel runs, nobody else can reap them) + */ + if (ip != NULL) + free(ip); + if (sec != NULL) + free(sec); + return NULL; } @@ -652,7 +667,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, } #ifdef HAVE_PTHREAD - if (pthread_create(&thread, NULL, nutscan_scan_xml_http_generic, (void *)tmp_sec) == 0) { + if (pthread_create(&thread, NULL, nutscan_scan_xml_http_thready, (void*)tmp_sec) == 0) { nutscan_thread_t *new_thread_array; # ifdef HAVE_PTHREAD_TRYJOIN pthread_mutex_lock(&threadcount_mutex); @@ -676,14 +691,17 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ } -#else /* not HAVE_PTHREAD */ - nutscan_scan_xml_http_generic((void *)tmp_sec); +#else /* if not HAVE_PTHREAD */ + nutscan_scan_xml_http_thready(tmp_sec); #endif /* if HAVE_PTHREAD */ - /* Prepare the next iteration */ -/* free(ip_str); */ /* One of these free()s seems to cause a double-free instead */ + /* Prepare the next iteration; note that + * nutscan_scan_xml_http_thready() + * takes care of freeing "tmp_sec" and its + * reference (NOT strdup!) to "ip_str" as + * peername. + */ ip_str = nutscan_ip_ranges_iter_inc(&ip); -/* free(tmp_sec); */ } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD # ifdef HAVE_SEMAPHORE @@ -797,10 +815,10 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, tmp_sec->usec_timeout = usec_timeout; } - nutscan_scan_xml_http_generic(tmp_sec); + /* Note: the thready method releases the resources */ + nutscan_scan_xml_http_thready(tmp_sec); result = nutscan_rewind_device(dev_ret); dev_ret = NULL; - free(tmp_sec); return result; } From 1532831a478259d80be4b0ca230b2aeac9ff5f6d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 21:00:05 +0200 Subject: [PATCH 04/18] Introduce scripts/valgrind with helper script+data to trace memory usage [#2511] Signed-off-by: Jim Klimov --- Makefile.am | 1 + NEWS.adoc | 3 ++ docs/developers.txt | 3 ++ docs/nut.dict | 4 +- scripts/Makefile.am | 5 +- scripts/valgrind/.valgrind.supp | 96 +++++++++++++++++++++++++++++++++ scripts/valgrind/README.adoc | 16 ++++++ scripts/valgrind/valgrind.sh | 21 ++++++++ 8 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 scripts/valgrind/.valgrind.supp create mode 100644 scripts/valgrind/README.adoc create mode 100755 scripts/valgrind/valgrind.sh diff --git a/Makefile.am b/Makefile.am index 697ce342f7..0ba1eeefb5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,6 +92,7 @@ distcheck-light-man: # Make a distcheck (and check in particular) with enabled valgrind and debug info memcheck distcheck-valgrind: + @echo "See also scripts/valgrind in NUT sources for a helper tool" +$(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_VALGRIND_FLAGS)" distcheck # workaround the dist generated files that are also part of the distribution diff --git a/NEWS.adoc b/NEWS.adoc index 4d492f0309..65830dd276 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -184,6 +184,9 @@ installed. respective warnings issued by the new generations of analysis tools. [#823, #2437, link:https://github.com/networkupstools/nut-website/issues/52[nut-website issue #52]] + - added `scripts/valgrind` with a helper script and suppression file to + ignore common third-party problems. [#2511] + - 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/docs/developers.txt b/docs/developers.txt index 6c95549140..ccddee5be2 100644 --- a/docs/developers.txt +++ b/docs/developers.txt @@ -1212,6 +1212,9 @@ suspected area and then exit cleanly. valgrind will tell you if you've done anything dodgy like freeing regions twice, reading uninitialized memory, or if you've leaked memory anywhere. +See also `scripts/valgrind` in NUT sources for a helper tool and resource +files to suppress common third-party problems. + For more information, refer to the link:http://valgrind.kde.org[Valgrind] project. diff --git a/docs/nut.dict b/docs/nut.dict index 6bb3967ff3..bf82d3a5ad 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3186 utf-8 +personal_ws-1.1 en 3188 utf-8 AAC AAS ABI @@ -2594,6 +2594,7 @@ pts pty pulizzi pw +pwd pwmib px pxW @@ -2859,6 +2860,7 @@ subnets subtree sudo suid +suppressions suseconds sv svc diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 225c10f015..f777ee9073 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -25,12 +25,15 @@ EXTRA_DIST = \ upower/95-upower-hid.rules \ usb_resetter/README.adoc \ usb_resetter/nut-driver.service \ + valgrind/README.adoc \ + valgrind/.valgrind.supp \ + valgrind/valgrind.sh \ Windows/halt.c \ Windows/Makefile SUBDIRS = augeas devd hotplug installer python systemd udev ufw Solaris Windows upsdrvsvcctl -SPELLCHECK_SRC = README.adoc RedHat/README.adoc usb_resetter/README.adoc +SPELLCHECK_SRC = README.adoc RedHat/README.adoc usb_resetter/README.adoc valgrind/README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp new file mode 100644 index 0000000000..fb75ef2ea6 --- /dev/null +++ b/scripts/valgrind/.valgrind.supp @@ -0,0 +1,96 @@ +{ + + Memcheck:Param + socketcall.send(msg) + fun:send + ... +} +{ + + Memcheck:Free + fun:free + ... + fun:__libc_freeres + ... +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:pool + fun:__static_initialization_and_destruction_0 + fun:_GLOBAL__sub_I_eh_alloc.cc + ... +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:_gcry_mpi_init + fun:global_init + ... +} +{ + + Memcheck:Leak + ... + fun:CRYPTO_* + ... +} +{ + + Memcheck:Leak + ... + fun:SSL_CTX_* + ... +} +{ + + Memcheck:Leak + ... + fun:OPENSSL_* + ... +} +{ + + Memcheck:Leak + fun:*alloc + ... + fun:_dl_init + ... +} +{ + + Memcheck:Leak + fun:*alloc + ... + fun:_dl_new_object + ... +} +{ + + Memcheck:Leak + fun:*alloc + ... + fun:elf_machine_rela + ... +} +{ + + Memcheck:Leak + fun:*alloc + ... + fun:dl_open_worker + ... +} +{ + + Memcheck:Leak + fun:*alloc + ... + fun:_dlerror_run + ... +} diff --git a/scripts/valgrind/README.adoc b/scripts/valgrind/README.adoc new file mode 100644 index 0000000000..6d5866163e --- /dev/null +++ b/scripts/valgrind/README.adoc @@ -0,0 +1,16 @@ +VALGRIND resources +================== + +Helper script and suppression file to analyze NUT binaries. + +Example use-case: +---- +:; make -ks -j && LD_LIBRARY_PATH=`pwd`/clients/.libs \ + ./scripts/valgrind/valgrind.sh ./tools/nut-scanner/nut-scanner -DDDDDD -m auto +---- + +See also: + +* link:https://wiki.wxwidgets.org/Valgrind_Suppression_File_Howto[Valgrind Suppression File How-to] + - Notably, add `--gen-suppressions=all --error-limit=no` to `valgrind` + program options to generate suppression snippets diff --git a/scripts/valgrind/valgrind.sh b/scripts/valgrind/valgrind.sh new file mode 100755 index 0000000000..2bb8608125 --- /dev/null +++ b/scripts/valgrind/valgrind.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# Copyright (C) 2024 by Jim Klimov + +SCRIPTDIR="`dirname "$0"`" +SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" + +LTEXEC="" +[ -n "${LIBTOOL-}" ] || LIBTOOL="`command -v libtool`" 2>/dev/null +[ -z "${LIBTOOL}" ] || LTEXEC="${LIBTOOL} --mode=execute " + +# TODO: Also wrap tool=callgrind e.g. via $0 symlink name? + +exec ${LTEXEC} \ +valgrind \ + --tool=memcheck --verbose \ + --leak-check=full --show-reachable=yes --error-exitcode=1 --show-error-list=yes \ + --trace-children=yes --track-fds=yes --show-leak-kinds=all --track-origins=yes \ + --suppressions="${SCRIPTDIR}/.valgrind.supp" \ + ${VALGRIND_OPTIONS-} \ + "$@" From 6cb572d13731bb2e0036f555dc082c77ce98dbc6 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 19:14:18 +0200 Subject: [PATCH 05/18] common/common.c: nut_prepare_search_paths(): avoid an FD leak, and comment what we do about "dirname" with and without realpath() support Signed-off-by: Jim Klimov --- common/common.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/common/common.c b/common/common.c index f7ffee93d9..a6646de03f 100644 --- a/common/common.c +++ b/common/common.c @@ -3087,6 +3087,9 @@ void nut_prepare_search_paths(void) { dupe = 1; #if HAVE_DECL_REALPATH free((char *)dirname); + /* Have some valid value, for kicks (likely + * to be ignored in the code path below) */ + dirname = search_paths_builtin[i]; #endif break; } @@ -3097,10 +3100,17 @@ void nut_prepare_search_paths(void) { "existing unique directory: %s", __func__, count_filtered, dirname); #if !HAVE_DECL_REALPATH + /* Make a copy of table entry, else we have + * a dynamic result of realpath() made above. + */ dirname = (const char *)xstrdup(dirname); #endif filtered_search_paths[count_filtered++] = dirname; - } + } /* else: dirname was freed above (for realpath) + * or is a reference to the table entry; no need + * to free() it either way */ + + closedir(dp); } /* If we mangled this before, forget the old result: */ From f2e922917ee5d159a33b898022d830059901ea50 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 20:04:39 +0200 Subject: [PATCH 06/18] tools/nut-scanner/*.c: refactor nutscan_free() to actively lt_dlclose() the loaded library modules [#2511] Avoid some memory leak reports Signed-off-by: Jim Klimov --- tools/nut-scanner/nut-scanner.c | 2 +- tools/nut-scanner/nutscan-init.c | 78 +++++++++++++++++++++++++------ tools/nut-scanner/scan_avahi.c | 25 ++++++++++ tools/nut-scanner/scan_ipmi.c | 25 ++++++++++ tools/nut-scanner/scan_nut.c | 19 ++++++++ tools/nut-scanner/scan_snmp.c | 34 +++++++++++++- tools/nut-scanner/scan_usb.c | 27 +++++++++++ tools/nut-scanner/scan_xml_http.c | 25 ++++++++++ 8 files changed, 219 insertions(+), 16 deletions(-) diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index eea548a650..a198f526ad 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -1886,8 +1886,8 @@ int main(int argc, char *argv[]) #endif upsdebugx(1, "SCANS DONE: free common scanner resources"); - nutscan_free(); nutscan_free_ip_ranges(&ip_ranges_list); + nutscan_free(); upsdebugx(1, "SCANS DONE: EXIT_SUCCESS"); return EXIT_SUCCESS; diff --git a/tools/nut-scanner/nutscan-init.c b/tools/nut-scanner/nutscan-init.c index d415299aff..bf458ec394 100644 --- a/tools/nut-scanner/nutscan-init.c +++ b/tools/nut-scanner/nutscan-init.c @@ -41,6 +41,11 @@ # if defined HAVE_WINSOCK2_H && HAVE_WINSOCK2_H # include # endif +#endif + +/* FIXME: We may want to (also?) use lt_dlopenext(), so + * that libtool would offer platform-specific extensions */ +#ifdef WIN32 # define SOEXT ".dll" #else # ifdef NUT_PLATFORM_APPLE_OSX @@ -61,12 +66,19 @@ int nutscan_avail_snmp = 0; int nutscan_avail_usb = 0; int nutscan_avail_xml_http = 0; +/* Methods defined in scan_*.c source files */ int nutscan_load_usb_library(const char *libname_path); +int nutscan_unload_usb_library(void); int nutscan_load_snmp_library(const char *libname_path); +int nutscan_unload_snmp_library(void); int nutscan_load_neon_library(const char *libname_path); +int nutscan_unload_neon_library(void); int nutscan_load_avahi_library(const char *libname_path); +int nutscan_unload_avahi_library(void); int nutscan_load_ipmi_library(const char *libname_path); +int nutscan_unload_ipmi_library(void); int nutscan_load_upsclient_library(const char *libname_path); +int nutscan_unload_upsclient_library(void); #ifdef HAVE_PTHREAD # ifdef HAVE_SEMAPHORE @@ -586,27 +598,67 @@ void nutscan_init(void) nutscan_avail_nut_simulation = 1; } -void nutscan_free(void) +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally to scan_* modules */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath) { - if (nutscan_avail_usb) { - lt_dlexit(); + int ret = -1; + + if (avail == NULL || pdl_handle == NULL) { + upsdebugx(1, "%s: called with bad inputs, no-op", __func__); + return -2; } - if (nutscan_avail_snmp) { - lt_dlexit(); + + /* never tried/already unloaded */ + if (*pdl_handle == NULL) { + goto end; } - if (nutscan_avail_xml_http) { - lt_dlexit(); + + /* if previous init failed */ + if (*pdl_handle == (void *)1) { + goto end; } - if (nutscan_avail_avahi) { - lt_dlexit(); + + if (*avail == 0) { + upsdebugx(1, "%s: Asked to unload a module %p " + "for %s but our flag says it is not loaded", + __func__, (void *)(*pdl_handle), + (libpath && *libpath && **libpath) + ? *libpath + : ""); } - if (nutscan_avail_ipmi) { - lt_dlexit(); + + /* init has already been done */ + if (libpath && *libpath && **libpath) { + upsdebugx(1, "%s: unloading module %s", + __func__, *libpath); } - if (nutscan_avail_nut) { - lt_dlexit(); + ret = lt_dlclose(*pdl_handle); + lt_dlexit(); + +end: + *pdl_handle = NULL; + *avail = 0; + + if (libpath && *libpath) { + free(*libpath); + *libpath = NULL; } + return ret; +} + +void nutscan_free(void) +{ + nutscan_unload_usb_library(); + nutscan_unload_snmp_library(); + nutscan_unload_neon_library(); + nutscan_unload_avahi_library(); + nutscan_unload_ipmi_library(); + nutscan_unload_upsclient_library(); + #ifdef HAVE_PTHREAD /* TOTHINK: See comments near mutex/semaphore init code above */ # ifdef HAVE_SEMAPHORE diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index d7813777a4..d83174167f 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -27,6 +27,9 @@ #include "common.h" #include "nut-scan.h" +/* externally visible to nutscan-init */ +int nutscan_unload_avahi_library(void); + #ifdef WITH_AVAHI #include @@ -48,6 +51,7 @@ /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; static AvahiClient* (*nut_avahi_service_browser_get_client)(AvahiServiceBrowser *); static int (*nut_avahi_simple_poll_loop)(AvahiSimplePoll *s); @@ -91,6 +95,15 @@ static int (*nut_avahi_service_browser_free)(AvahiServiceBrowser *); static char * (*nut_avahi_address_snprint)(char *ret_s, size_t length, const AvahiAddress *a); static const AvahiPoll* (*nut_avahi_simple_poll_get)(AvahiSimplePoll *s); +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_avahi_library(void) +{ + return nutscan_unload_library(&nutscan_avail_avahi, &dl_handle, &dl_saved_libname); +} + /* return 0 on error; visible externally */ int nutscan_load_avahi_library(const char *libname_path); int nutscan_load_avahi_library(const char *libname_path) @@ -210,6 +223,10 @@ int nutscan_load_avahi_library(const char *libname_path) goto err; } + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + return 1; err: fprintf(stderr, @@ -217,6 +234,10 @@ int nutscan_load_avahi_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; } /* end of dynamic link library stuff */ @@ -600,4 +621,8 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) return NULL; } +int nutscan_unload_avahi_library(void) +{ + return 0; +} #endif /* WITH_AVAHI */ diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index eb00db95fe..867fd927ee 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -28,6 +28,9 @@ #include "nut-scan.h" #include "nut_stdint.h" +/* externally visible to nutscan-init */ +int nutscan_unload_ipmi_library(void); + #ifdef WITH_IPMI #include "upsclient.h" @@ -46,6 +49,7 @@ /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; #ifdef HAVE_FREEIPMI_11X_12X /* Functions symbols remapping */ @@ -134,6 +138,15 @@ typedef int bool_t; static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec); static void * nutscan_scan_ipmi_device_thready(void * arg_sec); +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_ipmi_library(void) +{ + return nutscan_unload_library(&nutscan_avail_ipmi, &dl_handle, &dl_saved_libname); +} + /* Return 0 on error; visible externally */ int nutscan_load_ipmi_library(const char *libname_path); int nutscan_load_ipmi_library(const char *libname_path) @@ -261,6 +274,10 @@ int nutscan_load_ipmi_library(const char *libname_path) goto err; } + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + return 1; err: @@ -269,6 +286,10 @@ int nutscan_load_ipmi_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; } /* end of dynamic link library stuff */ @@ -1048,4 +1069,8 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nu return NULL; } +int nutscan_unload_ipmi_library(void) +{ + return 0; +} #endif /* WITH_IPMI */ diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index a29f39a576..b1625ad8c6 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -37,6 +37,7 @@ /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; static int (*nut_upscli_splitaddr)(const char *buf, char **hostname, uint16_t *port); static int (*nut_upscli_tryconnect)(UPSCONN_t *ups, const char *host, uint16_t port, @@ -68,6 +69,16 @@ struct scan_nut_arg { useconds_t timeout; }; +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_upsclient_library(void); +int nutscan_unload_upsclient_library(void) +{ + return nutscan_unload_library(&nutscan_avail_nut, &dl_handle, &dl_saved_libname); +} + /* return 0 on error; visible externally */ int nutscan_load_upsclient_library(const char *libname_path); int nutscan_load_upsclient_library(const char *libname_path) @@ -129,6 +140,10 @@ int nutscan_load_upsclient_library(const char *libname_path) goto err; } + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + return 1; err: @@ -137,6 +152,10 @@ int nutscan_load_upsclient_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; } /* end of dynamic link library stuff */ diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 6f971f5c5c..57007e2d79 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -29,6 +29,9 @@ #include "nut-scan.h" #include "nut_stdint.h" +/* externally visible to nutscan-init */ +int nutscan_unload_snmp_library(void); + #ifdef WITH_SNMP #ifndef WIN32 @@ -116,6 +119,7 @@ typedef int bool_t; /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; #endif /* WITH_SNMP_STATIC */ static void (*nut_init_snmp)(const char *type); @@ -177,9 +181,23 @@ static oid *nut_usmHMAC256SHA384AuthProtocol; static oid *nut_usmHMAC384SHA512AuthProtocol; #endif +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +#ifndef WITH_SNMP_STATIC +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +#endif +int nutscan_unload_snmp_library(void) +{ +#ifdef WITH_SNMP_STATIC + return 0; +#else + return nutscan_unload_library(&nutscan_avail_snmp, &dl_handle, &dl_saved_libname); +#endif +} + /* return 0 on error; visible externally */ int nutscan_load_snmp_library(const char *libname_path); - int nutscan_load_snmp_library(const char *libname_path) { #ifdef WITH_SNMP_STATIC @@ -453,7 +471,11 @@ int nutscan_load_snmp_library(const char *libname_path) } #endif /* NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol */ -#endif /* WITH_SNMP_STATIC */ + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + +#endif /* not WITH_SNMP_STATIC */ return 1; @@ -464,6 +486,10 @@ int nutscan_load_snmp_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; #endif /* not WITH_SNMP_STATIC */ } @@ -1422,4 +1448,8 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, return NULL; } +int nutscan_unload_snmp_library(void) +{ + return 0; +} #endif /* WITH_SNMP */ diff --git a/tools/nut-scanner/scan_usb.c b/tools/nut-scanner/scan_usb.c index 164f6c7983..0b756991ca 100644 --- a/tools/nut-scanner/scan_usb.c +++ b/tools/nut-scanner/scan_usb.c @@ -26,6 +26,9 @@ #include "common.h" #include "nut-scan.h" +/* externally visible to nutscan-init */ +int nutscan_unload_usb_library(void); + #ifdef WITH_USB #include "upsclient.h" @@ -37,6 +40,8 @@ /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; + static int (*nut_usb_close)(libusb_device_handle *dev); static int (*nut_usb_get_string_simple)(libusb_device_handle *dev, int index, char *buf, size_t buflen); @@ -76,6 +81,15 @@ static int (*nut_usb_get_string_simple)(libusb_device_handle *dev, int index, static char * (*nut_usb_strerror)(void); #endif /* WITH_LIBUSB_1_0 */ +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_usb_library(void) +{ + return nutscan_unload_library(&nutscan_avail_usb, &dl_handle, &dl_saved_libname); +} + /* return 0 on error; visible externally */ int nutscan_load_usb_library(const char *libname_path); int nutscan_load_usb_library(const char *libname_path) @@ -219,6 +233,10 @@ int nutscan_load_usb_library(const char *libname_path) } #endif /* WITH_LIBUSB_1_0 */ + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + return 1; err: @@ -227,6 +245,10 @@ int nutscan_load_usb_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; } /* end of dynamic link library stuff */ @@ -663,4 +685,9 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) return NULL; } + +int nutscan_unload_usb_library(void) +{ + return 0; +} #endif /* WITH_USB */ diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index 1e46191d1e..51a92cfed2 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -30,6 +30,9 @@ #include "nut-scan.h" #include "nut_stdint.h" +/* externally visible to nutscan-init */ +int nutscan_unload_neon_library(void); + #ifdef WITH_NEON #ifndef WIN32 @@ -60,6 +63,7 @@ /* dynamic link library stuff */ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; static void (*nut_ne_xml_push_handler)(ne_xml_parser *p, ne_xml_startelm_cb *startelm, @@ -85,6 +89,15 @@ typedef enum ebool { FALSE = 0, TRUE } bool_t; typedef int bool_t; #endif +/* return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_neon_library(void) +{ + return nutscan_unload_library(&nutscan_avail_xml_http, &dl_handle, &dl_saved_libname); +} + /* return 0 on error; visible externally */ int nutscan_load_neon_library(const char *libname_path); int nutscan_load_neon_library(const char *libname_path) @@ -141,6 +154,10 @@ int nutscan_load_neon_library(const char *libname_path) goto err; } + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + return 1; err: fprintf(stderr, @@ -148,6 +165,10 @@ int nutscan_load_neon_library(const char *libname_path) libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } return 0; } @@ -845,4 +866,8 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, return NULL; } +int nutscan_unload_neon_library(void) +{ + return 0; +} #endif /* WITH_NEON */ From 240e39a610151e9937a47a37daacb0654c6065ff Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 20:16:02 +0200 Subject: [PATCH 07/18] tools/nut-scanner/scan_*.c: initialize "stwS" and "stwST" to better track semaphore usage in debugger Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_ipmi.c | 3 ++- tools/nut-scanner/scan_nut.c | 3 ++- tools/nut-scanner/scan_snmp.c | 3 ++- tools/nut-scanner/scan_xml_http.c | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 867fd927ee..ad4820a56f 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -820,7 +820,8 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut * Otherwise, -1 is returned and errno is set, * and the state of the semaphore is unchanged. */ - int stwST = sem_trywait(semaphore_scantype), stwS = sem_trywait(semaphore); + int stwST = sem_trywait(semaphore_scantype); + int stwS = sem_trywait(semaphore); pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index b1625ad8c6..4daa5207dd 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -442,7 +442,8 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons * Otherwise, -1 is returned and errno is set, * and the state of the semaphore is unchanged. */ - int stwST = sem_trywait(semaphore_scantype), stwS = sem_trywait(semaphore); + int stwST = sem_trywait(semaphore_scantype); + int stwS = sem_trywait(semaphore); pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 57007e2d79..8d98a95886 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -1201,7 +1201,8 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, * Otherwise, -1 is returned and errno is set, * and the state of the semaphore is unchanged. */ - int stwST = sem_trywait(semaphore_scantype), stwS = sem_trywait(semaphore); + int stwST = sem_trywait(semaphore_scantype); + int stwS = sem_trywait(semaphore); pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index 51a92cfed2..f6ea1042f0 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -586,7 +586,8 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, * Otherwise, -1 is returned and errno is set, * and the state of the semaphore is unchanged. */ - int stwST = sem_trywait(semaphore_scantype), stwS = sem_trywait(semaphore); + int stwST = sem_trywait(semaphore_scantype); + int stwS = sem_trywait(semaphore); pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE From 1546309f8057d14d4eaa987ac4645b92c0203f35 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 20:16:27 +0200 Subject: [PATCH 08/18] tools/nut-scanner/scan_*.c: drop remaining usage of WSAStartup() overlooked before Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_nut.c | 6 ------ tools/nut-scanner/scan_snmp.c | 6 ------ 2 files changed, 12 deletions(-) diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 4daa5207dd..3de13ef642 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -332,12 +332,6 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons # endif #endif /* HAVE_PTHREAD */ -#ifdef WIN32 - WSADATA WSAdata; - WSAStartup(2,&WSAdata); - atexit((void(*)(void))WSACleanup); -#endif - #ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 8d98a95886..d7d565c156 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -1097,12 +1097,6 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, # endif #endif /* HAVE_PTHREAD */ -#ifdef WIN32 - WSADATA WSAdata; - WSAStartup(2,&WSAdata); - atexit((void(*)(void))WSACleanup); -#endif - #ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); From c13b3b03b7c87c221284202b7254dbc5c97192bf Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 20:17:02 +0200 Subject: [PATCH 09/18] tools/nut-scanner/scan_snmp.c: track nut_initialized_snmp to only init_snmp() once per library load [#2511] Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_snmp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index d7d565c156..02b1c85298 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -121,6 +121,7 @@ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; static char *dl_saved_libname = NULL; #endif /* WITH_SNMP_STATIC */ +static int nut_initialized_snmp = 0; static void (*nut_init_snmp)(const char *type); static void (*nut_snmp_sess_init)(netsnmp_session * session); @@ -192,6 +193,7 @@ int nutscan_unload_snmp_library(void) #ifdef WITH_SNMP_STATIC return 0; #else + nut_initialized_snmp = 0; return nutscan_unload_library(&nutscan_avail_snmp, &dl_handle, &dl_saved_libname); #endif } @@ -1165,7 +1167,10 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, } /* Initialize the SNMP library */ - (*nut_init_snmp)("nut-scanner"); + if (!nut_initialized_snmp) { + (*nut_init_snmp)("nut-scanner"); + nut_initialized_snmp = 1; + } ip_str = nutscan_ip_ranges_iter_init(&ip, irl); From 5ce752c693975a2b940b2c8625c2ec096023cf10 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 20:28:44 +0200 Subject: [PATCH 10/18] tools/nut-scanner/scan_nut.c: list_nut_devices_thready(): free allocations more reliably [#2511] Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_nut.c | 58 +++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 3de13ef642..435cdab294 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -173,9 +173,9 @@ static void * list_nut_devices_thready(void * arg) uint16_t port; size_t numq, numa; const char *query[4]; - char **answer; + char **answer = NULL; char *hostname = NULL; - UPSCONN_t *ups = malloc(sizeof(*ups)); + UPSCONN_t *ups = xcalloc(1, sizeof(*ups)); nutscan_device_t * dev = NULL; size_t buf_size; @@ -188,35 +188,35 @@ static void * list_nut_devices_thready(void * arg) upsdebugx(2, "Entering %s for %s", __func__, target_hostname); if ((*nut_upscli_splitaddr)(target_hostname, &hostname, &port) != 0) { - free(target_hostname); - free(nut_arg); - free(ups); - return NULL; + /* Avoid disconnect from not connected ups */ + if (ups) { + if (ups->host) + free(ups->host); + free(ups); + } + ups = NULL; + goto end; } if ((*nut_upscli_tryconnect)(ups, hostname, port, UPSCLI_CONN_TRYSSL, &tv) < 0) { - free(target_hostname); - free(nut_arg); - free(ups); - return NULL; + /* Avoid disconnect from not connected ups */ + if (ups) { + if (ups->host) + free(ups->host); + free(ups); + } + ups = NULL; + goto end; } if ((*nut_upscli_list_start)(ups, numq, query) < 0) { - (*nut_upscli_disconnect)(ups); - free(target_hostname); - free(nut_arg); - free(ups); - return NULL; + goto end; } while ((*nut_upscli_list_next)(ups, numq, query, &numa, &answer) == 1) { /* UPS */ if (numa < 3) { - (*nut_upscli_disconnect)(ups); - free(target_hostname); - free(nut_arg); - free(ups); - return NULL; + goto end; } /* FIXME: check for duplication by getting driver.port and device.serial @@ -279,10 +279,20 @@ static void * list_nut_devices_thready(void * arg) } - (*nut_upscli_disconnect)(ups); - free(target_hostname); - free(nut_arg); - free(ups); +end: + if (ups) { + (*nut_upscli_disconnect)(ups); + if (ups->host) + free(ups->host); + free(ups); + } + + if (target_hostname) + free(target_hostname); + if (hostname) + free(hostname); + if (nut_arg) + free(nut_arg); return NULL; } From 74a13786ec49d73455f54c3a9c15ede6cc4a40a3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 21:19:57 +0200 Subject: [PATCH 11/18] tools/nut-scanner/scan_xml_http.c: close broadcast socket too, avoid FD leak [#2511] Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_xml_http.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index f6ea1042f0..23b95173e2 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -217,7 +217,7 @@ static void * nutscan_scan_xml_http_thready(void * arg) /* A NULL "ip" causes a broadcast scan; otherwise the single ip address is queried directly */ char *ip = NULL; useconds_t usec_timeout = 0; - int peerSocket; + int peerSocket = -1; int sockopt_on = 1; struct sockaddr_in sockAddress_udp; socklen_t sockAddressLength = sizeof(sockAddress_udp); @@ -433,7 +433,8 @@ static void * nutscan_scan_xml_http_thready(void * arg) (ip ? ip : "")); end: - if (ip != NULL) + /* Broadcast is also a socket! */ + if (peerSocket != -1) close(peerSocket); end_free: From 2aa229616ac1e3a4b1d27d831674992b812d0858 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 22:06:45 +0200 Subject: [PATCH 12/18] tools/nut-scanner/scan_snmp.c, scripts/valgrind/.valgrind.supp: constrain libnetsnmp leak reports [#2511] It seems that although `init_snmp()` is called once, every use of the library initializes some data which it then does not release, at least on the test system here. Signed-off-by: Jim Klimov --- scripts/valgrind/.valgrind.supp | 7 +++++++ tools/nut-scanner/scan_snmp.c | 15 ++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp index fb75ef2ea6..c92a80bb48 100644 --- a/scripts/valgrind/.valgrind.supp +++ b/scripts/valgrind/.valgrind.supp @@ -94,3 +94,10 @@ fun:_dlerror_run ... } +{ + + Memcheck:Leak + ... + fun:init_snmp_once + ... +} diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 02b1c85298..18f3e559ab 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -1057,6 +1057,15 @@ static void * try_SysOID_thready(void * arg) return NULL; } +static void init_snmp_once(void) +{ + /* Initialize the SNMP library */ + if (!nut_initialized_snmp) { + (*nut_init_snmp)("nut-scanner"); + nut_initialized_snmp = 1; + } +} + nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip, useconds_t usec_timeout, nutscan_snmp_t * sec) { @@ -1166,11 +1175,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, upsdebugx(1, "Failed to enable numeric OIDs resolution"); } - /* Initialize the SNMP library */ - if (!nut_initialized_snmp) { - (*nut_init_snmp)("nut-scanner"); - nut_initialized_snmp = 1; - } + init_snmp_once(); ip_str = nutscan_ip_ranges_iter_init(&ip, irl); From 99ba1c5050812bb399e682ca02491ad4e1301db8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 22:24:49 +0200 Subject: [PATCH 13/18] tools/nut-scanner/scan_ipmi.c, tools/nut-scanner/scan_avahi.c, scripts/valgrind/.valgrind.supp: constrain warnings about library methods [#2511] Signed-off-by: Jim Klimov --- scripts/valgrind/.valgrind.supp | 14 ++++++++++++++ tools/nut-scanner/scan_avahi.c | 32 +++++++++++++++++++------------- tools/nut-scanner/scan_ipmi.c | 7 ++++++- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp index c92a80bb48..8cacb8f338 100644 --- a/scripts/valgrind/.valgrind.supp +++ b/scripts/valgrind/.valgrind.supp @@ -101,3 +101,17 @@ fun:init_snmp_once ... } +{ + + Memcheck:Leak + ... + fun:wrap_nut_ipmi_ctx_create + ... +} +{ + + Memcheck:Leak + ... + fun:wrap_nut_avahi_client_new + ... +} diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index d83174167f..812c0f9ac1 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -530,6 +530,24 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd } } +static AvahiClient* wrap_nut_avahi_client_new(int *error) +{ + /* Allocate a new client */ +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wassign-enum" +#endif + /* It seems that avahi-common/defs.h only defines the flags in a + * manner similar to bitmask flags to request certain features, + * but lacks a value in that enum for lack of flags (unconstrained + * lookup). So we have to silence a warning here... + */ + return (*nut_avahi_client_new)((*nut_avahi_simple_poll_get)(simple_poll), 0, client_callback, NULL, error); +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) +# pragma GCC diagnostic pop +#endif +} + nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) { /* Example service publication @@ -552,19 +570,7 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) } /* Allocate a new client */ -#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wassign-enum" -#endif - /* It seems that avahi-common/defs.h only defines the flags in a - * manner similar to bitmask flags to request certain features, - * but lacks a value in that enum for lack of flags (unconstrained - * lookup). So we have to silence a warning here... - */ - client = (*nut_avahi_client_new)((*nut_avahi_simple_poll_get)(simple_poll), 0, client_callback, NULL, &error); -#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) -# pragma GCC diagnostic pop -#endif + client = wrap_nut_avahi_client_new(&error); /* Check wether creating the client object succeeded */ if (!client) { diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index ad4820a56f..44f4fd3325 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -421,6 +421,11 @@ static int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) return 0; } +static ipmi_ctx_t wrap_nut_ipmi_ctx_create(void) +{ + return (*nut_ipmi_ctx_create) (); +} + /* Check for IPMI support on a specific (local or remote) system * Return NULL on error, or a valid nutscan_device_t otherwise */ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * ipmi_sec) @@ -437,7 +442,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t } /* Initialize the FreeIPMI library. */ - if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ())) + if (!(ipmi_ctx = wrap_nut_ipmi_ctx_create())) { /* we have to force cleanup, since exit handler is not yet installed */ fprintf(stderr, "Failed to ipmi_ctx_create\n"); From bc72d5aaeebc81bde85bea47e64293cf96b33f5f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 10 Jul 2024 22:31:04 +0200 Subject: [PATCH 14/18] tools/nut-scanner/scan_snmp.c, scripts/valgrind/.valgrind.supp: constrain warnings about library methods [#2511] Signed-off-by: Jim Klimov --- scripts/valgrind/.valgrind.supp | 8 ++++++++ tools/nut-scanner/scan_snmp.c | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp index 8cacb8f338..552c56c565 100644 --- a/scripts/valgrind/.valgrind.supp +++ b/scripts/valgrind/.valgrind.supp @@ -101,6 +101,14 @@ fun:init_snmp_once ... } +{ + + Memcheck:Leak + fun:*alloc + ... + fun:wrap_nut_snmp_sess_open + ... +} { Memcheck:Leak diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 18f3e559ab..b35c645846 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -922,6 +922,12 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) return 1; } +static void * wrap_nut_snmp_sess_open(struct snmp_session *session) +{ + /* Open the session */ + return (*nut_snmp_sess_open)(session); /* establish the session */ +} + /* Performs a (parallel-able) SNMP protocol scan of one remote host. * Returns NULL, updates global dev_ret when a scan is successful. * FREES the caller's copy of "sec" and "peername" in it, if applicable. @@ -951,7 +957,7 @@ static void * try_SysOID_thready(void * arg) snmp_sess.timeout = (long)g_usec_timeout; /* Open the session */ - handle = (*nut_snmp_sess_open)(&snmp_sess); /* establish the session */ + handle = wrap_nut_snmp_sess_open(&snmp_sess); /* establish the session */ if (handle == NULL) { upsdebugx(2, "Failed to open SNMP session for %s", From e66990ffa51959132ca137c6308f307a5896382b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Jul 2024 00:40:55 +0200 Subject: [PATCH 15/18] tools/nut-scanner/scan_xml_http.c: nutscan_scan_xml_http_thready(): revise trace-logging and comment markup [#2511] Signed-off-by: Jim Klimov --- tools/nut-scanner/scan_xml_http.c | 52 ++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index 23b95173e2..ff8ca5a414 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -211,10 +211,12 @@ static void * nutscan_scan_xml_http_thready(void * arg) { nutscan_xml_t * sec = (nutscan_xml_t *)arg; char *scanMsg = ""; -/* Note: at this time the HTTP/XML scan is in fact not implemented - just the UDP part */ + /* Note: at this time the HTTP/XML scan is + * in fact not implemented - just the UDP part */ /* uint16_t port_http = 80; */ uint16_t port_udp = 4679; -/* A NULL "ip" causes a broadcast scan; otherwise the single ip address is queried directly */ + /* A NULL "ip" causes a broadcast scan; otherwise + * the single ip address is queried directly */ char *ip = NULL; useconds_t usec_timeout = 0; int peerSocket = -1; @@ -254,26 +256,27 @@ static void * nutscan_scan_xml_http_thready(void * arg) goto end_free; } -/* FIXME : Per http://stackoverflow.com/questions/683624/udp-broadcast-on-all-interfaces - * A single sendto() generates a single packet, so one must iterate all known interfaces... */ + /* FIXME : Per http://stackoverflow.com/questions/683624/udp-broadcast-on-all-interfaces + * A single sendto() generates a single packet, + * so one must iterate all known interfaces... */ #define MAX_RETRIES 3 for (i = 0; i != MAX_RETRIES ; i++) { /* Initialize socket */ sockAddress_udp.sin_family = AF_INET; if (ip == NULL) { upsdebugx(2, - "nutscan_scan_xml_http_thready() : scanning connected network segment(s) " + "%s: scanning connected network segment(s) " "with a broadcast, attempt %d of %d with a timeout of %" PRIdMAX " usec", - (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); + __func__, (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); sockAddress_udp.sin_addr.s_addr = INADDR_BROADCAST; setsockopt(peerSocket, SOL_SOCKET, SO_BROADCAST, SOCK_OPT_CAST &sockopt_on, sizeof(sockopt_on)); } else { upsdebugx(2, - "nutscan_scan_xml_http_thready() : scanning IP '%s' with a unicast, " + "%s: scanning IP '%s' with a unicast, " "attempt %d of %d with a timeout of %" PRIdMAX " usec", - ip, (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); + __func__, ip, (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout); inet_pton(AF_INET, ip, &(sockAddress_udp.sin_addr)); } sockAddress_udp.sin_port = htons(port_udp); @@ -298,9 +301,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) timeout.tv_sec = usec_timeout / 1000000; timeout.tv_usec = usec_timeout % 1000000; - upsdebugx(5, "nutscan_scan_xml_http_thready() : sent request to %s, " + upsdebugx(5, "%s: sent request to %s, " "loop #%d/%d, waiting for responses", - (ip ? ip : ""), (i + 1), MAX_RETRIES); + __func__, (ip ? ip : ""), (i + 1), MAX_RETRIES); while ((ret = select(peerSocket + 1, &fds, NULL, NULL, &timeout)) ) { @@ -308,9 +311,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) int parserFailed; retNum ++; - upsdebugx(5, "nutscan_scan_xml_http_thready() : request to %s, " + upsdebugx(5, "%s: request to %s, " "loop #%d/%d, response #%d", - (ip ? ip : ""), (i + 1), MAX_RETRIES, retNum); + __func__, (ip ? ip : ""), (i + 1), MAX_RETRIES, retNum); timeout.tv_sec = usec_timeout / 1000000; timeout.tv_usec = usec_timeout % 1000000; @@ -358,9 +361,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) pthread_mutex_lock(&dev_mutex); #endif upsdebugx(5, - "Some host at IP %s replied to NetXML UDP request on port %d, " + "%s: Some host at IP %s replied to NetXML UDP request on port %d, " "inspecting the response...", - string, port_udp); + __func__, string, port_udp); nut_dev->type = TYPE_XML; /* Try to read device type */ parser = (*nut_ne_xml_create)(); @@ -378,9 +381,8 @@ static void * nutscan_scan_xml_http_thready(void * arg) * Does our driver support the notation? */ nut_dev->port = strdup(buf); upsdebugx(3, - "nutscan_scan_xml_http_thready(): " - "Adding configuration for driver='%s' port='%s'", - nut_dev->driver, nut_dev->port); + "%s: Adding configuration for driver='%s' port='%s'", + __func__, nut_dev->driver, nut_dev->port); dev_ret = nutscan_add_device_to_device( dev_ret, nut_dev); #ifdef HAVE_PTHREAD @@ -408,29 +410,29 @@ static void * nutscan_scan_xml_http_thready(void * arg) if (ip != NULL) { upsdebugx(2, - "nutscan_scan_xml_http_thready(): we collected one reply " + "%s: we collected one reply " "to unicast for %s (repsponse from %s), done", - ip, string); + __func__, ip, string); goto end; } } /* while select() responses */ if (ip == NULL && dev_ret != NULL) { upsdebugx(2, - "nutscan_scan_xml_http_thready(): we collected one round of replies " - "to broadcast with no errors, done"); + "%s: we collected one round of replies " + "to broadcast with no errors, done", __func__); goto end; } } } upsdebugx(2, - "nutscan_scan_xml_http_thready(): no replies collected for %s, done", - (ip ? ip : "")); + "%s: no replies collected for %s, done", + __func__, (ip ? ip : "")); goto end; end_abort: upsdebugx(1, - "Had to abort nutscan_scan_xml_http_thready() for %s, see fatal details above", - (ip ? ip : "")); + "%s: Had to abort scan for %s, see fatal details above", + __func__, (ip ? ip : "")); end: /* Broadcast is also a socket! */ From cce256752327d2cd89c1f23ac68080ad1faee4cc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Jul 2024 00:55:42 +0200 Subject: [PATCH 16/18] tools/nut-scanner/scan_*.c: reconcile coding style some more [#2511] Signed-off-by: Jim Klimov --- tools/nut-scanner/nutscan-init.c | 2 +- tools/nut-scanner/scan_avahi.c | 9 +++++--- tools/nut-scanner/scan_eaton_serial.c | 5 +++-- tools/nut-scanner/scan_ipmi.c | 4 +--- tools/nut-scanner/scan_nut.c | 32 +++++++++++++++------------ tools/nut-scanner/scan_snmp.c | 12 +++++----- tools/nut-scanner/scan_usb.c | 8 ++++--- tools/nut-scanner/scan_xml_http.c | 12 ++++++---- 8 files changed, 49 insertions(+), 35 deletions(-) diff --git a/tools/nut-scanner/nutscan-init.c b/tools/nut-scanner/nutscan-init.c index bf458ec394..a0246f52fc 100644 --- a/tools/nut-scanner/nutscan-init.c +++ b/tools/nut-scanner/nutscan-init.c @@ -598,7 +598,7 @@ void nutscan_init(void) nutscan_avail_nut_simulation = 1; } -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally to scan_* modules */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index 812c0f9ac1..18ea2db55f 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -95,7 +95,7 @@ static int (*nut_avahi_service_browser_free)(AvahiServiceBrowser *); static char * (*nut_avahi_address_snprint)(char *ret_s, size_t length, const AvahiAddress *a); static const AvahiPoll* (*nut_avahi_simple_poll_get)(AvahiSimplePoll *s); -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); @@ -104,7 +104,7 @@ int nutscan_unload_avahi_library(void) return nutscan_unload_library(&nutscan_avail_avahi, &dl_handle, &dl_saved_libname); } -/* return 0 on error; visible externally */ +/* Return 0 on error; visible externally */ int nutscan_load_avahi_library(const char *libname_path); int nutscan_load_avahi_library(const char *libname_path) { @@ -132,7 +132,10 @@ int nutscan_load_avahi_library(const char *libname_path) dl_error = lt_dlerror(); goto err; } - lt_dlerror(); /* Clear any existing error */ + + /* Clear any existing error */ + lt_dlerror(); + *(void **) (&nut_avahi_service_browser_get_client) = lt_dlsym(dl_handle, "avahi_service_browser_get_client"); if ((dl_error = lt_dlerror()) != NULL) { goto err; diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c index aee6af5c73..93f95875bf 100644 --- a/tools/nut-scanner/scan_eaton_serial.c +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -589,9 +589,10 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) # ifdef HAVE_SEMAPHORE /* Wait for all current scans to complete */ if (thread_array != NULL) { - upsdebugx (2, "%s: Running too many scanning threads, " + upsdebugx (2, "%s: Running too many scanning threads (%" + PRIuSIZE "), " "waiting until older ones would finish", - __func__); + __func__, thread_count); for (i = 0; i < thread_count ; i++) { int ret; if (!thread_array[i].active) { diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 44f4fd3325..76a1a73982 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -33,7 +33,6 @@ int nutscan_unload_ipmi_library(void); #ifdef WITH_IPMI -#include "upsclient.h" #include #include #include @@ -138,7 +137,7 @@ typedef int bool_t; static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec); static void * nutscan_scan_ipmi_device_thready(void * arg_sec); -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); @@ -633,7 +632,6 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t memset (port_id, 0, sizeof(port_id)); } - } /* Final cleanup */ diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 435cdab294..b1d1cce4dd 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -30,6 +30,10 @@ #include "upsclient.h" #include "nut-scan.h" #include "nut_stdint.h" + +/* externally visible to nutscan-init */ +int nutscan_unload_upsclient_library(void); + #include #define SCAN_NUT_DRIVERNAME "dummy-ups" @@ -69,27 +73,26 @@ struct scan_nut_arg { useconds_t timeout; }; -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); -int nutscan_unload_upsclient_library(void); int nutscan_unload_upsclient_library(void) { return nutscan_unload_library(&nutscan_avail_nut, &dl_handle, &dl_saved_libname); } -/* return 0 on error; visible externally */ +/* Return 0 on error; visible externally */ int nutscan_load_upsclient_library(const char *libname_path); int nutscan_load_upsclient_library(const char *libname_path) { if (dl_handle != NULL) { - /* if previous init failed */ - if (dl_handle == (void *)1) { - return 0; - } - /* init has already been done */ - return 1; + /* if previous init failed */ + if (dl_handle == (void *)1) { + return 0; + } + /* init has already been done */ + return 1; } if (libname_path == NULL) { @@ -98,17 +101,18 @@ int nutscan_load_upsclient_library(const char *libname_path) } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); - return 0; + fprintf(stderr, "Error initializing lt_init\n"); + return 0; } dl_handle = lt_dlopen(libname_path); if (!dl_handle) { - dl_error = lt_dlerror(); - goto err; + dl_error = lt_dlerror(); + goto err; } - lt_dlerror(); /* Clear any existing error */ + /* Clear any existing error */ + lt_dlerror(); *(void **) (&nut_upscli_splitaddr) = lt_dlsym(dl_handle, "upscli_splitaddr"); diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index b35c645846..6f96a95ac3 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -40,8 +40,8 @@ int nutscan_unload_snmp_library(void); # undef _WIN32_WINNT #endif -#include #include +#include #include /* workaround for buggy Net-SNMP config @@ -182,7 +182,7 @@ static oid *nut_usmHMAC256SHA384AuthProtocol; static oid *nut_usmHMAC384SHA512AuthProtocol; #endif -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ #ifndef WITH_SNMP_STATIC @@ -198,7 +198,7 @@ int nutscan_unload_snmp_library(void) #endif } -/* return 0 on error; visible externally */ +/* Return 0 on error; visible externally */ int nutscan_load_snmp_library(const char *libname_path); int nutscan_load_snmp_library(const char *libname_path) { @@ -312,7 +312,9 @@ int nutscan_load_snmp_library(const char *libname_path) goto err; } - lt_dlerror(); /* Clear any existing error */ + /* Clear any existing error */ + lt_dlerror(); + *(void **) (&nut_init_snmp) = lt_dlsym(dl_handle, "init_snmp"); if ((dl_error = lt_dlerror()) != NULL) { goto err; @@ -1331,7 +1333,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, # endif /* HAVE_PTHREAD_TRYJOIN */ } #else /* if not HAVE_PTHREAD */ - try_SysOID_thready((void *)tmp_sec); + try_SysOID_thready(tmp_sec); #endif /* if HAVE_PTHREAD */ /* Prepare the next iteration; note that diff --git a/tools/nut-scanner/scan_usb.c b/tools/nut-scanner/scan_usb.c index 0b756991ca..553a6d1198 100644 --- a/tools/nut-scanner/scan_usb.c +++ b/tools/nut-scanner/scan_usb.c @@ -81,7 +81,7 @@ static int (*nut_usb_get_string_simple)(libusb_device_handle *dev, int index, static char * (*nut_usb_strerror)(void); #endif /* WITH_LIBUSB_1_0 */ -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); @@ -90,7 +90,7 @@ int nutscan_unload_usb_library(void) return nutscan_unload_library(&nutscan_avail_usb, &dl_handle, &dl_saved_libname); } -/* return 0 on error; visible externally */ +/* Return 0 on error; visible externally */ int nutscan_load_usb_library(const char *libname_path); int nutscan_load_usb_library(const char *libname_path) { @@ -118,7 +118,9 @@ int nutscan_load_usb_library(const char *libname_path) dl_error = lt_dlerror(); goto err; } - lt_dlerror(); /* Clear any existing error */ + + /* Clear any existing error */ + lt_dlerror(); *(void **) (&nut_usb_init) = lt_dlsym(dl_handle, USB_INIT_SYMBOL); if ((dl_error = lt_dlerror()) != NULL) { diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index ff8ca5a414..a858c85662 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -89,7 +89,7 @@ typedef enum ebool { FALSE = 0, TRUE } bool_t; typedef int bool_t; #endif -/* return 0 on success, -1 on error e.g. "was not loaded"; +/* Return 0 on success, -1 on error e.g. "was not loaded"; * other values may be possible if lt_dlclose() errors set them; * visible externally */ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); @@ -98,7 +98,7 @@ int nutscan_unload_neon_library(void) return nutscan_unload_library(&nutscan_avail_xml_http, &dl_handle, &dl_saved_libname); } -/* return 0 on error; visible externally */ +/* Return 0 on error; visible externally */ int nutscan_load_neon_library(const char *libname_path); int nutscan_load_neon_library(const char *libname_path) { @@ -127,7 +127,9 @@ int nutscan_load_neon_library(const char *libname_path) goto err; } - lt_dlerror(); /* Clear any existing error */ + /* Clear any existing error */ + lt_dlerror(); + *(void **) (&nut_ne_xml_push_handler) = lt_dlsym(dl_handle, "ne_xml_push_handler"); if ((dl_error = lt_dlerror()) != NULL) { @@ -171,6 +173,7 @@ int nutscan_load_neon_library(const char *libname_path) } return 0; } +/* end of dynamic link library stuff */ /* A start-element callback for element with given namespace/name. */ static int startelm_cb(void *userdata, int parent, const char *nspace, const char *name, const char **atts) { @@ -479,8 +482,8 @@ nutscan_device_t * nutscan_scan_xml_http_range(const char * start_ip, const char nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, useconds_t usec_timeout, nutscan_xml_t * sec) { bool_t pass = TRUE; /* Track that we may spawn a scanning thread */ - nutscan_xml_t * tmp_sec = NULL; nutscan_device_t * result = NULL; + nutscan_xml_t * tmp_sec = NULL; if (!nutscan_avail_xml_http) { return NULL; @@ -498,6 +501,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, /* Iterate the one or a range of IPs to scan */ nutscan_ip_range_list_iter_t ip; char * ip_str = NULL; + #ifdef HAVE_PTHREAD # ifdef HAVE_SEMAPHORE sem_t * semaphore = nutscan_semaphore(); From 1fb03cd1ca6fd677d79a1173e1ab3c3b16b4cabe Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Jul 2024 03:37:38 +0200 Subject: [PATCH 17/18] scripts/valgrind/.valgrind.supp: update titles for libssl suppressions Signed-off-by: Jim Klimov --- scripts/valgrind/.valgrind.supp | 6 +-- tools/nut-scanner/Makefile.am | 2 +- tools/nut-scanner/nut-scanner.c | 29 +++++------ tools/nut-scanner/nutscan-display.c | 4 +- tools/nut-scanner/nutscan-ip.c | 9 ++-- tools/nut-scanner/nutscan-serial.c | 8 +-- tools/nut-scanner/scan_avahi.c | 53 ++++++++++--------- tools/nut-scanner/scan_ipmi.c | 29 ++++++----- tools/nut-scanner/scan_nut.c | 9 ++-- tools/nut-scanner/scan_nut_simulation.c | 4 +- tools/nut-scanner/scan_snmp.c | 68 ++++++++++++++----------- tools/nut-scanner/scan_usb.c | 33 ++++++------ tools/nut-scanner/scan_xml_http.c | 51 ++++++++++--------- 13 files changed, 164 insertions(+), 141 deletions(-) diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp index 552c56c565..905e883c7f 100644 --- a/scripts/valgrind/.valgrind.supp +++ b/scripts/valgrind/.valgrind.supp @@ -34,21 +34,21 @@ ... } { - + Memcheck:Leak ... fun:CRYPTO_* ... } { - + Memcheck:Leak ... fun:SSL_CTX_* ... } { - + Memcheck:Leak ... fun:OPENSSL_* diff --git a/tools/nut-scanner/Makefile.am b/tools/nut-scanner/Makefile.am index a445acc3d1..301c593656 100644 --- a/tools/nut-scanner/Makefile.am +++ b/tools/nut-scanner/Makefile.am @@ -96,7 +96,7 @@ libnutscan_la_LDFLAGS += -version-info 2:5:2 # 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_upsdebug|fatalx|xcalloc|snprintfcat|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_upsdebug|fatalx|fatal_with_errno|xcalloc|snprintfcat|max_threads|curr_threads|nut_report_config_flags|upsdebugx_report_search_paths|nut_prepare_search_paths)' libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include \ $(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index a198f526ad..ebfacc9aa7 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -348,7 +348,7 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) * `-m auto4/X` and `-m auto6/Y` requests? */ if (auto_nets_ptr && *auto_nets_ptr) { - fprintf(stderr, "Duplicate request for connected subnet scan ignored\n"); + upsdebugx(0, "Duplicate request for connected subnet scan ignored"); return; } @@ -437,9 +437,8 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) if (getifaddrs(&ifap) < 0 || !ifap) { if (ifap) freeifaddrs(ifap); - fatalx(EXIT_FAILURE, - "Failed to getifaddrs() for connected subnet scan: %s\n", - strerror(errno)); + fatal_with_errno(EXIT_FAILURE, + "Failed to getifaddrs() for connected subnet scan"); /* TOTHINK: Non-fatal, just return / goto finish? * Either way, do not proceed with code below! */ } @@ -1175,7 +1174,7 @@ int main(int argc, char *argv[]) /* Get max number of files. */ if (getrlimit(RLIMIT_NOFILE, &nofile_limit) != 0) { /* Report error, keep hardcoded default */ - fprintf(stderr, "getrlimit() failed with errno=%d, keeping default job limits\n", errno); + upsdebug_with_errno(0, "getrlimit() failed, keeping default job limits"); nofile_limit.rlim_cur = 0; nofile_limit.rlim_max = 0; } else { @@ -1249,8 +1248,8 @@ int main(int argc, char *argv[]) if (errno_saved || (s && *s != '\0') || l <= 0) { /* TODO: Any max limit? At least, * max(useconds_t)/1000000 ? */ - fprintf(stderr, - "Illegal timeout value, using default %ds\n", + upsdebugx(0, + "Illegal timeout value, using default %ds", DEFAULT_NETWORK_TIMEOUT); timeout = DEFAULT_NETWORK_TIMEOUT * 1000 * 1000; } else { @@ -1404,8 +1403,8 @@ int main(int argc, char *argv[]) ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD5; } else { - fprintf(stderr, - "Unknown authentication type (%s). Defaulting to MD5\n", + upsdebugx(0, + "Unknown authentication type (%s). Defaulting to MD5", optarg); } break; @@ -1449,27 +1448,27 @@ int main(int argc, char *argv[]) max_threads -= RESERVE_FD_COUNT; } - fprintf(stderr, + upsdebugx(0, "WARNING: Requested max scanning " "thread count %s (%ld) exceeds the " "current file descriptor count limit " "(minus reservation), constraining " - "to %" PRIuSIZE "\n", + "to %" PRIuSIZE, optarg, val, max_threads); } else # endif /* HAVE_SYS_RESOURCE_H */ max_threads = (size_t)val; } else { - fprintf(stderr, + upsdebugx(0, "WARNING: Requested max scanning " "thread count %s (%ld) is out of range, " - "using default %" PRIuSIZE "\n", + "using default %" PRIuSIZE, optarg, val, max_threads); } #else - fprintf(stderr, + upsdebugx(0, "WARNING: Max scanning thread count option " - "is not supported in this build, ignored\n"); + "is not supported in this build, ignored"); #endif /* HAVE_PTHREAD && ways to limit the thread count */ } break; diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index 08234f7e8c..f486b99198 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -263,7 +263,7 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) /* Reserve enough slots for all-unique serials */ map = calloc(listlen, sizeof(keyval_strings_t)); if (map == NULL) { - fprintf(stderr, "%s: Memory allocation error, skipped\n", __func__); + upsdebugx(0, "%s: Memory allocation error, skipped", __func__); return; } @@ -317,7 +317,7 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) count++; if (count != (i + 1) || count > listlen) { /* Should never get here, but just in case... */ - fprintf(stderr, "%s: Loop overflow, skipped\n", __func__); + upsdebugx(0, "%s: Loop overflow, skipped", __func__); upsdebugx(3, "%s: count=%" PRIuSIZE " i=%" PRIuSIZE " listlen%" PRIuSIZE, __func__, count, i, listlen); goto exit; diff --git a/tools/nut-scanner/nutscan-ip.c b/tools/nut-scanner/nutscan-ip.c index 0f89e430e2..5c09a15134 100644 --- a/tools/nut-scanner/nutscan-ip.c +++ b/tools/nut-scanner/nutscan-ip.c @@ -370,7 +370,8 @@ char * nutscan_ip_iter_init(nutscan_ip_iter_t * ip, const char * startIP, const ip->type = IPv6; hints.ai_family = AF_INET6; if (getaddrinfo(startIP, NULL, &hints, &res) != 0) { - fprintf(stderr, "Invalid address : %s\n", startIP); + upsdebugx(0, "WARNING: %s: Invalid address : %s", + __func__, startIP); return NULL; } @@ -388,7 +389,8 @@ char * nutscan_ip_iter_init(nutscan_ip_iter_t * ip, const char * startIP, const if (ip->type == IPv4) { hints.ai_family = AF_INET; if (getaddrinfo(stopIP, NULL, &hints, &res) != 0) { - fprintf(stderr, "Invalid address : %s\n", stopIP); + upsdebugx(0, "WARNING: %s: Invalid address : %s", + __func__, stopIP); return NULL; } @@ -399,7 +401,8 @@ char * nutscan_ip_iter_init(nutscan_ip_iter_t * ip, const char * startIP, const else { hints.ai_family = AF_INET6; if (getaddrinfo(stopIP, NULL, &hints, &res) != 0) { - fprintf(stderr, "Invalid address : %s\n", stopIP); + upsdebugx(0, "WARNING: %s: Invalid address : %s", + __func__, stopIP); return NULL; } memcpy(s_in6, res->ai_addr, sizeof(struct sockaddr_in6)); diff --git a/tools/nut-scanner/nutscan-serial.c b/tools/nut-scanner/nutscan-serial.c index a98b4dcb29..b354752ada 100644 --- a/tools/nut-scanner/nutscan-serial.c +++ b/tools/nut-scanner/nutscan-serial.c @@ -42,7 +42,7 @@ #define SERIAL_PORT_PREFIX "/dev/tty" #endif -#define ERR_OUT_OF_BOUND "Serial port range out of bound (must be 0 to 9 or a to z depending on your system)\n" +#define ERR_OUT_OF_BOUND "Serial port range out of bound (must be 0 to 9 or a to z depending on your system)" typedef struct { char * name; @@ -108,7 +108,7 @@ static char ** add_port(char ** list, char * port) /*+1 for the terminal NULL */ res = realloc(list, sizeof(char*) * (count + 1 + 1)); if (res == NULL) { - upsdebugx(1, "%s: Failed to realloc port list", __func__); + upsdebugx(0, "%s: Failed to realloc port list", __func__); return list; } res[count] = strdup(port); @@ -146,7 +146,7 @@ char ** nutscan_get_serial_ports_list(const char *ports_range) if ((list_sep_ptr = strchr(range, '-')) != NULL) { tok = strtok_r(range, "-", &saveptr); if (tok[1] != 0) { - fprintf(stderr, ERR_OUT_OF_BOUND); + upsdebugx(0, "%s", ERR_OUT_OF_BOUND); free(range); return NULL; } @@ -154,7 +154,7 @@ char ** nutscan_get_serial_ports_list(const char *ports_range) tok = strtok_r(NULL, "-", &saveptr); if (tok != NULL) { if (tok[1] != 0) { - fprintf(stderr, ERR_OUT_OF_BOUND); + upsdebugx(0, "%s", ERR_OUT_OF_BOUND); free(range); return NULL; } diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index 18ea2db55f..8a9a4bbe1c 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -118,12 +118,12 @@ int nutscan_load_avahi_library(const char *libname_path) } if (libname_path == NULL) { - fprintf(stderr, "AVAHI client library not found. AVAHI search disabled.\n"); + upsdebugx(0, "AVAHI client library not found. AVAHI search disabled."); return 0; } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -231,9 +231,10 @@ int nutscan_load_avahi_library(const char *libname_path) dl_saved_libname = xstrdup(libname_path); return 1; + err: - fprintf(stderr, - "Cannot load AVAHI library (%s) : %s. AVAHI search disabled.\n", + upsdebugx(0, + "Cannot load AVAHI library (%s) : %s. AVAHI search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -407,23 +408,23 @@ static void resolve_callback( switch (event) { case AVAHI_RESOLVER_FAILURE: - fprintf(stderr, - "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", - name, type, domain, + upsdebugx(0, "%s: " + "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s", + __func__, name, type, domain, (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_resolver_get_client)(r)))); break; case AVAHI_RESOLVER_FOUND: { char a[AVAHI_ADDRESS_STR_MAX], *t; -/* fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); */ +/* upsdebugx(1, "%s: Service '%s' of type '%s' in domain '%s':", __func__, name, type, domain); */ (*nut_avahi_address_snprint)(a, sizeof(a), address); t = (*nut_avahi_string_list_to_string)(txt); NUT_UNUSED_VARIABLE(flags); /* - fprintf(stderr, + upsdebugx(1, "\t%s:%u (%s)\n" "\tTXT=%s\n" "\tcookie is %u\n" @@ -471,14 +472,14 @@ static void browse_callback( switch (event) { case AVAHI_BROWSER_FAILURE: - fprintf(stderr, - "(Browser) %s\n", + upsdebugx(0, "%s: (Browser) %s", + __func__, (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_browser_get_client)(b)))); (*nut_avahi_simple_poll_quit)(simple_poll); return; case AVAHI_BROWSER_NEW: -/* fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); */ +/* upsdebugx(1, "%s: "(Browser) NEW: service '%s' of type '%s' in domain '%s'", __func__, name, type, domain); */ /* We ignore the returned resolver object. In the callback function we free it. If the server is terminated before @@ -498,14 +499,15 @@ static void browse_callback( #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) # pragma GCC diagnostic pop #endif - fprintf(stderr, - "Failed to resolve service '%s': %s\n", + upsdebugx(0, "%s: " + "Failed to resolve service '%s': %s", + __func__, name, (*nut_avahi_strerror)((*nut_avahi_client_errno)(c))); break; case AVAHI_BROWSER_REMOVE: - fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + upsdebugx(0, "%s: (Browser) REMOVE: service '%s' of type '%s' in domain '%s'", __func__, name, type, domain); break; case AVAHI_BROWSER_ALL_FOR_NOW: @@ -514,7 +516,7 @@ static void browse_callback( case AVAHI_BROWSER_CACHE_EXHAUSTED: fallthrough_AVAHI_BROWSER_CACHE_EXHAUSTED: -/* fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); */ +/* upsdebugx(1, "%s: (Browser) %s", __func__, event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); */ break; } } @@ -526,8 +528,9 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd /* Called whenever the client or server state changes */ if (state == AVAHI_CLIENT_FAILURE) { - fprintf(stderr, - "Server connection failure: %s\n", + upsdebugx(0, "%s: " + "Server connection failure: %s", + __func__, (*nut_avahi_strerror)((*nut_avahi_client_errno)(c))); (*nut_avahi_simple_poll_quit)(simple_poll); } @@ -568,7 +571,8 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) /* Allocate main loop object */ if (!(simple_poll = (*nut_avahi_simple_poll_new)())) { - fprintf(stderr, "Failed to create Avahi simple poll object.\n"); + upsdebugx(0, "%s: Failed to create Avahi simple poll object.", + __func__); goto fail; } @@ -577,9 +581,9 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) /* Check wether creating the client object succeeded */ if (!client) { - fprintf(stderr, - "Failed to create Avahi client: %s\n", - (*nut_avahi_strerror)(error)); + upsdebugx(0, "%s: " + "Failed to create Avahi client: %s", + __func__, (*nut_avahi_strerror)(error)); goto fail; } @@ -596,8 +600,9 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) # pragma GCC diagnostic pop #endif - fprintf(stderr, - "Failed to create Avahi service browser: %s\n", + upsdebugx(0, "%s: " + "Failed to create Avahi service browser: %s", + __func__, (*nut_avahi_strerror)((*nut_avahi_client_errno)(client))); goto fail; } diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 76a1a73982..316f15bd15 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -160,12 +160,12 @@ int nutscan_load_ipmi_library(const char *libname_path) } if (libname_path == NULL) { - fprintf(stderr, "IPMI library not found. IPMI search disabled.\n"); + upsdebugx(0, "IPMI library not found. IPMI search disabled."); return 0; } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -280,8 +280,8 @@ int nutscan_load_ipmi_library(const char *libname_path) return 1; err: - fprintf(stderr, - "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", + upsdebugx(0, + "Cannot load IPMI library (%s) : %s. IPMI search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -345,7 +345,9 @@ static int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) /* Parse FRU information */ if (!(fru_parse_ctx = (*nut_ipmi_fru_ctx_create) (ipmi_ctx))) { - fprintf(stderr, "Error with %s(): %s\n", IPMI_FRU_CTX_CREATE, (*nut_ipmi_ctx_errormsg)(ipmi_ctx)); + upsdebugx(0, "%s: Error with %s(): %s", + __func__, IPMI_FRU_CTX_CREATE, + (*nut_ipmi_ctx_errormsg)(ipmi_ctx)); return 0; } @@ -361,7 +363,8 @@ static int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) } if (ipmi_id < 0 || (unsigned int)ipmi_id > UINT8_MAX) { - fprintf(stderr, "is_ipmi_device_supported: ipmi_id=%d is out of range!\n", ipmi_id); + upsdebugx(0, "%s: ipmi_id=%d is out of range!", + __func__, ipmi_id); return 0; } if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, (uint8_t)ipmi_id) < 0) @@ -444,7 +447,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t if (!(ipmi_ctx = wrap_nut_ipmi_ctx_create())) { /* we have to force cleanup, since exit handler is not yet installed */ - fprintf(stderr, "Failed to ipmi_ctx_create\n"); + upsdebugx(0, "%s: Failed to ipmi_ctx_create", __func__); return NULL; } @@ -455,7 +458,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t /* FIXME: we need root right to access local IPMI! if (!ipmi_is_root ()) { - fprintf(stderr, "IPMI scan: %s\n", ipmi_ctx_strerror (IPMI_ERR_PERMISSION)); + upsdebugx(0, "%s: IPMI scan: %s", __func__, ipmi_ctx_strerror (IPMI_ERR_PERMISSION)); } */ if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, @@ -489,7 +492,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * int parse_kg (void *out, unsigned int outlen, const char *in) * if ((rv = parse_kg (common_cmd_args_config->k_g, IPMI_MAX_K_G_LENGTH + 1, data->string)) < 0) * { - * fprintf (stderr, "Config File Error: k_g input formatted incorrectly\n"); + * upsdebugx(0, "%s: Config File Error: k_g input formatted incorrectly", __func__); * exit (EXIT_FAILURE); * }*/ if ((ret = (*nut_ipmi_ctx_open_outofband_2_0) (ipmi_ctx, @@ -605,7 +608,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t if (is_ipmi_device_supported(ipmi_ctx, ipmi_id)) { if ((nut_dev = nutscan_new_device()) == NULL) { - fprintf(stderr, "Memory allocation error\n"); + upsdebugx(0, "%s: Memory allocation error", __func__); nutscan_free_device(current_nut_dev); break; } @@ -915,10 +918,10 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut if (pass) { tmp_sec = malloc(sizeof(nutscan_ipmi_t)); if (tmp_sec == NULL) { - fprintf(stderr, - "Memory allocation error\n"); - return NULL; + upsdebugx(0, "%s: Memory allocation error", __func__); + break; } + memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t)); tmp_sec->peername = ip_str; diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index b1d1cce4dd..da11aa53a5 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -96,12 +96,12 @@ int nutscan_load_upsclient_library(const char *libname_path) } if (libname_path == NULL) { - fprintf(stderr, "NUT client library not found. NUT search disabled.\n"); + upsdebugx(0, "NUT client library not found. NUT search disabled."); return 0; } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -151,8 +151,8 @@ int nutscan_load_upsclient_library(const char *libname_path) return 1; err: - fprintf(stderr, - "Cannot load NUT library (%s) : %s. NUT search disabled.\n", + upsdebugx(0, + "Cannot load NUT library (%s) : %s. NUT search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -555,6 +555,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons } if ((nut_arg = malloc(sizeof(struct scan_nut_arg))) == NULL) { + upsdebugx(0, "%s: Memory allocation error", __func__); free(ip_dest); break; } diff --git a/tools/nut-scanner/scan_nut_simulation.c b/tools/nut-scanner/scan_nut_simulation.c index b2c4cddabb..7324ddb1d8 100644 --- a/tools/nut-scanner/scan_nut_simulation.c +++ b/tools/nut-scanner/scan_nut_simulation.c @@ -48,8 +48,8 @@ nutscan_device_t * nutscan_scan_nut_simulation(void) upsdebugx(1, "Scanning: %s", CONFPATH); if ((dp = opendir(CONFPATH)) == NULL) { - upsdebugx(1, "%s: Failed to open %s: %s (%d)", - __func__, CONFPATH, strerror(errno), errno); + upsdebug_with_errno(1, "%s: Failed to open %s", + __func__, CONFPATH); upsdebugx(0, "Failed to open %s, skip NUT simulation scan", CONFPATH); return NULL; diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index 6f96a95ac3..13def273b6 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -297,12 +297,12 @@ int nutscan_load_snmp_library(const char *libname_path) } if (libname_path == NULL) { - upsdebugx(1, "SNMP library not found. SNMP search disabled"); + upsdebugx(0, "SNMP library not found. SNMP search disabled."); return 0; } if (lt_dlinit() != 0) { - upsdebugx(1, "Error initializing lt_init"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -485,8 +485,8 @@ int nutscan_load_snmp_library(const char *libname_path) #ifndef WITH_SNMP_STATIC err: - fprintf(stderr, - "Cannot load SNMP library (%s) : %s. SNMP search disabled.\n", + upsdebugx(0, + "Cannot load SNMP library (%s) : %s. SNMP search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -693,15 +693,16 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) else if (strcmp(sec->secLevel, "authPriv") == 0) snmp_sess->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; else { - fprintf(stderr, - "Bad SNMPv3 securityLevel: %s\n", - sec->secLevel); + upsdebugx(0, "WARNING: %s: " + "Bad SNMPv3 securityLevel: %s", + __func__, sec->secLevel); return 0; } /* Security name */ if (sec->secName == NULL) { - fprintf(stderr, "securityName is required for SNMPv3\n"); + upsdebugx(0, "WARNING: %s: securityName is required for SNMPv3", + __func__); return 0; } snmp_sess->securityName = strdup(sec->secName); @@ -716,20 +717,20 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) switch (snmp_sess->securityLevel) { case SNMP_SEC_LEVEL_AUTHNOPRIV: if (sec->authPassword == NULL) { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "authPassword is required " - "for SNMPv3 in %s mode\n", - sec->secLevel); + "for SNMPv3 in %s mode", + __func__, sec->secLevel); return 0; } break; case SNMP_SEC_LEVEL_AUTHPRIV: if ((sec->authPassword == NULL) || (sec->privPassword == NULL)) { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "authPassword and privPassword are " - "required for SNMPv3 in %s mode\n", - sec->secLevel); + "required for SNMPv3 in %s mode", + __func__, sec->secLevel); return 0; } break; @@ -791,9 +792,9 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) #else { #endif - fprintf(stderr, - "Bad SNMPv3 authProtocol: %s\n", - sec->authProtocol); + upsdebugx(0, "WARNING: %s: " + "Bad SNMPv3 authProtocol: %s", + __func__, sec->authProtocol); return 0; } } @@ -813,8 +814,8 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif - fprintf(stderr, "Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, - snmp_sess->securityAuthProtoLen); + upsdebugx(0, "WARNING: %s: Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, + __func__, snmp_sess->securityAuthProtoLen); return 0; } if ((*nut_generate_Ku)(snmp_sess->securityAuthProto, @@ -825,9 +826,10 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) &snmp_sess->securityAuthKeyLen) != SNMPERR_SUCCESS ) { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "Error generating Ku from " - "authentication pass phrase\n"); + "authentication pass phrase", + __func__); return 0; } @@ -878,9 +880,9 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) #else { #endif - fprintf(stderr, - "Bad SNMPv3 privProtocol: %s\n", - sec->privProtocol); + upsdebugx(0, "WARNING: %s: " + "Bad SNMPv3 privProtocol: %s", + __func__, sec->privProtocol); return 0; } } @@ -901,8 +903,8 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif - fprintf(stderr, "Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, - snmp_sess->securityAuthProtoLen); + upsdebugx(0, "WARNING: %s: Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, + __func__, snmp_sess->securityAuthProtoLen); return 0; } if ((*nut_generate_Ku)(snmp_sess->securityAuthProto, @@ -913,9 +915,10 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) &snmp_sess->securityPrivKeyLen) != SNMPERR_SUCCESS ) { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "Error generating Ku from " - "private pass phrase\n"); + "private pass phrase", + __func__); return 0; } @@ -980,7 +983,7 @@ static void * try_SysOID_thready(void * arg) pdu = (*nut_snmp_pdu_create)(SNMP_MSG_GET); if (pdu == NULL) { - fprintf(stderr, "Not enough memory\n"); + upsdebugx(0, "%s: Memory allocation error", __func__); (*nut_snmp_sess_close)(handle); goto try_SysOID_free; } @@ -1177,7 +1180,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, g_usec_timeout = usec_timeout; - /* Force numeric OIDs resolution (ie, do not resolve to textual names) + /* Force numeric OIDs resolution (i.e., do not resolve to textual names) * This is mostly for the convenience of debug output */ if (nut_snmp_out_toggle_options("n") != NULL) { upsdebugx(1, "Failed to enable numeric OIDs resolution"); @@ -1304,6 +1307,11 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, if (pass) { tmp_sec = malloc(sizeof(nutscan_snmp_t)); + if (tmp_sec == NULL) { + upsdebugx(0, "%s: Memory allocation error", __func__); + break; + } + memcpy(tmp_sec, sec, sizeof(nutscan_snmp_t)); tmp_sec->peername = ip_str; diff --git a/tools/nut-scanner/scan_usb.c b/tools/nut-scanner/scan_usb.c index 553a6d1198..67d20b578c 100644 --- a/tools/nut-scanner/scan_usb.c +++ b/tools/nut-scanner/scan_usb.c @@ -104,12 +104,12 @@ int nutscan_load_usb_library(const char *libname_path) } if (libname_path == NULL) { - fprintf(stderr, "USB library not found. USB search disabled.\n"); + upsdebugx(0, "USB library not found. USB search disabled."); return 0; } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -183,10 +183,10 @@ int nutscan_load_usb_library(const char *libname_path) *(void **) (&nut_usb_get_port_number) = lt_dlsym(dl_handle, "libusb_get_port_number"); if ((dl_error = lt_dlerror()) != NULL) { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "While loading USB library (%s), failed to find libusb_get_port_number() : %s. " - "The \"busport\" USB matching option will be disabled.\n", - libname_path, dl_error); + "The \"busport\" USB matching option will be disabled.", + __func__, libname_path, dl_error); nut_usb_get_port_number = NULL; } @@ -242,8 +242,8 @@ int nutscan_load_usb_library(const char *libname_path) return 1; err: - fprintf(stderr, - "Cannot load USB library (%s) : %s. USB search disabled.\n", + upsdebugx(0, + "Cannot load USB library (%s) : %s. USB search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -448,9 +448,12 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) #if WITH_LIBUSB_1_0 ret = (*nut_usb_open)(dev, &udev); if (!udev || ret != LIBUSB_SUCCESS) { - fprintf(stderr, "Failed to open device " - "bus '%s' device/port '%s' bus/port '%s', skipping: %s\n", - busname, device_port, bus_port, + upsdebugx(0, "WARNING: %s: " + "Failed to open device " + "bus '%s' device/port '%s' " + "bus/port '%s', skipping: %s", + __func__, busname, + device_port, bus_port, (*nut_usb_strerror)(ret)); /* Note: closing is not applicable @@ -472,9 +475,10 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) udev = (*nut_usb_open)(dev); if (!udev) { /* TOTHINK: any errno or similar to test? */ - fprintf(stderr, "Failed to open device " - "bus '%s' device/port '%s', skipping: %s\n", - busname, device_port, + upsdebugx(0, "WARNING: %s: " + "Failed to open device " + "bus '%s' device/port '%s', skipping: %s", + __func__, busname, device_port, (*nut_usb_strerror)()); continue; } @@ -554,8 +558,7 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) nut_dev = nutscan_new_device(); if (nut_dev == NULL) { - fprintf(stderr, - "Memory allocation error\n"); + upsdebugx(0, "%s: Memory allocation error", __func__); nutscan_free_device(current_nut_dev); free(serialnumber); free(device_name); diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index a858c85662..9bec46f37b 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -56,7 +56,6 @@ int nutscan_unload_neon_library(void); #include #include -#include #include #include @@ -112,12 +111,12 @@ int nutscan_load_neon_library(const char *libname_path) } if (libname_path == NULL) { - fprintf(stderr, "Neon library not found. XML search disabled.\n"); + upsdebugx(0, "Neon library not found. XML search disabled."); return 0; } if (lt_dlinit() != 0) { - fprintf(stderr, "Error initializing lt_init\n"); + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); return 0; } @@ -161,9 +160,10 @@ int nutscan_load_neon_library(const char *libname_path) dl_saved_libname = xstrdup(libname_path); return 1; + err: - fprintf(stderr, - "Cannot load XML library (%s) : %s. XML search disabled.\n", + upsdebugx(0, + "Cannot load XML library (%s) : %s. XML search disabled.", libname_path, dl_error); dl_handle = (void *)1; lt_dlexit(); @@ -255,7 +255,8 @@ static void * nutscan_scan_xml_http_thready(void * arg) } if ((peerSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - fprintf(stderr, "Error creating socket\n"); + upsdebugx(0, "%s: Error creating socket for %s", + __func__, ip ? ip : "broadcast"); goto end_free; } @@ -289,8 +290,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) (struct sockaddr *)&sockAddress_udp, sockAddressLength) <= 0 ) { - fprintf(stderr, - "Error sending Eaton to %s, #%d/%d\n", + upsdebugx(0, "%s: " + "Error sending Eaton to %s, #%d/%d", + __func__, (ip ? ip : ""), (i + 1), MAX_RETRIES); usleep(usec_timeout); continue; @@ -322,9 +324,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) timeout.tv_usec = usec_timeout % 1000000; if (ret == -1) { - fprintf(stderr, - "Error waiting on \ - socket: %d\n", errno); + upsdebug_with_errno(0, + "%s: Error waiting on socket", + __func__); break; } @@ -335,9 +337,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) &sockAddressLength); if (recv_size < 0) { - fprintf(stderr, - "Error reading \ - socket: %d, #%d/%d\n", errno, (i + 1), MAX_RETRIES); + upsdebug_with_errno(0, "%s: " + "Error reading socket: #%d/%d", + __func__, (i + 1), MAX_RETRIES); usleep(usec_timeout); continue; } @@ -348,15 +350,15 @@ static void * nutscan_scan_xml_http_thready(void * arg) sizeof(string), NULL, 0, NI_NUMERICHOST) != 0 ) { - fprintf(stderr, - "Error converting IP address: %d\n", errno); + upsdebug_with_errno(0, "%s: " + "Error converting IP address", __func__); usleep(usec_timeout); continue; } nut_dev = nutscan_new_device(); if (nut_dev == NULL) { - fprintf(stderr, "Memory allocation error\n"); + upsdebugx(0, "%s: Memory allocation error", __func__); goto end_abort; } @@ -394,10 +396,10 @@ static void * nutscan_scan_xml_http_thready(void * arg) } else { - fprintf(stderr, + upsdebugx(0, "WARNING: %s: " "Device at IP %s replied with NetXML but was not deemed compatible " - "with 'netxml-ups' driver (unsupported protocol version, etc.)\n", - string); + "with 'netxml-ups' driver (unsupported protocol version, etc.)", + __func__, string); nutscan_free_device(nut_dev); nut_dev = NULL; #ifdef HAVE_PTHREAD @@ -685,10 +687,10 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, if (pass) { tmp_sec = malloc(sizeof(nutscan_xml_t)); if (tmp_sec == NULL) { - fprintf(stderr, - "Memory allocation error\n"); - return NULL; + upsdebugx(0, "%s: Memory allocation error", __func__); + break; } + memcpy(tmp_sec, sec, sizeof(nutscan_xml_t)); tmp_sec->peername = ip_str; if (tmp_sec->usec_timeout <= 0) { @@ -827,8 +829,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, /* both start_ip == end_ip == NULL, scan broadcast */ tmp_sec = malloc(sizeof(nutscan_xml_t)); if (tmp_sec == NULL) { - fprintf(stderr, - "Memory allocation error\n"); + upsdebugx(0, "%s: Memory allocation error", __func__); return NULL; } From f7e94fdacb2068cc4c45d51ff0eaac95c8765274 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Jul 2024 03:39:54 +0200 Subject: [PATCH 18/18] scripts/valgrind/.valgrind.supp: sem_open is broken in some libc implementations [#2511] Per https://forums.freebsd.org/threads/named-semaphore-uninitialized-bytes.84850/ apparently BSD libc and GLibc at least do suffer Signed-off-by: Jim Klimov --- scripts/valgrind/.valgrind.supp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/valgrind/.valgrind.supp b/scripts/valgrind/.valgrind.supp index 905e883c7f..2e175ebaf5 100644 --- a/scripts/valgrind/.valgrind.supp +++ b/scripts/valgrind/.valgrind.supp @@ -123,3 +123,20 @@ fun:wrap_nut_avahi_client_new ... } +{ + # https://forums.freebsd.org/threads/named-semaphore-uninitialized-bytes.84850/ + + Memcheck:Cond + ... + fun:sem_open + ... +} +{ + + Memcheck:Cond + ... + fun:sem_trywait* + ... + fun:start_thread + ... +}