From 0c9276444fb041ac6ffd7134374cf7b8c4e9bfaa Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 14 Jan 2023 20:49:09 +0100 Subject: [PATCH 1/6] nut-scanner: report bogus and duplicate serial numbers [#1810] --- NEWS | 4 + UPGRADING | 4 + docs/man/Makefile.am | 9 + docs/man/nut-scanner.txt | 4 + docs/man/nutscan.txt | 7 +- docs/man/nutscan_add_option_to_device.txt | 9 + docs/man/nutscan_cidr_to_ip.txt | 1 + docs/man/nutscan_display_parsable.txt | 7 + docs/man/nutscan_display_sanity_check.txt | 39 ++++ .../nutscan_display_sanity_check_serial.txt | 43 ++++ docs/man/nutscan_display_ups_conf.txt | 6 + ...can_display_ups_conf_with_sanity_check.txt | 36 ++++ docs/man/nutscan_free_device.txt | 1 + docs/man/nutscan_get_serial_ports_list.txt | 1 + docs/man/nutscan_init.txt | 3 + docs/man/nutscan_new_device.txt | 3 + docs/man/nutscan_scan_avahi.txt | 3 + docs/man/nutscan_scan_eaton_serial.txt | 3 + docs/man/nutscan_scan_ipmi.txt | 6 +- docs/man/nutscan_scan_nut.txt | 6 +- docs/man/nutscan_scan_snmp.txt | 6 +- docs/man/nutscan_scan_usb.txt | 6 +- docs/man/nutscan_scan_xml_http_range.txt | 6 +- tools/nut-scanner/nut-scan.h | 6 + tools/nut-scanner/nut-scanner.c | 12 +- tools/nut-scanner/nutscan-display.c | 183 ++++++++++++++++++ 26 files changed, 405 insertions(+), 9 deletions(-) create mode 100644 docs/man/nutscan_display_sanity_check.txt create mode 100644 docs/man/nutscan_display_sanity_check_serial.txt create mode 100644 docs/man/nutscan_display_ups_conf_with_sanity_check.txt diff --git a/NEWS b/NEWS index 17f42d52ce..fba4e94833 100644 --- a/NEWS +++ b/NEWS @@ -184,6 +184,10 @@ https://github.com/networkupstools/nut/milestone/8 abort and require either to install the dependency or explicitly forfeit the tool (some distro packages missed it quietly in the past) [#1560] + - The `nut-scanner` program should now by default warn about serial numbers + which do not make much sense (are duplicate, empty, all same character, etc) + [#1810] + - Existing openssl-1.1.0 support added for NUT v2.8.0 release was tested to be sufficient without deprecation warnings for builds against openssl-3.0.x (but no real-time testing was done yet) [#1547] diff --git a/UPGRADING b/UPGRADING index 701d8412c4..85d4ea7769 100644 --- a/UPGRADING +++ b/UPGRADING @@ -31,6 +31,10 @@ Changes from 2.8.0 to 2.8.1 device configuration [#1790]: hopefully these would now suffice for sufficiently unique combinations; + * The `nut-scanner` tool should also suggest sanity-check violations + as comments in its generated device configuration [#1810], e.g. bogus + or duplicate serial number values; + * The common USB matching logic was updated with an `allow_duplicates` flag (caveat emptor!) which may help monitor several related no-name devices on systems that do not discern "bus" and "device" values diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index 146e7c525c..3dcf7f609b 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -177,6 +177,9 @@ SRC_DEV_PAGES = \ nutscan_scan_avahi.txt \ nutscan_scan_ipmi.txt \ nutscan_scan_eaton_serial.txt \ + nutscan_display_sanity_check.txt \ + nutscan_display_sanity_check_serial.txt \ + nutscan_display_ups_conf_with_sanity_check.txt \ nutscan_display_ups_conf.txt \ nutscan_display_parsable.txt \ nutscan_cidr_to_ip.txt \ @@ -290,6 +293,9 @@ MAN3_DEV_PAGES = \ nutscan_scan_avahi.3 \ nutscan_scan_ipmi.3 \ nutscan_scan_eaton_serial.3 \ + nutscan_display_sanity_check.3 \ + nutscan_display_sanity_check_serial.3 \ + nutscan_display_ups_conf_with_sanity_check.3 \ nutscan_display_ups_conf.3 \ nutscan_display_parsable.3 \ nutscan_cidr_to_ip.3 \ @@ -352,6 +358,9 @@ HTML_DEV_MANS = \ nutscan_scan_avahi.html \ nutscan_scan_ipmi.html \ nutscan_scan_eaton_serial.html \ + nutscan_display_sanity_check.html \ + nutscan_display_sanity_check_serial.html \ + nutscan_display_ups_conf_with_sanity_check.html \ nutscan_display_ups_conf.html \ nutscan_display_parsable.html \ nutscan_cidr_to_ip.html \ diff --git a/docs/man/nut-scanner.txt b/docs/man/nut-scanner.txt index 95603603dd..b4e6e543db 100644 --- a/docs/man/nut-scanner.txt +++ b/docs/man/nut-scanner.txt @@ -37,6 +37,10 @@ Display the help text. DISPLAY OPTIONS --------------- +*-Q* | *--disp_nut_conf_with_sanity_check*:: +Display result in the 'ups.conf' format with sanity-check warnings (if any) +as comments (default). + *-N* | *--disp_nut_conf*:: Display result in the 'ups.conf' format. diff --git a/docs/man/nutscan.txt b/docs/man/nutscan.txt index 99cb2471e2..bfef09f52b 100644 --- a/docs/man/nutscan.txt +++ b/docs/man/nutscan.txt @@ -43,7 +43,9 @@ linkman:nutscan_add_device_to_device[3]. Helper functions are also provided to output data using standard formats: - linkman:nutscan_display_parsable[3] for parsable output, -- linkman:nutscan_display_ups_conf[3] for ups.conf style. +- linkman:nutscan_display_ups_conf[3] for ups.conf style, +- linkman:nutscan_display_ups_conf_with_sanity_check[3] for ups.conf style + with comments for warnings about possible configuration problems (if any). ERROR HANDLING @@ -59,6 +61,9 @@ linkman:nut-scanner[8], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_device_to_device[3], diff --git a/docs/man/nutscan_add_option_to_device.txt b/docs/man/nutscan_add_option_to_device.txt index 2dbf6690c0..b7a5262402 100644 --- a/docs/man/nutscan_add_option_to_device.txt +++ b/docs/man/nutscan_add_option_to_device.txt @@ -38,6 +38,12 @@ associated 'value'. Copies of 'option_name' and 'value' are stored in the device, so the caller can safely free both of the original strings used as arguments. +Such options and their values may be further sanity-checked and reported +as warnings by *nutscan_display_sanity_check()* dispatcher and its related +methods which implement the logic of particular checks. This is used for +example when generating 'ups.conf' file content suggestions with +*nutscan_display_ups_conf_with_sanity_check()* method. + NOTES ----- @@ -49,6 +55,9 @@ SEE ALSO linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_device_to_device[3] diff --git a/docs/man/nutscan_cidr_to_ip.txt b/docs/man/nutscan_cidr_to_ip.txt index 5f18213eeb..ef7c9a9c1a 100644 --- a/docs/man/nutscan_cidr_to_ip.txt +++ b/docs/man/nutscan_cidr_to_ip.txt @@ -40,4 +40,5 @@ SEE ALSO linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3] diff --git a/docs/man/nutscan_display_parsable.txt b/docs/man/nutscan_display_parsable.txt index 9e275153be..aa2cc76e4b 100644 --- a/docs/man/nutscan_display_parsable.txt +++ b/docs/man/nutscan_display_parsable.txt @@ -29,12 +29,19 @@ which is: * and depend on , see the corresponding driver's man page. +Note that this format is for machine consumption, so is not associated +with sanity checks that may be used along with display method for the +'ups.conf' file format. + SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_display_sanity_check.txt b/docs/man/nutscan_display_sanity_check.txt new file mode 100644 index 0000000000..f0e6ce4eb0 --- /dev/null +++ b/docs/man/nutscan_display_sanity_check.txt @@ -0,0 +1,39 @@ +NUTSCAN_DISPLAY_SANITY_CHECK(3) +=============================== + +NAME +---- + +nutscan_display_sanity_check - Display sanity check warnings about +the specified `nutscan_device_t` structure on stdout. + +SYNOPSIS +-------- + + #include + + void nutscan_display_sanity_check(nutscan_device_t * device); + +DESCRIPTION +----------- + +The *nutscan_display_sanity_check()* function calls all sanity-check +analyzers against displays all NUT devices in 'device', and they may +print comments to stdout. It displays them in a way that it can be +directly copied into the 'ups.conf' file. + +It is called from *nutscan_display_ups_conf_with_sanity_check()* to +provide an aggregate content for 'ups.conf' file in one shot. + +SEE ALSO +-------- + +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], +linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], +linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], +linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], +linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_display_sanity_check_serial.txt b/docs/man/nutscan_display_sanity_check_serial.txt new file mode 100644 index 0000000000..243b15a341 --- /dev/null +++ b/docs/man/nutscan_display_sanity_check_serial.txt @@ -0,0 +1,43 @@ +NUTSCAN_DISPLAY_SANITY_CHECK_SERIAL(3) +====================================== + +NAME +---- + +nutscan_display_sanity_check_serial - Display sanity check warnings +about "serial" (serial number/code string) optional values in the +specified `nutscan_device_t` structure on stdout. + +SYNOPSIS +-------- + + #include + + void nutscan_display_sanity_check_serial(nutscan_device_t * device); + +DESCRIPTION +----------- + +The *nutscan_display_sanity_check_serial()* function analyzes "serial" +optional field in all NUT devices in 'device', and in case of duplicate +or otherwise seemingly invalid values, prints comments to stdout. +It displays them in a way that it can be directly copied into the +'ups.conf' file. + +It is called from *nutscan_display_ups_conf_with_sanity_check()* to +provide an aggregate content for 'ups.conf' file in one shot. + +SEE ALSO +-------- + +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], +linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], +linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], +linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], +linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_display_ups_conf.txt b/docs/man/nutscan_display_ups_conf.txt index b79c90fa0c..3b6233ac9d 100644 --- a/docs/man/nutscan_display_ups_conf.txt +++ b/docs/man/nutscan_display_ups_conf.txt @@ -21,12 +21,18 @@ The *nutscan_display_ups_conf()* function displays all NUT devices in 'device' to stdout. It displays them in a way that it can be directly copied into the 'ups.conf' file. +It is called from *nutscan_display_ups_conf_with_sanity_check()* to +provide an aggregate content for 'ups.conf' file in one shot. + SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_display_ups_conf_with_sanity_check.txt b/docs/man/nutscan_display_ups_conf_with_sanity_check.txt new file mode 100644 index 0000000000..838375eb36 --- /dev/null +++ b/docs/man/nutscan_display_ups_conf_with_sanity_check.txt @@ -0,0 +1,36 @@ +NUTSCAN_DISPLAY_UPS_CONF_WITH_SANITY_CHECK(3) +============================================= + +NAME +---- + +nutscan_display_ups_conf_with_sanity_check - Display the specified +`nutscan_device_t` structure and sanity-check warnings on stdout. + +SYNOPSIS +-------- + + #include + + void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device); + +DESCRIPTION +----------- + +The *nutscan_display_ups_conf_with_sanity_check()* function displays +all NUT devices in 'device' to stdout, and follows up with comments +about sanity-check violations (if any). It displays them in a way that +it can be directly copied into the 'ups.conf' file. + +SEE ALSO +-------- + +linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], +linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], +linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], +linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], +linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_free_device.txt b/docs/man/nutscan_free_device.txt index 4420f362e2..7ef10cc3ad 100644 --- a/docs/man/nutscan_free_device.txt +++ b/docs/man/nutscan_free_device.txt @@ -32,6 +32,7 @@ SEE ALSO linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3] diff --git a/docs/man/nutscan_get_serial_ports_list.txt b/docs/man/nutscan_get_serial_ports_list.txt index 8b38bedbbf..bf8aa26d89 100644 --- a/docs/man/nutscan_get_serial_ports_list.txt +++ b/docs/man/nutscan_get_serial_ports_list.txt @@ -56,4 +56,5 @@ linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_eaton_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3] diff --git a/docs/man/nutscan_init.txt b/docs/man/nutscan_init.txt index 17e6ddf91d..6d372e0ce3 100644 --- a/docs/man/nutscan_init.txt +++ b/docs/man/nutscan_init.txt @@ -46,6 +46,9 @@ linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3] diff --git a/docs/man/nutscan_new_device.txt b/docs/man/nutscan_new_device.txt index 81cf26d164..43581599ec 100644 --- a/docs/man/nutscan_new_device.txt +++ b/docs/man/nutscan_new_device.txt @@ -37,5 +37,8 @@ linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3] linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3] +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3] linkman:nutscan_add_device_to_device[3] diff --git a/docs/man/nutscan_scan_avahi.txt b/docs/man/nutscan_scan_avahi.txt index 01f02e9e92..5c407d3d7b 100644 --- a/docs/man/nutscan_scan_avahi.txt +++ b/docs/man/nutscan_scan_avahi.txt @@ -41,6 +41,9 @@ linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3], diff --git a/docs/man/nutscan_scan_eaton_serial.txt b/docs/man/nutscan_scan_eaton_serial.txt index 068db12877..42e2a826ec 100644 --- a/docs/man/nutscan_scan_eaton_serial.txt +++ b/docs/man/nutscan_scan_eaton_serial.txt @@ -40,6 +40,9 @@ linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], diff --git a/docs/man/nutscan_scan_ipmi.txt b/docs/man/nutscan_scan_ipmi.txt index 9d463f477d..a1fddcfce8 100644 --- a/docs/man/nutscan_scan_ipmi.txt +++ b/docs/man/nutscan_scan_ipmi.txt @@ -50,7 +50,11 @@ SEE ALSO linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], -linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_scan_snmp[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], diff --git a/docs/man/nutscan_scan_nut.txt b/docs/man/nutscan_scan_nut.txt index 7d0b543c84..08c6520c88 100644 --- a/docs/man/nutscan_scan_nut.txt +++ b/docs/man/nutscan_scan_nut.txt @@ -46,7 +46,11 @@ SEE ALSO linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], -linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_scan_ipmi[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], diff --git a/docs/man/nutscan_scan_snmp.txt b/docs/man/nutscan_scan_snmp.txt index ecc893ffb9..3ae72ccfd1 100644 --- a/docs/man/nutscan_scan_snmp.txt +++ b/docs/man/nutscan_scan_snmp.txt @@ -82,7 +82,11 @@ SEE ALSO linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], -linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_scan_ipmi[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], diff --git a/docs/man/nutscan_scan_usb.txt b/docs/man/nutscan_scan_usb.txt index 878c712a92..25d2b6ddb0 100644 --- a/docs/man/nutscan_scan_usb.txt +++ b/docs/man/nutscan_scan_usb.txt @@ -33,7 +33,11 @@ SEE ALSO linkman:nutscan_init[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], -linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_scan_ipmi[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3] diff --git a/docs/man/nutscan_scan_xml_http_range.txt b/docs/man/nutscan_scan_xml_http_range.txt index 15cb2af5c1..70e0a86b23 100644 --- a/docs/man/nutscan_scan_xml_http_range.txt +++ b/docs/man/nutscan_scan_xml_http_range.txt @@ -48,7 +48,11 @@ SEE ALSO linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], -linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_scan_ipmi[3], +linkman:nutscan_display_sanity_check[3], +linkman:nutscan_display_sanity_check_serial[3], +linkman:nutscan_display_ups_conf_with_sanity_check[3], +linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3] diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index d71d690c01..ae5f8f42cd 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -4,6 +4,7 @@ * 2012 - Arnaud Quette * 2016 - EATON - IP addressed XML scan * 2016-2021 - EATON - Various threads-related improvements + * 2023 - Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -172,6 +173,11 @@ sem_t * nutscan_semaphore(void); void nutscan_display_ups_conf(nutscan_device_t * device); void nutscan_display_parsable(nutscan_device_t * device); +/* Display sanity-check concerns for various fields etc. (if any) */ +void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device); +void nutscan_display_sanity_check(nutscan_device_t * device); +void nutscan_display_sanity_check_serial(nutscan_device_t * device); + #ifdef __cplusplus /* *INDENT-OFF* */ } diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index c1b76a09ac..05e28f7d00 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 - 2012 Arnaud Quette * Copyright (C) 2016 Michal Vyskocil - * Copyright (C) 2016 - 2021 Jim Klimov + * Copyright (C) 2016 - 2023 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,7 +61,7 @@ #define ERR_BAD_OPTION (-1) -static const char optstring[] = "?ht:T:s:e:E:c:l:u:W:X:w:x:p:b:B:d:L:CUSMOAm:NPqIVaD"; +static const char optstring[] = "?ht:T:s:e:E:c:l:u:W:X:w:x:p:b:B:d:L:CUSMOAm:QNPqIVaD"; #ifdef HAVE_GETOPT_LONG static const struct option longopts[] = { @@ -90,6 +90,7 @@ static const struct option longopts[] = { { "oldnut_scan", no_argument, NULL, 'O' }, { "avahi_scan", no_argument, NULL, 'A' }, { "ipmi_scan", no_argument, NULL, 'I' }, + { "disp_nut_conf_with_sanity_check", no_argument, NULL, 'Q' }, { "disp_nut_conf", no_argument, NULL, 'N' }, { "disp_parsable", no_argument, NULL, 'P' }, { "quiet", no_argument, NULL, 'q' }, @@ -329,6 +330,7 @@ static void show_usage() printf("\nNUT specific options:\n"); printf(" -p, --port : Port number of remote NUT upsd\n"); printf("\ndisplay specific options:\n"); + printf(" -Q, --disp_nut_conf_with_sanity_check: Display result in the ups.conf format with sanity-check warnings as comments (default)\n"); printf(" -N, --disp_nut_conf: Display result in the ups.conf format\n"); printf(" -P, --disp_parsable: Display result in a parsable format\n"); printf("\nMiscellaneous options:\n"); @@ -413,7 +415,8 @@ int main(int argc, char *argv[]) nutscan_init(); - display_func = nutscan_display_ups_conf; + /* Default, see -Q/-N/-P below */ + display_func = nutscan_display_ups_conf_with_sanity_check; /* Parse command line options -- Second loop: everything else */ /* Restore error messages... */ @@ -631,6 +634,9 @@ int main(int argc, char *argv[]) } allow_ipmi = 1; break; + case 'Q': + display_func = nutscan_display_ups_conf_with_sanity_check; + break; case 'N': display_func = nutscan_display_ups_conf; break; diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index 71f2248b15..e31d05f1dd 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 - EATON + * 2023 - Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ #include #include "nutscan-device.h" #include "nut-scan.h" +#include "nut_stdint.h" static char * nutscan_device_type_string[TYPE_END] = { "NONE", @@ -37,6 +39,12 @@ static char * nutscan_device_type_string[TYPE_END] = { "EATON_SERIAL" }; +void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device) +{ + nutscan_display_ups_conf(device); + nutscan_display_sanity_check(device); +} + void nutscan_display_ups_conf(nutscan_device_t * device) { nutscan_device_t * current_dev = device; @@ -119,3 +127,178 @@ void nutscan_display_parsable(nutscan_device_t * device) } while (current_dev != NULL); } + +/* TODO: If this is ever a memory-pressure problem, + * e.g. if preparing to monitor hundreds of devices, + * can convert to dynamically allocated (and freed) + * strings. For now go for speed with static arrays. + */ +typedef struct keyval_strings { + char key[SMALLBUF]; + char val[LARGEBUF]; +} keyval_strings_t; + +void nutscan_display_sanity_check_serial(nutscan_device_t * device) +{ + /* Some devices have useless serial numbers + * (empty strings, all-zeroes, all-spaces etc.) + * and others have identical serial numbers on + * physically different hardware units. + * Warn about these as a possible problem e.g. + * for matching and discerning devices generally. + * Note that we may also have multiple data paths + * to the same device (e.g. monitored over USB + * and SNMP, so the situation is not necessarily + * a problem). + * Also note that not all devices may have/report + * a serial at all (option will be missing). + */ + nutscan_device_t * current_dev = device; + nutscan_options_t * opt; + int nutdev_num = 1; + size_t listlen = 0, count = 0, i; + keyval_strings_t *map = NULL, *entry = NULL; + + if (device == NULL) { + return; + } + + /* Find end of the list */ + while (current_dev->next != NULL) { + current_dev = current_dev->next; + } + + /* Find start of the list and count its size */ + while (current_dev->prev != NULL) { + current_dev = current_dev->prev; + listlen++; + } + + /* Empty? No bogus data or conflicts at least... */ + if (!listlen) { + return; + } + + /* Process each device: + * Build a map of "serial"=>"nutdevX[,...,nutdevZ]" + * and warn if there are bogus "serial" keys or if + * there are several nutdev's (a comma in value). + */ + + /* Reserve enough slots for all-unique serials */ + map = calloc(sizeof(keyval_strings_t), listlen); + if (map == NULL) { + fprintf(stderr, "%s: Memory allocation error, skipped\n", __func__); + return; + } + + do { + /* Look for serial option in current device */ + opt = current_dev->opt; + + while (NULL != opt) { + if (opt->option != NULL && !strcmp(opt->option, "serial")) { + /* This nutdevX has a serial; is it in map already? */ + char keytmp[SMALLBUF]; + snprintf(keytmp, sizeof(keytmp), "%s", + opt->value ? (opt->value[0] ? opt->value : "") : ""); + + for (i = 0, entry = NULL; i < listlen && map[i].key[0] != '\0'; i++) { + if (!strncmp(map[i].key, keytmp, sizeof(map[i].key))) { + entry = &(map[i]); + break; + } + } + + if (entry) { + /* Got a hit => append value */ + /* TODO: If changing from preallocated LARGEBUF to + * dynamic allocation, malloc data for larger "val". + */ + snprintfcat(entry->val, sizeof(entry->val), + ",nutdev%i", nutdev_num); + } else { + /* No hit => new key */ + /* TODO: If changing from preallocated LARGEBUF to + * dynamic allocation, malloc data for new "entry" + * and its key/val fields. + */ + entry = &(map[i]); + + count++; + if (count != i || count > listlen) { + /* Should never get here, but just in case... */ + fprintf(stderr, "%s: Loop overflow, skipped\n", __func__); + goto exit; + } + + snprintf(entry->key, sizeof(entry->key), + "%s", keytmp); + snprintf(entry->val, sizeof(entry->val), + "nutdev%i", nutdev_num); + } + + /* Abort the opt-searching loop for this device */ + goto next; + } + opt = opt->next; + } + +next: + nutdev_num++; + + current_dev = current_dev->next; + } + while (current_dev != NULL); + + if (!count) { + /* No serials in found devices? Oh well */ + goto exit; + } + + /* Now look for red flags in the map */ + /* FIXME: Weed out special chars to avoid breaking comment-line markup? + * Thinking of ASCII control codes < 32 including CR/LF, and codes 128+... */ + for (i = 0; i < count; i++) { + size_t j; + entry = &(map[i]); + + /* NULL or empty serials */ + if (!strcmp(entry->key, "") || !strcmp(entry->key, "")) { + printf("\n# WARNING: %s \"serial\" reported in some devices: %s\n", + entry->key, entry->val); + continue; + } + + /* All chars in "serial" are same (zero, space, etc.) */ + for (j = 0; entry->key[j] != '\0' && entry->key[j] == entry->key[0]; j++); + if (j > 0 && entry->key[j] == '\0') { + printf("\n# WARNING: all-same character \"serial\" " + "with %" PRIuSIZE " copies of '%c' (0x%02X) " + "reported in some devices: %s\n", + j, entry->key[0], entry->key[0], entry->val); + continue; + } + + /* Duplicates (maybe same device, maybe not) */ + for (j = 0; entry->val[j] != '\0' && entry->val[j] != ','; j++); + if (j > 0 && entry->key[j] != '\0') { + printf("\n# WARNING: same \"serial\" value \"%s\" " + "reported in several device configurations " + "(maybe okay if multiple drivers for same device, " + "likely a vendor bug if reported by same driver " + "for many devices): %s\n", + entry->key, entry->val); + continue; + } + } + +exit: + free (map); +} + +void nutscan_display_sanity_check(nutscan_device_t * device) +{ + /* Extend the list later as more sanity-checking appears */ + nutscan_display_sanity_check_serial(device); +} From 040df4db5f9126d069707aadf79de77f3a69807f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 14 Jan 2023 23:43:26 +0100 Subject: [PATCH 2/6] tools/nut-scanner/nutscan-display.c: trace entry into the display methods [#1810] --- tools/nut-scanner/nutscan-display.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index e31d05f1dd..fdadd37f81 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -41,6 +41,9 @@ static char * nutscan_device_type_string[TYPE_END] = { void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device) { + upsdebugx(2, "%s: %s", __func__, device + ? (device->type < TYPE_END ? nutscan_device_type_string[device->type] : "") + : ""); nutscan_display_ups_conf(device); nutscan_display_sanity_check(device); } @@ -51,6 +54,10 @@ void nutscan_display_ups_conf(nutscan_device_t * device) nutscan_options_t * opt; static int nutdev_num = 1; + upsdebugx(2, "%s: %s", __func__, device + ? (device->type < TYPE_END ? nutscan_device_type_string[device->type] : "") + : ""); + if (device == NULL) { return; } @@ -91,6 +98,10 @@ void nutscan_display_parsable(nutscan_device_t * device) nutscan_device_t * current_dev = device; nutscan_options_t * opt; + upsdebugx(2, "%s: %s", __func__, device + ? (device->type < TYPE_END ? nutscan_device_type_string[device->type] : "") + : ""); + if (device == NULL) { return; } @@ -159,6 +170,10 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) size_t listlen = 0, count = 0, i; keyval_strings_t *map = NULL, *entry = NULL; + upsdebugx(2, "%s: %s", __func__, device + ? (device->type < TYPE_END ? nutscan_device_type_string[device->type] : "") + : ""); + if (device == NULL) { return; } @@ -299,6 +314,10 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) void nutscan_display_sanity_check(nutscan_device_t * device) { + upsdebugx(2, "%s: %s", __func__, device + ? (device->type < TYPE_END ? nutscan_device_type_string[device->type] : "") + : ""); + /* Extend the list later as more sanity-checking appears */ nutscan_display_sanity_check_serial(device); } From a40db655cf1eb97059f04b74eba49baaa76016e2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 14 Jan 2023 23:52:09 +0100 Subject: [PATCH 3/6] tools/nut-scanner/nutscan-display.c: nutscan_display_sanity_check_serial(): trace progress through logic [#1810] --- tools/nut-scanner/nutscan-display.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index fdadd37f81..e30d13e987 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -207,6 +207,9 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) return; } + upsdebugx(3, "%s: checking serial numbers for %" PRIuSIZE " device configuration(s)", + __func__, listlen); + do { /* Look for serial option in current device */ opt = current_dev->opt; @@ -227,6 +230,9 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) if (entry) { /* Got a hit => append value */ + upsdebugx(3, "%s: duplicate entry for serial '%s'", + __func__, keytmp); + /* TODO: If changing from preallocated LARGEBUF to * dynamic allocation, malloc data for larger "val". */ @@ -234,6 +240,9 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) ",nutdev%i", nutdev_num); } else { /* No hit => new key */ + upsdebugx(3, "%s: new entry for serial '%s'", + __func__, keytmp); + /* TODO: If changing from preallocated LARGEBUF to * dynamic allocation, malloc data for new "entry" * and its key/val fields. @@ -244,6 +253,8 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) if (count != i || count > listlen) { /* Should never get here, but just in case... */ fprintf(stderr, "%s: Loop overflow, skipped\n", __func__); + upsdebugx(3, "%s: count=%" PRIuSIZE " i=%" PRIuSIZE " listlen%" PRIuSIZE, + __func__, count, i, listlen); goto exit; } From fb1856d46eceb7b22fcd6a12a18e37174d63d1f4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 14 Jan 2023 23:52:30 +0100 Subject: [PATCH 4/6] tools/nut-scanner/nutscan-display.c: nutscan_display_sanity_check_serial(): if not null, one device entry exists [#1810] --- tools/nut-scanner/nutscan-display.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index e30d13e987..95ed0c98f3 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -178,6 +178,9 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) return; } + /* At least one entry exists... */ + listlen++; + /* Find end of the list */ while (current_dev->next != NULL) { current_dev = current_dev->next; @@ -189,11 +192,6 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) listlen++; } - /* Empty? No bogus data or conflicts at least... */ - if (!listlen) { - return; - } - /* Process each device: * Build a map of "serial"=>"nutdevX[,...,nutdevZ]" * and warn if there are bogus "serial" keys or if From 7304fc54390245a987e7c9be82598ab3c3a65255 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 14 Jan 2023 23:53:00 +0100 Subject: [PATCH 5/6] tools/nut-scanner/nutscan-display.c: nutscan_display_sanity_check_serial(): fix failsafe condition [#1810] --- tools/nut-scanner/nutscan-display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index 95ed0c98f3..b4e562c2ef 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -248,7 +248,7 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) entry = &(map[i]); count++; - if (count != i || count > listlen) { + if (count != (i + 1) || count > listlen) { /* Should never get here, but just in case... */ fprintf(stderr, "%s: Loop overflow, skipped\n", __func__); upsdebugx(3, "%s: count=%" PRIuSIZE " i=%" PRIuSIZE " listlen%" PRIuSIZE, From 10e0d0b093d69bf632f2a0a85d0809f82906c65a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 15 Jan 2023 00:01:24 +0100 Subject: [PATCH 6/6] tools/nut-scanner/nutscan-display.c: weave nutdevX numbering for different scan types when generating ups.conf with sanity-check warnings with a global var [#1810] --- tools/nut-scanner/nutscan-display.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index b4e562c2ef..9cfa2716ec 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -39,6 +39,8 @@ static char * nutscan_device_type_string[TYPE_END] = { "EATON_SERIAL" }; +static int last_nutdev_num = 0; + void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device) { upsdebugx(2, "%s: %s", __func__, device @@ -91,6 +93,8 @@ void nutscan_display_ups_conf(nutscan_device_t * device) current_dev = current_dev->next; } while (current_dev != NULL); + + last_nutdev_num = nutdev_num; } void nutscan_display_parsable(nutscan_device_t * device) @@ -164,9 +168,19 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) * Also note that not all devices may have/report * a serial at all (option will be missing). */ + /* FIXME: Currently this is normally called as part + * of nutscan_display_ups_conf_with_sanity_check() + * and nut-scanner goes over each type separately. + * So with current approach it will not see "issues" + * with multiple data paths (e.g. USB and SNMP) to + * same device. + */ nutscan_device_t * current_dev = device; nutscan_options_t * opt; - int nutdev_num = 1; + /* Keep numbering consistent with global entry naming. + * Note its last value is after loop, so "real + 1". + */ + int nutdev_num = last_nutdev_num - 1; size_t listlen = 0, count = 0, i; keyval_strings_t *map = NULL, *entry = NULL;