new upstream 2.8.0

This commit is contained in:
lagertonne 2022-06-29 12:37:36 +02:00
parent fc7f4b43c1
commit b2b0c9995a
836 changed files with 137090 additions and 30018 deletions

View file

@ -1,7 +1,47 @@
BUILT_SOURCES = nutscan-usb.h nutscan-snmp.h
# Generally, list headers and/or sources which are re-generated
# for nut-scanner in the parent dir
NUT_SCANNER_DEPS_H = nutscan-usb.h nutscan-snmp.h
NUT_SCANNER_DEPS_C =
nutscan-usb.h nutscan-snmp.h:
cd ..; $(MAKE) $(AM_MAKEFLAGS) nut-scanner-deps
# General set of nut-scanner dependencies generated in the parent dir
NUT_SCANNER_DEPS = $(NUT_SCANNER_DEPS_H) $(NUT_SCANNER_DEPS_C)
BUILT_SOURCES = $(NUT_SCANNER_DEPS)
CLEANFILES = $(BUILT_SOURCES)
# Make sure we have the freshest files (no-op if built earlier and then
# no driver sources and other dependencies were edited by a developer)
$(NUT_SCANNER_DEPS): dummy
@cd .. && $(MAKE) $(AM_MAKEFLAGS) nut-scanner-deps
# Make sure out-of-dir dependencies exist (especially when dev-building parts):
$(top_builddir)/common/libcommon.la: dummy
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
# do not hard depend on '../include/nut_version.h', since it blocks
# 'dist', and is only required for actual build, in which case
# BUILT_SOURCES (in ../include) will ensure nut_version.h will
# be built before anything else
nut-scanner.c: $(top_builddir)/include/nut_version.h
LINKED_SOURCE_FILES =
# Separate the .deps of other dirs from this one
# NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver
# of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS
LINKED_SOURCE_FILES += serial.c
serial.c: $(top_srcdir)/drivers/serial.c
test -s "$@" || ln -s -f "$(top_srcdir)/drivers/serial.c" "$@"
LINKED_SOURCE_FILES += bcmxcp_ser.c
bcmxcp_ser.c: $(top_srcdir)/drivers/bcmxcp_ser.c
test -s "$@" || ln -s -f "$(top_srcdir)/drivers/bcmxcp_ser.c" "$@"
CLEANFILES += $(LINKED_SOURCE_FILES)
BUILT_SOURCES += $(LINKED_SOURCE_FILES)
$(top_builddir)/include/nut_version.h:
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
# Only build nut-scanner, and its library, if libltdl was found (required!)
if WITH_LIBLTDL
@ -10,18 +50,39 @@ if WITH_LIBLTDL
endif
libnutscan_la_SOURCES = scan_nut.c scan_ipmi.c \
nutscan-device.c nutscan-ip.c nutscan-display.c \
nutscan-init.c scan_usb.c scan_snmp.c scan_xml_http.c \
scan_avahi.c scan_eaton_serial.c nutscan-serial.c \
../../drivers/serial.c \
../../drivers/bcmxcp_ser.c \
../../common/common.c
libnutscan_la_LIBADD = $(NETLIBS) $(LIBLTDL_LIBS)
libnutscan_la_LDFLAGS = $(SERLIBS) -version-info 1:0:0
libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include $(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers
nutscan-init.c scan_usb.c scan_snmp.c scan_xml_http.c \
scan_avahi.c scan_eaton_serial.c nutscan-serial.c
nodist_libnutscan_la_SOURCES = $(LINKED_SOURCE_FILES)
libnutscan_la_LIBADD = $(NETLIBS)
if WITH_LIBLTDL
libnutscan_la_LIBADD += $(LIBLTDL_LIBS)
endif
libnutscan_la_LIBADD += $(top_builddir)/common/libcommonclient.la
#
# Below we set API versions of public libraries
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# Note that changes here may have to be reflected in packaging (the shared
# object .so names would differ)
#
# libnutscan version information
libnutscan_la_LDFLAGS = $(SERLIBS) -version-info 2:0:0
# libnutscan exported symbols regex
# WARNING: Since the library includes parts of libcommon (as much as needed
# e.g. for logging or string manipulations), we export a few symbols from
# those too. This may cause issues for (third-party) code development that
# would use both libnutscan and libcommon or similar libs. Here we did have
# a problem with nut-scanner using two copies of common.c and conflicting
# copies of "nut_debug_level" making fun of our debug-logging attempts.
# One solution to tackle if needed for those cases would be to make some
# dynamic/shared libnutcommon (etc.)
libnutscan_la_LDFLAGS += -export-symbols-regex '^(nutscan_|nut_debug_level|s_upsdebugx|max_threads|curr_threads)'
libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include \
$(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers
nut_scanner_SOURCES = nut-scanner.c
nut_scanner_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include
nut_scanner_LDADD = libnutscan.la ../../common/libcommon.la
nut_scanner_LDADD = libnutscan.la
if WITH_SSL
libnutscan_la_CFLAGS += $(LIBSSL_CFLAGS)
@ -43,13 +104,21 @@ if WITH_IPMI
libnutscan_la_CFLAGS += $(LIBIPMI_CFLAGS)
endif
dist_noinst_HEADERS = nutscan-usb.h nutscan-snmp.h
# C is not a header, but there is no dist_noinst_SOURCES
dist_noinst_HEADERS = $(NUT_SCANNER_DEPS_H) $(NUT_SCANNER_DEPS_C)
if WITH_DEV
include_HEADERS = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h
include_HEADERS = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
else
dist_noinst_HEADERS += nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
endif
CLEANFILES = nutscan-usb.h nutscan-snmp.h
dummy:
CLEANFILES += *-spellchecked
MAINTAINERCLEANFILES = Makefile.in .dirstamp
# NOTE: Do not clean ".deps" in SUBDIRS of the main project,
# the root Makefile.am takes care of that!
#clean-local:
# rm -rf $(builddir)/.deps

View file

@ -1,7 +1,7 @@
# Makefile.in generated by automake 1.14.1 from Makefile.am.
# Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -17,7 +17,17 @@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@ -82,29 +92,34 @@ build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
@WITH_LIBLTDL_TRUE@bin_PROGRAMS = nut-scanner$(EXEEXT)
@WITH_SSL_TRUE@am__append_1 = $(LIBSSL_CFLAGS)
@WITH_SSL_TRUE@am__append_2 = $(LIBSSL_LIBS)
@WITH_USB_TRUE@am__append_3 = $(LIBUSB_CFLAGS)
@WITH_SNMP_TRUE@am__append_4 = $(LIBNETSNMP_CFLAGS)
@WITH_NEON_TRUE@am__append_5 = $(LIBNEON_CFLAGS)
@WITH_AVAHI_TRUE@am__append_6 = $(LIBAVAHI_CFLAGS)
@WITH_IPMI_TRUE@am__append_7 = $(LIBIPMI_CFLAGS)
@WITH_DEV_FALSE@am__append_8 = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
@WITH_LIBLTDL_TRUE@am__append_1 = $(LIBLTDL_LIBS)
@WITH_SSL_TRUE@am__append_2 = $(LIBSSL_CFLAGS)
@WITH_SSL_TRUE@am__append_3 = $(LIBSSL_LIBS)
@WITH_USB_TRUE@am__append_4 = $(LIBUSB_CFLAGS)
@WITH_SNMP_TRUE@am__append_5 = $(LIBNETSNMP_CFLAGS)
@WITH_NEON_TRUE@am__append_6 = $(LIBNEON_CFLAGS)
@WITH_AVAHI_TRUE@am__append_7 = $(LIBAVAHI_CFLAGS)
@WITH_IPMI_TRUE@am__append_8 = $(LIBIPMI_CFLAGS)
@WITH_DEV_FALSE@am__append_9 = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
subdir = tools/nut-scanner
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp $(am__dist_noinst_HEADERS_DIST) \
$(am__include_HEADERS_DIST) README
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \
$(top_srcdir)/m4/ax_c_pragmas.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_compare_version.m4 \
$(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nut_arg_with.m4 \
$(top_srcdir)/m4/nut_check_asciidoc.m4 \
$(top_srcdir)/m4/nut_check_cppcheck.m4 \
$(top_srcdir)/m4/nut_check_headers_windows.m4 \
$(top_srcdir)/m4/nut_check_libavahi.m4 \
$(top_srcdir)/m4/nut_check_libfreeipmi.m4 \
$(top_srcdir)/m4/nut_check_libgd.m4 \
$(top_srcdir)/m4/nut_check_libltdl.m4 \
$(top_srcdir)/m4/nut_check_libmodbus.m4 \
$(top_srcdir)/m4/nut_check_libneon.m4 \
$(top_srcdir)/m4/nut_check_libnetsnmp.m4 \
$(top_srcdir)/m4/nut_check_libnss.m4 \
@ -113,15 +128,25 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
$(top_srcdir)/m4/nut_check_libusb.m4 \
$(top_srcdir)/m4/nut_check_libwrap.m4 \
$(top_srcdir)/m4/nut_check_os.m4 \
$(top_srcdir)/m4/nut_check_pkgconfig.m4 \
$(top_srcdir)/m4/nut_check_python.m4 \
$(top_srcdir)/m4/nut_compiler_family.m4 \
$(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \
$(top_srcdir)/m4/nut_report_feature.m4 \
$(top_srcdir)/m4/nut_stash_warnings.m4 \
$(top_srcdir)/m4/nut_type_socklen_t.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_noinst_HEADERS_DIST) \
$(am__include_HEADERS_DIST) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \
"$(DESTDIR)$(includedir)"
PROGRAMS = $(bin_PROGRAMS)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@ -149,25 +174,25 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
am__DEPENDENCIES_1 =
@WITH_SSL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
@WITH_LIBLTDL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
@WITH_SSL_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
libnutscan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am__dirstamp = $(am__leading_dot)dirstamp
$(am__DEPENDENCIES_2) \
$(top_builddir)/common/libcommonclient.la \
$(am__DEPENDENCIES_3)
am_libnutscan_la_OBJECTS = libnutscan_la-scan_nut.lo \
libnutscan_la-scan_ipmi.lo libnutscan_la-nutscan-device.lo \
libnutscan_la-nutscan-ip.lo libnutscan_la-nutscan-display.lo \
libnutscan_la-nutscan-init.lo libnutscan_la-scan_usb.lo \
libnutscan_la-scan_snmp.lo libnutscan_la-scan_xml_http.lo \
libnutscan_la-scan_avahi.lo libnutscan_la-scan_eaton_serial.lo \
libnutscan_la-nutscan-serial.lo \
../../drivers/libnutscan_la-serial.lo \
../../drivers/libnutscan_la-bcmxcp_ser.lo \
../../common/libnutscan_la-common.lo
libnutscan_la_OBJECTS = $(am_libnutscan_la_OBJECTS)
libnutscan_la-nutscan-serial.lo
am__objects_1 = libnutscan_la-serial.lo libnutscan_la-bcmxcp_ser.lo
nodist_libnutscan_la_OBJECTS = $(am__objects_1)
libnutscan_la_OBJECTS = $(am_libnutscan_la_OBJECTS) \
$(nodist_libnutscan_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
@ -176,10 +201,9 @@ libnutscan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libnutscan_la_CFLAGS) \
$(CFLAGS) $(libnutscan_la_LDFLAGS) $(LDFLAGS) -o $@
@WITH_LIBLTDL_TRUE@am_libnutscan_la_rpath = -rpath $(libdir)
PROGRAMS = $(bin_PROGRAMS)
am_nut_scanner_OBJECTS = nut_scanner-nut-scanner.$(OBJEXT)
nut_scanner_OBJECTS = $(am_nut_scanner_OBJECTS)
nut_scanner_DEPENDENCIES = libnutscan.la ../../common/libcommon.la
nut_scanner_DEPENDENCIES = libnutscan.la
nut_scanner_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(nut_scanner_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
@ -197,7 +221,22 @@ am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo \
./$(DEPDIR)/libnutscan_la-nutscan-device.Plo \
./$(DEPDIR)/libnutscan_la-nutscan-display.Plo \
./$(DEPDIR)/libnutscan_la-nutscan-init.Plo \
./$(DEPDIR)/libnutscan_la-nutscan-ip.Plo \
./$(DEPDIR)/libnutscan_la-nutscan-serial.Plo \
./$(DEPDIR)/libnutscan_la-scan_avahi.Plo \
./$(DEPDIR)/libnutscan_la-scan_eaton_serial.Plo \
./$(DEPDIR)/libnutscan_la-scan_ipmi.Plo \
./$(DEPDIR)/libnutscan_la-scan_nut.Plo \
./$(DEPDIR)/libnutscan_la-scan_snmp.Plo \
./$(DEPDIR)/libnutscan_la-scan_usb.Plo \
./$(DEPDIR)/libnutscan_la-scan_xml_http.Plo \
./$(DEPDIR)/libnutscan_la-serial.Plo \
./$(DEPDIR)/nut_scanner-nut-scanner.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -217,7 +256,8 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libnutscan_la_SOURCES) $(nut_scanner_SOURCES)
SOURCES = $(libnutscan_la_SOURCES) $(nodist_libnutscan_la_SOURCES) \
$(nut_scanner_SOURCES)
DIST_SOURCES = $(libnutscan_la_SOURCES) $(nut_scanner_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
@ -227,7 +267,7 @@ am__can_run_installinfo = \
am__dist_noinst_HEADERS_DIST = nutscan-usb.h nutscan-snmp.h nut-scan.h \
nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
am__include_HEADERS_DIST = nut-scan.h nutscan-device.h nutscan-ip.h \
nutscan-init.h
nutscan-init.h nutscan-serial.h
HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
@ -248,6 +288,7 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
A2X = @A2X@
ACLOCAL = @ACLOCAL@
@ -256,6 +297,7 @@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ASCIIDOC = @ASCIIDOC@
ASPELL = @ASPELL@
AUGPARSE = @AUGPARSE@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@ -266,6 +308,7 @@ CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CONFPATH = @CONFPATH@
CPP = @CPP@
CPPCHECK = @CPPCHECK@
CPPFLAGS = @CPPFLAGS@
CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@
CPPUNIT_LIBS = @CPPUNIT_LIBS@
@ -279,6 +322,7 @@ DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOC_BUILD_LIST = @DOC_BUILD_LIST@
DOC_CHECK_LIST = @DOC_CHECK_LIST@
DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@
DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@
DRIVER_MAN_LIST = @DRIVER_MAN_LIST@
@ -291,6 +335,7 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GDLIB_CONFIG = @GDLIB_CONFIG@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@ -308,6 +353,8 @@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@
LIBIPMI_LIBS = @LIBIPMI_LIBS@
LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@
LIBLTDL_LIBS = @LIBLTDL_LIBS@
LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@
LIBMODBUS_LIBS = @LIBMODBUS_LIBS@
LIBNEON_CFLAGS = @LIBNEON_CFLAGS@
LIBNEON_LIBS = @LIBNEON_LIBS@
LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@
@ -318,21 +365,29 @@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@
LIBS = @LIBS@
LIBSSL_CFLAGS = @LIBSSL_CFLAGS@
LIBSSL_LIBS = @LIBSSL_LIBS@
LIBSSL_REQUIRES = @LIBSSL_REQUIRES@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIBUSB_CFLAGS = @LIBUSB_CFLAGS@
LIBUSB_CONFIG = @LIBUSB_CONFIG@
LIBUSB_LIBS = @LIBUSB_LIBS@
LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LIPO = @LIPO@
LN_S = @LN_S@
LN_S_R = @LN_S_R@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NETLIBS = @NETLIBS@
NET_SNMP_CONFIG = @NET_SNMP_CONFIG@
NM = @NM@
NMEDIT = @NMEDIT@
NUT_DATADIR = @NUT_DATADIR@
NUT_LIBEXECDIR = @NUT_LIBEXECDIR@
NUT_NETVERSION = @NUT_NETVERSION@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
@ -352,6 +407,9 @@ PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PORT = @PORT@
PYTHON = @PYTHON@
PYTHON2 = @PYTHON2@
PYTHON3 = @PYTHON3@
RANLIB = @RANLIB@
RUN_AS_GROUP = @RUN_AS_GROUP@
RUN_AS_USER = @RUN_AS_USER@
@ -365,6 +423,7 @@ STATEPATH = @STATEPATH@
STRIP = @STRIP@
SUN_LIBUSB = @SUN_LIBUSB@
TREE_VERSION = @TREE_VERSION@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
XMLLINT = @XMLLINT@
@ -382,6 +441,7 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
auglensdir = @auglensdir@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@ -395,6 +455,9 @@ datarootdir = @datarootdir@
devddir = @devddir@
docdir = @docdir@
driverexecdir = @driverexecdir@
dummy_PKG_CONFIG = @dummy_PKG_CONFIG@
dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@
dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
@ -420,12 +483,14 @@ pkgconfigdir = @pkgconfigdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
systemdsystemshutdowndir = @systemdsystemshutdowndir@
systemdshutdowndir = @systemdshutdowndir@
systemdsystemunitdir = @systemdsystemunitdir@
systemdtmpfilesdir = @systemdtmpfilesdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
@ -435,28 +500,63 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
udevdir = @udevdir@
BUILT_SOURCES = nutscan-usb.h nutscan-snmp.h
# Generally, list headers and/or sources which are re-generated
# for nut-scanner in the parent dir
NUT_SCANNER_DEPS_H = nutscan-usb.h nutscan-snmp.h
NUT_SCANNER_DEPS_C =
# General set of nut-scanner dependencies generated in the parent dir
NUT_SCANNER_DEPS = $(NUT_SCANNER_DEPS_H) $(NUT_SCANNER_DEPS_C)
BUILT_SOURCES = $(NUT_SCANNER_DEPS) $(LINKED_SOURCE_FILES)
CLEANFILES = $(BUILT_SOURCES) $(LINKED_SOURCE_FILES) *-spellchecked
# Separate the .deps of other dirs from this one
# NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver
# of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS
LINKED_SOURCE_FILES = serial.c bcmxcp_ser.c
@WITH_LIBLTDL_TRUE@lib_LTLIBRARIES = libnutscan.la
libnutscan_la_SOURCES = scan_nut.c scan_ipmi.c \
nutscan-device.c nutscan-ip.c nutscan-display.c \
nutscan-init.c scan_usb.c scan_snmp.c scan_xml_http.c \
scan_avahi.c scan_eaton_serial.c nutscan-serial.c \
../../drivers/serial.c \
../../drivers/bcmxcp_ser.c \
../../common/common.c
nutscan-init.c scan_usb.c scan_snmp.c scan_xml_http.c \
scan_avahi.c scan_eaton_serial.c nutscan-serial.c
libnutscan_la_LIBADD = $(NETLIBS) $(LIBLTDL_LIBS) $(am__append_2)
libnutscan_la_LDFLAGS = $(SERLIBS) -version-info 1:0:0
nodist_libnutscan_la_SOURCES = $(LINKED_SOURCE_FILES)
libnutscan_la_LIBADD = $(NETLIBS) $(am__append_1) \
$(top_builddir)/common/libcommonclient.la $(am__append_3)
#
# Below we set API versions of public libraries
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# Note that changes here may have to be reflected in packaging (the shared
# object .so names would differ)
#
# libnutscan version information
# libnutscan exported symbols regex
# WARNING: Since the library includes parts of libcommon (as much as needed
# e.g. for logging or string manipulations), we export a few symbols from
# those too. This may cause issues for (third-party) code development that
# would use both libnutscan and libcommon or similar libs. Here we did have
# a problem with nut-scanner using two copies of common.c and conflicting
# 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 = $(SERLIBS) -version-info 2:0:0 \
-export-symbols-regex \
'^(nutscan_|nut_debug_level|s_upsdebugx|max_threads|curr_threads)'
libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include \
$(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers $(am__append_1) \
$(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_6) $(am__append_7)
$(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers $(am__append_2) \
$(am__append_4) $(am__append_5) $(am__append_6) \
$(am__append_7) $(am__append_8)
nut_scanner_SOURCES = nut-scanner.c
nut_scanner_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include
nut_scanner_LDADD = libnutscan.la ../../common/libcommon.la
dist_noinst_HEADERS = nutscan-usb.h nutscan-snmp.h $(am__append_8)
@WITH_DEV_TRUE@include_HEADERS = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h
CLEANFILES = nutscan-usb.h nutscan-snmp.h
nut_scanner_LDADD = libnutscan.la
# C is not a header, but there is no dist_noinst_SOURCES
dist_noinst_HEADERS = $(NUT_SCANNER_DEPS_H) $(NUT_SCANNER_DEPS_C) \
$(am__append_9)
@WITH_DEV_TRUE@include_HEADERS = nut-scan.h nutscan-device.h nutscan-ip.h nutscan-init.h nutscan-serial.h
MAINTAINERCLEANFILES = Makefile.in .dirstamp
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
@ -474,14 +574,13 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/nut-scanner/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu tools/nut-scanner/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
@ -492,63 +591,6 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
../../drivers/$(am__dirstamp):
@$(MKDIR_P) ../../drivers
@: > ../../drivers/$(am__dirstamp)
../../drivers/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) ../../drivers/$(DEPDIR)
@: > ../../drivers/$(DEPDIR)/$(am__dirstamp)
../../drivers/libnutscan_la-serial.lo: ../../drivers/$(am__dirstamp) \
../../drivers/$(DEPDIR)/$(am__dirstamp)
../../drivers/libnutscan_la-bcmxcp_ser.lo: \
../../drivers/$(am__dirstamp) \
../../drivers/$(DEPDIR)/$(am__dirstamp)
../../common/$(am__dirstamp):
@$(MKDIR_P) ../../common
@: > ../../common/$(am__dirstamp)
../../common/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) ../../common/$(DEPDIR)
@: > ../../common/$(DEPDIR)/$(am__dirstamp)
../../common/libnutscan_la-common.lo: ../../common/$(am__dirstamp) \
../../common/$(DEPDIR)/$(am__dirstamp)
libnutscan.la: $(libnutscan_la_OBJECTS) $(libnutscan_la_DEPENDENCIES) $(EXTRA_libnutscan_la_DEPENDENCIES)
$(AM_V_CCLD)$(libnutscan_la_LINK) $(am_libnutscan_la_rpath) $(libnutscan_la_OBJECTS) $(libnutscan_la_LIBADD) $(LIBS)
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
@ -599,36 +641,75 @@ clean-binPROGRAMS:
echo " rm -f" $$list; \
rm -f $$list
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libnutscan.la: $(libnutscan_la_OBJECTS) $(libnutscan_la_DEPENDENCIES) $(EXTRA_libnutscan_la_DEPENDENCIES)
$(AM_V_CCLD)$(libnutscan_la_LINK) $(am_libnutscan_la_rpath) $(libnutscan_la_OBJECTS) $(libnutscan_la_LIBADD) $(LIBS)
nut-scanner$(EXEEXT): $(nut_scanner_OBJECTS) $(nut_scanner_DEPENDENCIES) $(EXTRA_nut_scanner_DEPENDENCIES)
@rm -f nut-scanner$(EXEEXT)
$(AM_V_CCLD)$(nut_scanner_LINK) $(nut_scanner_OBJECTS) $(nut_scanner_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f ../../common/*.$(OBJEXT)
-rm -f ../../common/*.lo
-rm -f ../../drivers/*.$(OBJEXT)
-rm -f ../../drivers/*.lo
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@../../common/$(DEPDIR)/libnutscan_la-common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@../../drivers/$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@../../drivers/$(DEPDIR)/libnutscan_la-serial.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-device.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-display.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-init.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-ip.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-serial.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_avahi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_eaton_serial.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_ipmi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_nut.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_snmp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_usb.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_xml_http.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut_scanner-nut-scanner.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-device.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-display.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-init.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-ip.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-nutscan-serial.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_avahi.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_eaton_serial.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_ipmi.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_nut.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_snmp.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_usb.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-scan_xml_http.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutscan_la-serial.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut_scanner-nut-scanner.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@ -738,26 +819,19 @@ libnutscan_la-nutscan-serial.lo: nutscan-serial.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o libnutscan_la-nutscan-serial.lo `test -f 'nutscan-serial.c' || echo '$(srcdir)/'`nutscan-serial.c
../../drivers/libnutscan_la-serial.lo: ../../drivers/serial.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -MT ../../drivers/libnutscan_la-serial.lo -MD -MP -MF ../../drivers/$(DEPDIR)/libnutscan_la-serial.Tpo -c -o ../../drivers/libnutscan_la-serial.lo `test -f '../../drivers/serial.c' || echo '$(srcdir)/'`../../drivers/serial.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../drivers/$(DEPDIR)/libnutscan_la-serial.Tpo ../../drivers/$(DEPDIR)/libnutscan_la-serial.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../drivers/serial.c' object='../../drivers/libnutscan_la-serial.lo' libtool=yes @AMDEPBACKSLASH@
libnutscan_la-serial.lo: serial.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -MT libnutscan_la-serial.lo -MD -MP -MF $(DEPDIR)/libnutscan_la-serial.Tpo -c -o libnutscan_la-serial.lo `test -f 'serial.c' || echo '$(srcdir)/'`serial.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutscan_la-serial.Tpo $(DEPDIR)/libnutscan_la-serial.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial.c' object='libnutscan_la-serial.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o ../../drivers/libnutscan_la-serial.lo `test -f '../../drivers/serial.c' || echo '$(srcdir)/'`../../drivers/serial.c
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o libnutscan_la-serial.lo `test -f 'serial.c' || echo '$(srcdir)/'`serial.c
../../drivers/libnutscan_la-bcmxcp_ser.lo: ../../drivers/bcmxcp_ser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -MT ../../drivers/libnutscan_la-bcmxcp_ser.lo -MD -MP -MF ../../drivers/$(DEPDIR)/libnutscan_la-bcmxcp_ser.Tpo -c -o ../../drivers/libnutscan_la-bcmxcp_ser.lo `test -f '../../drivers/bcmxcp_ser.c' || echo '$(srcdir)/'`../../drivers/bcmxcp_ser.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../drivers/$(DEPDIR)/libnutscan_la-bcmxcp_ser.Tpo ../../drivers/$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../drivers/bcmxcp_ser.c' object='../../drivers/libnutscan_la-bcmxcp_ser.lo' libtool=yes @AMDEPBACKSLASH@
libnutscan_la-bcmxcp_ser.lo: bcmxcp_ser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -MT libnutscan_la-bcmxcp_ser.lo -MD -MP -MF $(DEPDIR)/libnutscan_la-bcmxcp_ser.Tpo -c -o libnutscan_la-bcmxcp_ser.lo `test -f 'bcmxcp_ser.c' || echo '$(srcdir)/'`bcmxcp_ser.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutscan_la-bcmxcp_ser.Tpo $(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bcmxcp_ser.c' object='libnutscan_la-bcmxcp_ser.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o ../../drivers/libnutscan_la-bcmxcp_ser.lo `test -f '../../drivers/bcmxcp_ser.c' || echo '$(srcdir)/'`../../drivers/bcmxcp_ser.c
../../common/libnutscan_la-common.lo: ../../common/common.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -MT ../../common/libnutscan_la-common.lo -MD -MP -MF ../../common/$(DEPDIR)/libnutscan_la-common.Tpo -c -o ../../common/libnutscan_la-common.lo `test -f '../../common/common.c' || echo '$(srcdir)/'`../../common/common.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../common/$(DEPDIR)/libnutscan_la-common.Tpo ../../common/$(DEPDIR)/libnutscan_la-common.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../common/common.c' object='../../common/libnutscan_la-common.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o ../../common/libnutscan_la-common.lo `test -f '../../common/common.c' || echo '$(srcdir)/'`../../common/common.c
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutscan_la_CFLAGS) $(CFLAGS) -c -o libnutscan_la-bcmxcp_ser.lo `test -f 'bcmxcp_ser.c' || echo '$(srcdir)/'`bcmxcp_ser.c
nut_scanner-nut-scanner.o: nut-scanner.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nut_scanner_CFLAGS) $(CFLAGS) -MT nut_scanner-nut-scanner.o -MD -MP -MF $(DEPDIR)/nut_scanner-nut-scanner.Tpo -c -o nut_scanner-nut-scanner.o `test -f 'nut-scanner.c' || echo '$(srcdir)/'`nut-scanner.c
@ -778,8 +852,6 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
-rm -rf ../../common/.libs ../../common/_libs
-rm -rf ../../drivers/.libs ../../drivers/_libs
install-includeHEADERS: $(include_HEADERS)
@$(NORMAL_INSTALL)
@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
@ -854,7 +926,10 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
@ -887,16 +962,17 @@ distdir: $(DISTFILES)
check-am: all-am
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
install-binPROGRAMS: install-libLTLIBRARIES
installdirs:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"; do \
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: install-exec-am
install-exec: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-exec-am
install-data: install-data-am
uninstall: uninstall-am
@ -922,22 +998,33 @@ clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-rm -f ../../common/$(DEPDIR)/$(am__dirstamp)
-rm -f ../../common/$(am__dirstamp)
-rm -f ../../drivers/$(DEPDIR)/$(am__dirstamp)
-rm -f ../../drivers/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
clean-libtool mostlyclean-am
distclean: distclean-am
-rm -rf ../../common/$(DEPDIR) ../../drivers/$(DEPDIR) ./$(DEPDIR)
-rm -f ./$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-device.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-display.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-init.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-ip.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-serial.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_avahi.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_eaton_serial.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_ipmi.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_nut.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_snmp.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_usb.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_xml_http.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-serial.Plo
-rm -f ./$(DEPDIR)/nut_scanner-nut-scanner.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@ -983,7 +1070,21 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ../../common/$(DEPDIR) ../../drivers/$(DEPDIR) ./$(DEPDIR)
-rm -f ./$(DEPDIR)/libnutscan_la-bcmxcp_ser.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-device.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-display.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-init.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-ip.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-nutscan-serial.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_avahi.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_eaton_serial.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_ipmi.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_nut.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_snmp.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_usb.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-scan_xml_http.Plo
-rm -f ./$(DEPDIR)/libnutscan_la-serial.Plo
-rm -f ./$(DEPDIR)/nut_scanner-nut-scanner.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@ -1003,9 +1104,9 @@ ps-am:
uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
uninstall-libLTLIBRARIES
.MAKE: all check install install-am install-strip
.MAKE: all check install install-am install-exec install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
clean-libtool cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-libtool \
@ -1022,9 +1123,37 @@ uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
uninstall-includeHEADERS uninstall-libLTLIBRARIES
.PRECIOUS: Makefile
nutscan-usb.h nutscan-snmp.h:
cd ..; $(MAKE) $(AM_MAKEFLAGS) nut-scanner-deps
# Make sure we have the freshest files (no-op if built earlier and then
# no driver sources and other dependencies were edited by a developer)
$(NUT_SCANNER_DEPS): dummy
@cd .. && $(MAKE) $(AM_MAKEFLAGS) nut-scanner-deps
# Make sure out-of-dir dependencies exist (especially when dev-building parts):
$(top_builddir)/common/libcommon.la: dummy
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
# do not hard depend on '../include/nut_version.h', since it blocks
# 'dist', and is only required for actual build, in which case
# BUILT_SOURCES (in ../include) will ensure nut_version.h will
# be built before anything else
nut-scanner.c: $(top_builddir)/include/nut_version.h
serial.c: $(top_srcdir)/drivers/serial.c
test -s "$@" || ln -s -f "$(top_srcdir)/drivers/serial.c" "$@"
bcmxcp_ser.c: $(top_srcdir)/drivers/bcmxcp_ser.c
test -s "$@" || ln -s -f "$(top_srcdir)/drivers/bcmxcp_ser.c" "$@"
$(top_builddir)/include/nut_version.h:
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
dummy:
# NOTE: Do not clean ".deps" in SUBDIRS of the main project,
# the root Makefile.am takes care of that!
#clean-local:
# rm -rf $(builddir)/.deps
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.

View file

@ -38,6 +38,8 @@ iteration function to display results:
nutscan_options_t * opt;
nutscan_device_t *device;
nutscan-init();
if ((device = nutscan_scan_usb()) == NULL) {
printf("No device found\n");
exit(EXIT_FAILURE);

View file

@ -2,6 +2,8 @@
* Copyright (C)
* 2011 - EATON
* 2012 - Arnaud Quette <arnaud.quette@free.fr>
* 2016 - EATON - IP addressed XML scan
* 2016-2021 - EATON - Various threads-related improvements
*
* 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
@ -22,19 +24,47 @@
\brief general header for nut-scanner
\author Frederic Bohe <fredericbohe@eaton.com>
\author Arnaud Quette <arnaud.quette@free.fr>
\author Michal Vyskocil <MichalVyskocil@eaton.com>
\author Jim Klimov <EvgenyKlimov@eaton.com>
*/
#ifndef NUT_SCAN_H
#define NUT_SCAN_H
#include "config.h"
#include <sys/types.h>
#include "nut_stdint.h"
#include <nutscan-init.h>
#include <nutscan-device.h>
#include <nutscan-ip.h>
#include <timehead.h>
#ifdef WITH_IPMI
#include <freeipmi/freeipmi.h>
#endif
#ifdef HAVE_PTHREAD
# include <pthread.h>
# ifdef HAVE_SEMAPHORE
# include <semaphore.h>
# endif
# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE)
extern size_t max_threads, curr_threads, max_threads_netxml, max_threads_oldnut, max_threads_netsnmp;
# endif
# ifdef HAVE_PTHREAD_TRYJOIN
extern pthread_mutex_t threadcount_mutex;
# endif
typedef struct nutscan_thread {
pthread_t thread;
int active; /* true if the thread was created, false if joined (to not join twice) */
} nutscan_thread_t;
#endif /* HAVE_PTHREAD */
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
@ -83,21 +113,39 @@ typedef struct nutscan_ipmi {
#define IPMI_1_5 1
#define IPMI_2_0 0
/* XML HTTP structure */
typedef struct nutscan_xml {
uint16_t port_http; /* Port for xml http (tcp) */
uint16_t port_udp; /* Port for xml udp */
useconds_t usec_timeout; /* Wait this long for a response */
char *peername; /* Hostname or NULL for broadcast mode */
} nutscan_xml_t;
/* Scanning */
nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip, long usec_timeout, nutscan_snmp_t * sec);
nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip, useconds_t usec_timeout, nutscan_snmp_t * sec);
nutscan_device_t * nutscan_scan_usb();
nutscan_device_t * nutscan_scan_usb(void);
nutscan_device_t * nutscan_scan_xml_http(long usec_timeout);
/* If "ip" == NULL, do a broadcast scan */
/* If sec->usec_timeout <= 0 then the common usec_timeout arg overrides it */
nutscan_device_t * nutscan_scan_xml_http_range(const char *start_ip, const char *end_ip, useconds_t usec_timeout, nutscan_xml_t * sec);
nutscan_device_t * nutscan_scan_nut(const char * startIP, const char * stopIP, const char * port, long usec_timeout);
nutscan_device_t * nutscan_scan_nut(const char * startIP, const char * stopIP, const char * port, useconds_t usec_timeout);
nutscan_device_t * nutscan_scan_avahi(long usec_timeout);
nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout);
nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec);
nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec);
nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list);
#ifdef HAVE_PTHREAD
# ifdef HAVE_SEMAPHORE
/* Expose shared libnutscanner semaphore for overall thread count
* limited across different scanning methods (protocols/media): */
sem_t * nutscan_semaphore(void);
# endif
#endif
/* Display functions */
void nutscan_display_ups_conf(nutscan_device_t * device);
void nutscan_display_parsable(nutscan_device_t * device);

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@
\brief manipulation of a container describing a NUT device
\author Frederic Bohe <fredericbohe@eaton.com>
*/
#include "config.h" /* must be the first header */
#include "nutscan-device.h"
#include <stdlib.h>
@ -34,18 +35,18 @@ const char * nutscan_device_type_strings[TYPE_END - 1] = {
"IPMI",
"Avahi",
"serial",
};
};
nutscan_device_t * nutscan_new_device()
{
nutscan_device_t * device;
device = malloc(sizeof(nutscan_device_t));
if( device==NULL) {
if (device == NULL) {
return NULL;
}
memset(device,0,sizeof(nutscan_device_t));
memset(device, 0, sizeof(nutscan_device_t));
return device;
}
@ -54,13 +55,13 @@ static void deep_free_device(nutscan_device_t * device)
{
nutscan_options_t * current;
if(device==NULL) {
if (device == NULL) {
return;
}
if(device->driver) {
if (device->driver) {
free(device->driver);
}
if(device->port) {
if (device->port) {
free(device->port);
}
@ -68,21 +69,21 @@ static void deep_free_device(nutscan_device_t * device)
current = device->opt;
device->opt = current->next;
if(current->option != NULL) {
if (current->option != NULL) {
free(current->option);
}
if(current->value != NULL) {
if (current->value != NULL) {
free(current->value);
}
free(current);
};
}
if(device->prev) {
if (device->prev) {
device->prev->next = device->next;
}
if(device->next) {
if (device->next) {
device->next->prev = device->prev;
}
@ -91,13 +92,13 @@ static void deep_free_device(nutscan_device_t * device)
void nutscan_free_device(nutscan_device_t * device)
{
if(device==NULL) {
if (device == NULL) {
return;
}
while(device->prev != NULL) {
while (device->prev != NULL) {
deep_free_device(device->prev);
}
while(device->next != NULL) {
while (device->next != NULL) {
deep_free_device(device->next);
}
@ -116,19 +117,19 @@ void nutscan_add_option_to_device(nutscan_device_t * device, char * option, char
*opt = (nutscan_options_t *)malloc(sizeof(nutscan_options_t));
// TBD: A gracefull way to propagate memory failure would be nice
/* TBD: A gracefull way to propagate memory failure would be nice */
assert(NULL != *opt);
memset(*opt, 0, sizeof(nutscan_options_t));
if( option != NULL ) {
if (option != NULL) {
(*opt)->option = strdup(option);
}
else {
(*opt)->option = NULL;
}
if( value != NULL ) {
if (value != NULL) {
(*opt)->value = strdup(value);
}
else {
@ -138,41 +139,40 @@ void nutscan_add_option_to_device(nutscan_device_t * device, char * option, char
nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutscan_device_t * second)
{
nutscan_device_t * dev1=NULL;
nutscan_device_t * dev2=NULL;
nutscan_device_t * dev1 = NULL;
nutscan_device_t * dev2 = NULL;
/* Get end of first device */
if( first != NULL) {
if (first != NULL) {
dev1 = first;
while(dev1->next != NULL) {
while (dev1->next != NULL) {
dev1 = dev1->next;
}
}
else {
if( second == NULL ) {
if (second == NULL) {
return NULL;
}
/* return end of second */
dev2 = second;
while(dev2->next != NULL) {
while (dev2->next != NULL) {
dev2 = dev2->next;
}
return dev2;
}
/* Get start of second */
if( second != NULL ) {
if (second != NULL) {
dev2 = second;
while(dev2->prev != NULL) {
while (dev2->prev != NULL) {
dev2 = dev2->prev;
}
}
else {
/* return end of first */
dev1 = first;
while(dev1->next != NULL) {
while (dev1->next != NULL) {
dev1 = dev1->next;
}
return dev1;
}
@ -182,8 +182,8 @@ nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutsca
dev2->prev = dev1;
/* return end of both */
while(dev2->next != NULL) {
dev2 = dev2->next;
while (dev2->next != NULL) {
dev2 = dev2->next;
}
return dev2;

View file

@ -41,7 +41,7 @@ extern "C" {
(assert(0 < (type) && (type) < TYPE_END), nutscan_device_type_strings[type - 1])
typedef enum nutscan_device_type {
TYPE_NONE=0,
TYPE_NONE = 0,
TYPE_USB,
TYPE_SNMP,
TYPE_XML,
@ -70,9 +70,9 @@ typedef struct nutscan_device {
struct nutscan_device * next;
} nutscan_device_t;
nutscan_device_t * nutscan_new_device();
nutscan_device_t * nutscan_new_device(void);
void nutscan_free_device(nutscan_device_t * device);
void nutscan_add_option_to_device(nutscan_device_t * device,char * option, char * value);
void nutscan_add_option_to_device(nutscan_device_t * device, char * option, char * value);
nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutscan_device_t * second);
/**

View file

@ -24,16 +24,18 @@
#include "common.h"
#include <stdio.h>
#include "nutscan-device.h"
#include "nut-scan.h"
char * nutscan_device_type_string[TYPE_END]= {
"NONE",
"USB",
"SNMP",
"XML",
"NUT",
"IPMI",
"AVAHI",
"EATON_SERIAL" };
static char * nutscan_device_type_string[TYPE_END] = {
"NONE",
"USB",
"SNMP",
"XML",
"NUT",
"IPMI",
"AVAHI",
"EATON_SERIAL"
};
void nutscan_display_ups_conf(nutscan_device_t * device)
{
@ -41,16 +43,16 @@ void nutscan_display_ups_conf(nutscan_device_t * device)
nutscan_options_t * opt;
static int nutdev_num = 1;
if(device==NULL) {
if (device == NULL) {
return;
}
/* Find start of the list */
while(current_dev->prev != NULL) {
while (current_dev->prev != NULL) {
current_dev = current_dev->prev;
}
/* Display each devices */
/* Display each device */
do {
printf("[nutdev%i]\n\tdriver = \"%s\"\n\tport = \"%s\"\n",
nutdev_num, current_dev->driver,
@ -59,9 +61,9 @@ void nutscan_display_ups_conf(nutscan_device_t * device)
opt = current_dev->opt;
while (NULL != opt) {
if( opt->option != NULL ) {
printf("\t%s",opt->option);
if( opt->value != NULL ) {
if (opt->option != NULL) {
printf("\t%s", opt->option);
if (opt->value != NULL) {
printf(" = \"%s\"", opt->value);
}
printf("\n");
@ -73,7 +75,7 @@ void nutscan_display_ups_conf(nutscan_device_t * device)
current_dev = current_dev->next;
}
while( current_dev != NULL );
while (current_dev != NULL);
}
void nutscan_display_parsable(nutscan_device_t * device)
@ -81,17 +83,18 @@ void nutscan_display_parsable(nutscan_device_t * device)
nutscan_device_t * current_dev = device;
nutscan_options_t * opt;
if(device==NULL) {
if (device == NULL) {
return;
}
/* Find start of the list */
while(current_dev->prev != NULL) {
while (current_dev->prev != NULL) {
current_dev = current_dev->prev;
}
/* Display each devices */
/* Display each device */
do {
/* Do not separate by whitespace, in case someone already parses this */
printf("%s:driver=\"%s\",port=\"%s\"",
nutscan_device_type_string[current_dev->type],
current_dev->driver,
@ -100,9 +103,10 @@ void nutscan_display_parsable(nutscan_device_t * device)
opt = current_dev->opt;
while (NULL != opt) {
if( opt->option != NULL ) {
printf(",%s",opt->option);
if( opt->value != NULL ) {
if (opt->option != NULL) {
/* Do not separate by whitespace, in case someone already parses this */
printf(",%s", opt->option);
if (opt->value != NULL) {
printf("=\"%s\"", opt->value);
}
}
@ -113,6 +117,5 @@ void nutscan_display_parsable(nutscan_device_t * device)
current_dev = current_dev->next;
}
while( current_dev != NULL );
while (current_dev != NULL);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 - EATON
* Copyright (C) 2011-2021 - EATON
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,14 +19,16 @@
/*! \file nutscan-init.c
\brief init functions for nut scanner library
\author Frederic Bohe <fredericbohe@eaton.com>
\author Arnaud Quette <ArnaudQuette@Eaton.com>
*/
#include "common.h"
#include "nutscan-init.h"
#include <ltdl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include "nut-scan.h"
int nutscan_avail_avahi = 0;
int nutscan_avail_ipmi = 0;
@ -42,85 +44,176 @@ int nutscan_load_avahi_library(const char *libname_path);
int nutscan_load_ipmi_library(const char *libname_path);
int nutscan_load_upsclient_library(const char *libname_path);
/* FIXME: would be good to get more from /etc/ld.so.conf[.d] */
char * search_paths[] = {
LIBDIR,
"/usr/lib64",
"/lib64",
"/usr/lib",
"/lib",
"/usr/local/lib",
NULL
};
#ifdef HAVE_PTHREAD
# ifdef HAVE_SEMAPHORE
/* Shared by library consumers, exposed by nutscan_semaphore() below */
static sem_t semaphore;
const char * get_libname(const char* base_libname)
sem_t * nutscan_semaphore(void)
{
DIR *dp;
struct dirent *dirp;
int index = 0;
char *libname_path = NULL;
char current_test_path[LARGEBUF];
for(index = 0 ; (search_paths[index] != NULL) && (libname_path == NULL) ; index++)
{
memset(current_test_path, 0, LARGEBUF);
if ((dp = opendir(search_paths[index])) == NULL)
continue;
while ((dirp = readdir(dp)) != NULL)
{
if(!strncmp(dirp->d_name, base_libname, strlen(base_libname))) {
snprintf(current_test_path, LARGEBUF, "%s/%s", search_paths[index], dirp->d_name);
libname_path = realpath(current_test_path, NULL);
if (libname_path != NULL)
break;
}
}
closedir(dp);
}
/* fprintf(stderr,"Looking for lib %s, found %s\n", base_libname, (libname_path!=NULL)?libname_path:"NULL");*/
return libname_path;
return &semaphore;
}
# endif /* HAVE_SEMAPHORE */
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_t threadcount_mutex;
# endif
# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE)
/* We have 3 networked scan types: nut, snmp, xml,
* and users typically give their /24 subnet as "-m" arg.
* With some systems having a 1024 default (u)limit to
* file descriptors, this should fit if those are involved.
* On some systems tested, a large amount of not-joined
* pthreads did cause various crashes; also RAM is limited.
* Note that each scan may be time consuming to query an
* IP address and wait for (no) reply, so while these threads
* are usually not resource-intensive (nor computationally),
* they spend much wallclock time each so parallelism helps.
*/
size_t max_threads = DEFAULT_THREAD;
size_t curr_threads = 0;
size_t max_threads_netxml = 1021; /* experimental finding, see PR#1158 */
size_t max_threads_oldnut = 1021;
size_t max_threads_netsnmp = 0; /* 10240; */
/* per reports in PR#1158, some versions of net-snmp could be limited
* to 1024 threads in the past; this was not found in practice.
* Still, some practical limit can be useful (configurable?)
* Here 0 means to not apply any special limit (beside max_threads).
*/
# endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE */
#endif /* HAVE_PTHREAD */
void nutscan_init(void)
{
#ifdef HAVE_PTHREAD
/* TOTHINK: Should semaphores to limit thread count
* and the more naive but portable methods be an
* if-else proposition? At least when initializing?
*/
# ifdef HAVE_SEMAPHORE
/* NOTE: This semaphore may get re-initialized in nut-scanner program
* after parsing command-line arguments. It calls nutscan_init() before
* parsing CLI, to know about available libs and to set defaults below.
*/
#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 > 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 to range acceptable for sem_init()",
__func__);
max_threads = UINT_MAX - 1;
}
sem_init(&semaphore, 0, (unsigned int)max_threads);
# endif
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_init(&threadcount_mutex, NULL);
# endif
#endif /* HAVE_PTHREAD */
char *libname = NULL;
#ifdef WITH_USB
nutscan_avail_usb = nutscan_load_usb_library(get_libname("libusb-0.1.so"));
#if WITH_LIBUSB_1_0
libname = get_libname("libusb-1.0.so");
#else
libname = get_libname("libusb-0.1.so");
if (!libname) {
/* We can also use libusb-compat from newer libusb-1.0 releases */
libname = get_libname("libusb.so");
}
#endif
if (libname) {
nutscan_avail_usb = nutscan_load_usb_library(libname);
free(libname);
}
#endif
#ifdef WITH_SNMP
nutscan_avail_snmp = nutscan_load_snmp_library(get_libname("libnetsnmp.so"));
libname = get_libname("libnetsnmp.so");
if (libname) {
nutscan_avail_snmp = nutscan_load_snmp_library(libname);
free(libname);
}
#endif
#ifdef WITH_NEON
nutscan_avail_xml_http = nutscan_load_neon_library(get_libname("libneon.so"));
libname = get_libname("libneon.so");
if (!libname) {
libname = get_libname("libneon-gnutls.so");
}
if (libname) {
nutscan_avail_xml_http = nutscan_load_neon_library(libname);
free(libname);
}
#endif
#ifdef WITH_AVAHI
nutscan_avail_avahi = nutscan_load_avahi_library(get_libname("libavahi-client.so"));
libname = get_libname("libavahi-client.so");
if (libname) {
nutscan_avail_avahi = nutscan_load_avahi_library(libname);
free(libname);
}
#endif
#ifdef WITH_FREEIPMI
nutscan_avail_ipmi = nutscan_load_ipmi_library(get_libname("libfreeipmi.so"));
libname = get_libname("libfreeipmi.so");
if (libname) {
nutscan_avail_ipmi = nutscan_load_ipmi_library(libname);
free(libname);
}
#endif
nutscan_avail_nut = nutscan_load_upsclient_library(get_libname("libupsclient.so"));
libname = get_libname("libupsclient.so");
if (libname) {
nutscan_avail_nut = nutscan_load_upsclient_library(libname);
free(libname);
}
}
void nutscan_free(void)
{
if( nutscan_avail_usb ) {
if (nutscan_avail_usb) {
lt_dlexit();
}
if( nutscan_avail_snmp ) {
if (nutscan_avail_snmp) {
lt_dlexit();
}
if( nutscan_avail_xml_http ) {
if (nutscan_avail_xml_http) {
lt_dlexit();
}
if( nutscan_avail_avahi ) {
if (nutscan_avail_avahi) {
lt_dlexit();
}
if( nutscan_avail_ipmi ) {
if (nutscan_avail_ipmi) {
lt_dlexit();
}
if( nutscan_avail_nut ) {
if (nutscan_avail_nut) {
lt_dlexit();
}
#ifdef HAVE_PTHREAD
/* TOTHINK: See comments near mutex/semaphore init code above */
# ifdef HAVE_SEMAPHORE
sem_destroy(nutscan_semaphore());
# endif
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_destroy(&threadcount_mutex);
# endif
#endif
}

View file

@ -40,6 +40,8 @@ extern int nutscan_avail_xml_http;
void nutscan_init(void);
void nutscan_free(void);
#define DEFAULT_THREAD 512
#ifdef __cplusplus
/* *INDENT-OFF* */
}

View file

@ -21,6 +21,8 @@
\author Frederic Bohe <fredericbohe@eaton.com>
*/
#include "config.h" /* must be first */
#include "nutscan-ip.h"
#include <stdio.h>
#include "common.h"
@ -32,9 +34,9 @@ static void increment_IPv6(struct in6_addr * addr)
{
int i;
for( i=15 ; i>= 0 ; i--) {
for (i = 15 ; i >= 0 ; i--) {
addr->s6_addr[i]++;
if( addr->s6_addr[i] != 0) {
if (addr->s6_addr[i] != 0) {
break;
}
}
@ -44,37 +46,39 @@ static void invert_IPv6(struct in6_addr * addr1, struct in6_addr * addr2)
{
struct in6_addr addr;
memcpy(addr.s6_addr,addr1->s6_addr,sizeof(addr.s6_addr));
memcpy(addr1->s6_addr,addr2->s6_addr,sizeof(addr.s6_addr));
memcpy(addr2->s6_addr,addr.s6_addr,sizeof(addr.s6_addr));
memcpy(addr.s6_addr, addr1->s6_addr, sizeof(addr.s6_addr));
memcpy(addr1->s6_addr, addr2->s6_addr, sizeof(addr.s6_addr));
memcpy(addr2->s6_addr, addr.s6_addr, sizeof(addr.s6_addr));
}
static int ntop( struct in_addr * ip, char * host, size_t host_size)
static int ntop(struct in_addr * ip, char * host, GETNAMEINFO_TYPE_ARG46 host_size)
{
struct sockaddr_in in;
memset(&in,0,sizeof(struct sockaddr_in));
memset(&in, 0, sizeof(struct sockaddr_in));
in.sin_addr = *ip;
in.sin_family = AF_INET;
return getnameinfo((struct sockaddr *)&in,
sizeof(struct sockaddr_in),
host,host_size,NULL,0,NI_NUMERICHOST);
return getnameinfo(
(struct sockaddr *)&in,
sizeof(struct sockaddr_in),
host, host_size, NULL, 0, NI_NUMERICHOST);
}
static int ntop6( struct in6_addr * ip, char * host, size_t host_size)
static int ntop6(struct in6_addr * ip, char * host, GETNAMEINFO_TYPE_ARG46 host_size)
{
struct sockaddr_in6 in6;
memset(&in6,0,sizeof(struct sockaddr_in6));
memcpy( &in6.sin6_addr, ip, sizeof(struct in6_addr) );
memset(&in6, 0, sizeof(struct sockaddr_in6));
memcpy(&in6.sin6_addr, ip, sizeof(struct in6_addr));
in6.sin6_family = AF_INET6;
return getnameinfo((struct sockaddr *)&in6,
sizeof(struct sockaddr_in6),
host,host_size,NULL,0,NI_NUMERICHOST);
return getnameinfo(
(struct sockaddr *)&in6,
sizeof(struct sockaddr_in6),
host, host_size, NULL, 0, NI_NUMERICHOST);
}
/* Return the first ip or NULL if error */
char * nutscan_ip_iter_init(nutscan_ip_iter_t * ip, const char * startIP, const char * stopIP)
{
int addr;
uint32_t addr; /* 32-bit IPv4 address */
int i;
struct addrinfo hints;
struct addrinfo *res;
@ -82,92 +86,127 @@ char * nutscan_ip_iter_init(nutscan_ip_iter_t * ip, const char * startIP, const
struct sockaddr_in6 * s_in6;
char host[SMALLBUF];
if( startIP == NULL ) {
if (startIP == NULL) {
return NULL;
}
if(stopIP == NULL ) {
if (stopIP == NULL) {
stopIP = startIP;
}
memset(&hints,0,sizeof(struct addrinfo));
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
ip->type = IPv4;
/* Detecting IPv4 vs IPv6 */
if(getaddrinfo(startIP,NULL,&hints,&res) != 0) {
if (getaddrinfo(startIP, NULL, &hints, &res) != 0) {
/*Try IPv6 detection */
ip->type = IPv6;
hints.ai_family = AF_INET6;
if(getaddrinfo(startIP,NULL,&hints,&res) != 0) {
fprintf(stderr,"Invalid address : %s\n",startIP);
if (getaddrinfo(startIP, NULL, &hints, &res) != 0) {
fprintf(stderr, "Invalid address : %s\n", startIP);
return NULL;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in6 = (struct sockaddr_in6 *)res->ai_addr;
memcpy(&ip->start6,&s_in6->sin6_addr,sizeof(struct in6_addr));
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
memcpy(&ip->start6, &s_in6->sin6_addr, sizeof(struct in6_addr));
freeaddrinfo(res);
}
else {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in = (struct sockaddr_in *)res->ai_addr;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
ip->start = s_in->sin_addr;
freeaddrinfo(res);
}
/* Compute stop IP */
if( ip->type == IPv4 ) {
if (ip->type == IPv4) {
hints.ai_family = AF_INET;
if(getaddrinfo(stopIP,NULL,&hints,&res) != 0) {
fprintf(stderr,"Invalid address : %s\n",stopIP);
return NULL;
}
if (getaddrinfo(stopIP, NULL, &hints, &res) != 0) {
fprintf(stderr, "Invalid address : %s\n", stopIP);
return NULL;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in = (struct sockaddr_in *)res->ai_addr;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
ip->stop = s_in->sin_addr;
freeaddrinfo(res);
}
else {
}
else {
hints.ai_family = AF_INET6;
if(getaddrinfo(stopIP,NULL,&hints,&res) != 0) {
fprintf(stderr,"Invalid address : %s\n",stopIP);
return NULL;
}
if (getaddrinfo(stopIP, NULL, &hints, &res) != 0) {
fprintf(stderr, "Invalid address : %s\n", stopIP);
return NULL;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in6 = (struct sockaddr_in6 *)res->ai_addr;
memcpy(&ip->stop6,&s_in6->sin6_addr,sizeof(struct in6_addr));
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
memcpy(&ip->stop6, &s_in6->sin6_addr, sizeof(struct in6_addr));
freeaddrinfo(res);
}
}
/* Make sure start IP is lesser than stop IP */
if( ip->type == IPv4 ) {
if( ntohl(ip->start.s_addr) > ntohl(ip->stop.s_addr) ) {
addr = ip->start.s_addr;
ip->start.s_addr = ip->stop.s_addr;
ip->stop.s_addr = addr;
}
/* Make sure start IP is lesser than stop IP */
if (ip->type == IPv4) {
if (ntohl(ip->start.s_addr) > ntohl(ip->stop.s_addr)) {
addr = ip->start.s_addr;
ip->start.s_addr = ip->stop.s_addr;
ip->stop.s_addr = addr;
}
if( ntop(&ip->start, host, sizeof(host)) != 0 ) {
if (ntop(&ip->start, host, sizeof(host)) != 0) {
return NULL;
}
return strdup(host);
}
else { /* IPv6 */
for( i=0; i<16; i++ ) {
if( ip->start6.s6_addr[i] !=ip->stop6.s6_addr[i] ) {
if(ip->start6.s6_addr[i]>ip->stop6.s6_addr[i]){
invert_IPv6(&ip->start6,&ip->stop6);
}
break;
}
}
}
else { /* IPv6 */
for (i = 0; i < 16; i++) {
if (ip->start6.s6_addr[i] !=ip->stop6.s6_addr[i]) {
if (ip->start6.s6_addr[i] > ip->stop6.s6_addr[i]) {
invert_IPv6(&ip->start6, &ip->stop6);
}
break;
}
}
if( ntop6(&ip->start6, host, sizeof(host)) != 0 ) {
if (ntop6(&ip->start6, host, sizeof(host)) != 0) {
return NULL;
}
return strdup(host);
}
}
}
@ -178,30 +217,30 @@ char * nutscan_ip_iter_inc(nutscan_ip_iter_t * ip)
{
char host[SMALLBUF];
if( ip->type == IPv4 ) {
if (ip->type == IPv4) {
/* Check if this is the last address to scan */
if(ip->start.s_addr == ip->stop.s_addr) {
if (ip->start.s_addr == ip->stop.s_addr) {
return NULL;
}
/* increment the address (need to pass address in host
byte order, then pass back in network byte order */
ip->start.s_addr = htonl((ntohl(ip->start.s_addr)+1));
ip->start.s_addr = htonl((ntohl(ip->start.s_addr) + 1));
if( ntop(&ip->start, host, sizeof(host)) != 0 ) {
if (ntop(&ip->start, host, sizeof(host)) != 0) {
return NULL;
}
return strdup(host);
}
else {
/* Check if this is the last address to scan */
if( memcmp(&ip->start6.s6_addr, &ip->stop6.s6_addr,
sizeof(ip->start6.s6_addr)) == 0 ) {
if (memcmp(&ip->start6.s6_addr, &ip->stop6.s6_addr,
sizeof(ip->start6.s6_addr)) == 0) {
return NULL;
}
increment_IPv6(&ip->start6);
if( ntop6(&ip->start6, host, sizeof(host)) != 0 ) {
if (ntop6(&ip->start6, host, sizeof(host)) != 0) {
return NULL;
}
@ -218,7 +257,7 @@ int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip)
nutscan_ip_iter_t ip;
int mask_val;
int mask_byte;
unsigned long mask_bit;
uint32_t mask_bit; /* 32-bit IPv4 address bitmask */
char host[SMALLBUF];
struct addrinfo hints;
struct addrinfo *res;
@ -229,47 +268,87 @@ int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip)
*stop_ip = NULL;
cidr_tok = strdup(cidr);
first_ip = strdup(strtok_r(cidr_tok,"/",&saveptr));
if( first_ip == NULL) {
first_ip = strdup(strtok_r(cidr_tok, "/", &saveptr));
if (first_ip == NULL) {
upsdebugx(0, "WARNING: %s failed to parse first_ip from cidr=%s",
__func__, cidr);
free(cidr_tok);
return 0;
}
mask = strtok_r(NULL,"/",&saveptr);
if( mask == NULL ) {
mask = strtok_r(NULL, "/", &saveptr);
if (mask == NULL) {
upsdebugx(0, "WARNING: %s failed to parse mask from cidr=%s (first_ip=%s)",
__func__, cidr, first_ip);
free (first_ip);
free(cidr_tok);
return 0;
}
free(cidr_tok);
upsdebugx(5, "%s: parsed cidr=%s into first_ip=%s and mask=%s",
__func__, cidr, first_ip, mask);
mask_val = atoi(mask);
upsdebugx(5, "%s: parsed mask value %d",
__func__, mask_val);
/* Detecting IPv4 vs IPv6 */
memset(&hints,0,sizeof(struct addrinfo));
/* NOTE: Sanity-wise, some larger number also makes sense
* as the maximum subnet size we would scan. But at least,
* this helps avoid scanning the whole Internet just due
* to string-parsing errors.
*/
if (mask_val < 1) {
fatalx(EXIT_FAILURE, "Bad netmask: %s", mask);
}
/* Note: this freeing invalidates "mask" and "saveptr" pointer targets */
free(cidr_tok);
/* Detecting IPv4 vs IPv6 */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
ip.type = IPv4;
/* Detecting IPv4 vs IPv6 */
if(getaddrinfo(first_ip,NULL,&hints,&res) != 0) {
if (getaddrinfo(first_ip, NULL, &hints, &res) != 0) {
/*Try IPv6 detection */
ip.type = IPv6;
hints.ai_family = AF_INET6;
int ret;
if((ret=getaddrinfo(first_ip,NULL,&hints,&res)) != 0) {
if ((ret = getaddrinfo(first_ip, NULL, &hints, &res)) != 0) {
free(first_ip);
return 0;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in6 = (struct sockaddr_in6 *)res->ai_addr;
memcpy(&ip.start6,&s_in6->sin6_addr,sizeof(struct in6_addr));
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
memcpy(&ip.start6, &s_in6->sin6_addr, sizeof(struct in6_addr));
freeaddrinfo(res);
}
else {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in = (struct sockaddr_in *)res->ai_addr;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
ip.start = s_in->sin_addr;
freeaddrinfo(res);
}
if( ip.type == IPv4 ) {
if (ip.type == IPv4) {
if( mask_val > 0 ) {
if (mask_val > 0) {
mask_val --;
mask_bit = 0x80000000;
mask_bit >>= mask_val;
@ -281,14 +360,14 @@ int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip)
ip.stop.s_addr = htonl(ntohl(ip.start.s_addr)|mask_bit);
ip.start.s_addr = htonl(ntohl(ip.start.s_addr)&(~mask_bit));
if( ntop(&ip.start, host, sizeof(host)) != 0 ) {
if (ntop(&ip.start, host, sizeof(host)) != 0) {
*start_ip = NULL;
*stop_ip = NULL;
return 0;
}
*start_ip = strdup(host);
if( ntop(&ip.stop, host, sizeof(host)) != 0 ) {
if (ntop(&ip.stop, host, sizeof(host)) != 0) {
free(*start_ip);
*start_ip = NULL;
*stop_ip = NULL;
@ -300,31 +379,40 @@ int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip)
return 1;
}
else {
if(getaddrinfo(first_ip,NULL,&hints,&res) != 0) {
if (getaddrinfo(first_ip, NULL, &hints, &res) != 0) {
return 0;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/* Note: we receive a pointer to res above, so have
* no control about alignment of its further data */
s_in6 = (struct sockaddr_in6 *)res->ai_addr;
memcpy(&ip.stop6,&s_in6->sin6_addr,sizeof(struct in6_addr));
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN)
# pragma GCC diagnostic pop
#endif
memcpy(&ip.stop6, &s_in6->sin6_addr, sizeof(struct in6_addr));
freeaddrinfo(res);
mask_byte = mask_val / 8;
if( mask_byte < 16 ) {
memset( &(ip.stop6.s6_addr[mask_byte+1]), 0xFF, 15 - mask_byte);
memset( &(ip.start6.s6_addr[mask_byte+1]), 0x00, 15 - mask_byte);
if (mask_byte < 16 && mask_byte >= 0) {
memset(&(ip.stop6.s6_addr[mask_byte + 1]), 0xFF, 15 - (uint8_t)mask_byte);
memset(&(ip.start6.s6_addr[mask_byte + 1]), 0x00, 15 - (uint8_t)mask_byte);
mask_bit = (0x100 >> mask_val%8)-1;
mask_bit = (0x100 >> mask_val%8) - 1;
ip.stop6.s6_addr[mask_byte] |= mask_bit;
ip.start6.s6_addr[mask_byte] &= (~mask_bit);
}
if( ntop6(&ip.start6, host, sizeof(host)) != 0 ) {
if (ntop6(&ip.start6, host, sizeof(host)) != 0) {
*start_ip = NULL;
*stop_ip = NULL;
return 0;
}
*start_ip = strdup(host);
if( ntop6(&ip.stop6, host, sizeof(host)) != 0 ) {
if (ntop6(&ip.stop6, host, sizeof(host)) != 0) {
free(*start_ip);
*start_ip = NULL;
*stop_ip = NULL;

View file

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2011 - EATON
*
* This program is free software; you can redistribute it and/or modify
@ -34,16 +34,16 @@ extern "C" {
#endif
enum network_type {
IPv4,
IPv6
IPv4,
IPv6
};
typedef struct nutscan_ip_iter {
enum network_type type;
struct in_addr start;
struct in_addr stop;
struct in6_addr start6;
struct in6_addr stop6;
struct in_addr start;
struct in_addr stop;
struct in6_addr start6;
struct in6_addr stop6;
} nutscan_ip_iter_t;
char * nutscan_ip_iter_init(nutscan_ip_iter_t *, const char * startIP, const char * stopIP);

View file

@ -22,11 +22,14 @@
\author Arnaud Quette <arnaud.quette@free.fr>
*/
#include "config.h" /* must be the first header */
#include "nutscan-serial.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "nut_platform.h"
#include "common.h"
#ifdef WIN32
/* Windows: all serial port names start with "COM" */
@ -44,7 +47,7 @@ typedef struct {
char auto_stop_port;
} device_portname_t;
device_portname_t device_portname[] = {
static device_portname_t device_portname[] = {
#ifdef NUT_PLATFORM_HPUX
/* the first number seems to be a card instance, the second number seems
to be a port number */
@ -70,7 +73,7 @@ device_portname_t device_portname[] = {
/* { "/dev/ttyd%i", "=" }, */
/* { "/dev/ttyf%i", "=" }, */
/* FIXME: Mac OS X has no serial port, but maybe ttyUSB? */
{ NULL, 0 }
{ NULL, 0, 0 }
};
/* Return 1 if port_name is a full path name to a serial port,
@ -87,25 +90,26 @@ static int is_serial_port_path(const char * port_name)
static char ** add_port(char ** list, char * port)
{
char ** res;
int count = 0;
size_t count = 0;
if(list == NULL) {
if (list == NULL) {
count = 0;
}
else {
while(list[count] != NULL) {
while (list[count] != NULL) {
count++;
}
}
/*+1 to get the number of port from the index nb_ports*/
/*+1 for the terminal NULL */
res = realloc(list,(count+1+1)*sizeof(char*));
if( res == NULL ) {
return NULL;
res = realloc(list, sizeof(char*) * (count + 1 + 1));
if (res == NULL) {
upsdebugx(1, "%s: Failed to realloc port list", __func__);
return list;
}
res[count] = strdup(port);
res[count+1] = NULL;
res[count + 1] = NULL;
return res;
}
@ -135,19 +139,19 @@ char ** nutscan_get_serial_ports_list(const char *ports_range)
/* we have a list:
* - single element: X (digit) or port name (COM1, /dev/ttyS0, ...)
* - range list: X-Y
* - multiple elements (coma separated): /dev/ttyS0,/dev/ttyUSB0 */
if ( (list_sep_ptr = strchr(range, '-')) != NULL ) {
tok = strtok_r(range,"-",&saveptr);
if( tok[1] != 0 ) {
fprintf(stderr,ERR_OUT_OF_BOUND);
* - multiple elements (comma separated): /dev/ttyS0,/dev/ttyUSB0 */
if ((list_sep_ptr = strchr(range, '-')) != NULL) {
tok = strtok_r(range, "-", &saveptr);
if (tok[1] != 0) {
fprintf(stderr, ERR_OUT_OF_BOUND);
free(range);
return NULL;
}
start_port = tok[0];
tok = strtok_r(NULL,"-",&saveptr);
if( tok != NULL ) {
if( tok[1] != 0 ) {
fprintf(stderr,ERR_OUT_OF_BOUND);
tok = strtok_r(NULL, "-", &saveptr);
if (tok != NULL) {
if (tok[1] != 0) {
fprintf(stderr, ERR_OUT_OF_BOUND);
free(range);
return NULL;
}
@ -157,19 +161,20 @@ char ** nutscan_get_serial_ports_list(const char *ports_range)
stop_port = start_port;
}
}
else if ( ((list_sep_ptr = strchr(ports_range, ',')) != NULL )
&& (is_serial_port_path(ports_range)) ) {
tok = strtok_r(range,",",&saveptr);
while( tok != NULL ) {
ports_list = add_port(ports_list,tok);
tok = strtok_r(NULL,",",&saveptr);
else if (((list_sep_ptr = strchr(ports_range, ',')) != NULL)
&& (is_serial_port_path(ports_range))
) {
tok = strtok_r(range, ",", &saveptr);
while (tok != NULL) {
ports_list = add_port(ports_list, tok);
tok = strtok_r(NULL, ",", &saveptr);
}
}
else {
/* we have been provided a single port name */
/* it's a full device name */
if( ports_range[1] != 0 ) {
ports_list = add_port(ports_list,range);
if (ports_range[1] != 0) {
ports_list = add_port(ports_list, range);
}
/* it's device number */
else {
@ -179,21 +184,35 @@ char ** nutscan_get_serial_ports_list(const char *ports_range)
free(range);
}
if( start_port == 0 && !flag_auto) {
if (start_port == 0 && !flag_auto) {
return ports_list;
}
for (cur_device=device_portname;cur_device->name!= NULL;cur_device++) {
if( flag_auto ) {
for (cur_device = device_portname; cur_device->name != NULL; cur_device++) {
if (flag_auto) {
start_port = cur_device->auto_start_port;
stop_port = cur_device->auto_stop_port;
}
for( current_port=start_port; current_port <= stop_port;
current_port++){
snprintf(str_tmp, sizeof(str_tmp),cur_device->name,
for (current_port = start_port; current_port <= stop_port;
current_port++) {
#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
#pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY
#pragma GCC diagnostic ignored "-Wformat-security"
#endif
/* We actually have a format string in the name,
* see the device_portname[] definition above */
snprintf(str_tmp, sizeof(str_tmp), cur_device->name,
current_port);
ports_list = add_port(ports_list,str_tmp);
#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
#pragma GCC diagnostic pop
#endif
ports_list = add_port(ports_list, str_tmp);
}
}
return ports_list;

View file

@ -1,6 +1,7 @@
/* nutscan-snmp
* Copyright (C) 2011 - Frederic Bohe <FredericBohe@Eaton.com>
* Copyright (C) 2016 - Arnaud Quette <ArnaudQuette@Eaton.com>
/* nutscan-snmp.h - fully generated during build of NUT
* Copyright (C) 2011-2019 EATON
* Authors: Frederic Bohe <FredericBohe@Eaton.com>
* Arnaud Quette <ArnaudQuette@Eaton.com>
*
* 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
@ -21,36 +22,44 @@
#define DEVSCAN_SNMP_H
typedef struct {
char * oid;
char * mib;
char * sysoid;
char * oid;
char * mib;
char * sysoid;
} snmp_device_id_t;
/* SNMP IDs device table */
static snmp_device_id_t snmp_device_table[] = {
{ "", "apc_ats", ".1.3.6.1.4.1.318.1.3.11"},
{ ".1.3.6.1.4.1.534.10.2.1.2.0", "eaton_ats", ".1.3.6.1.4.1.705.1"},
{ ".1.3.6.1.4.1.13742.1.1.12.0", "raritan", ".1.3.6.1.4.1.13742"},
{ "", "xppc", ".1.3.6.1.4.1.935"},
{ "1.3.6.1.4.1.534.1.1.2.0", "pw", ".1.3.6.1.4.1.534.1"},
{ "1.3.6.1.4.1.534.1.1.2.0", "pxgx_ups", ".1.3.6.1.4.1.534.2.12"},
{ "1.3.6.1.2.1.33.1.1.1.0", "ietf", ".1.3.6.1.2.1.33"},
{ "", "ietf", ".1.3.6.1.4.1.850.1"},
{ ".1.3.6.1.4.1.232.165.3.1.1.0", "cpqpower", ".1.3.6.1.4.1.232.165.3"},
{ ".1.3.6.1.4.1.17373.3.1.1.0", "aphel_genesisII", ".1.3.6.1.4.1.17373"},
{ ".1.3.6.1.4.1.534.6.6.6.1.1.12.0", "aphel_revelation", ".1.3.6.1.4.1.534.6.6.6"},
{ ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0", "eaton_epdu", ".1.3.6.1.4.1.534.6.6.7"},
{ ".1.3.6.1.4.1.20677.1", "pulizzi_switched1", ".1.3.6.1.4.1.20677.1"},
{ ".1.3.6.1.4.1.20677.1", "pulizzi_switched2", ".1.3.6.1.4.1.20677.2"},
{ ".1.3.6.1.4.1.3808.1.1.1.1.1.1.0", "cyberpower", ".1.3.6.1.4.1.3808"},
{ ".1.3.6.1.4.1.705.1.1.1.0", "mge", ".1.3.6.1.4.1.705.1"},
{ "", "delta_ups", ".1.3.6.1.4.1.2254.2.4"},
{ "", "huawei", ".1.3.6.1.4.1.8072.3.2.10"},
{ ".1.3.6.1.4.1.4555.1.1.1.1.1.1.0", "netvision", ".1.3.6.1.4.1.4555.1.1.1"},
{ ".1.3.6.1.4.1.318.1.1.1.1.1.1.0", "apcc", NULL},
{ ".1.3.6.1.4.1.4779.1.3.5.2.1.24.1", "baytech", NULL},
{ ".1.3.6.1.4.1.2947.1.1.2.0", "bestpower", NULL},
/* Terminating entry */
{ NULL, NULL, NULL}
{ ".1.3.6.1.4.1.318.1.1.8.1.5.0", "apc_ats", ".1.3.6.1.4.1.318.1.3.11" },
{ ".1.3.6.1.4.1.318.1.1.1.1.1.1.0", "apcc", ".1.3.6.1.4.1.318.1.1.1.1.1.1.0" },
{ ".1.3.6.1.4.1.318.1.1.4.1.4.0", "apc_pdu", ".1.3.6.1.4.1.318.1.3.4.4.1.3.6.1.4.1.318.1.3.4.5" },
{ ".1.3.6.1.4.1.318.1.1.4.1.4.0", "apc_pdu", ".1.3.6.1.4.1.318.1.3.4.5" },
{ ".1.3.6.1.4.1.318.1.1.4.1.4.0", "apc_pdu", ".1.3.6.1.4.1.318.1.3.4.6" },
{ ".1.3.6.1.4.1.4779.1.3.5.2.1.24.1", "baytech", ".1.3.6.1.4.1.4779" },
{ ".1.3.6.1.4.1.2947.1.1.2.0", "bestpower", ".1.3.6.1.4.1.2947.1.1.2.0" },
{ ".1.3.6.1.4.1.232.165.3.1.1.0", "cpqpower", ".1.3.6.1.4.1.232.165.3" },
{ ".1.3.6.1.4.1.3808.1.1.1.1.1.1.0", "cyberpower", ".1.3.6.1.4.1.3808.1.1.1" },
{ NULL, "delta_ups", ".1.3.6.1.4.1.2254.2.4" },
{ ".1.3.6.1.4.1.534.10.2.1.2.0", "eaton_ats16_nm2", ".1.3.6.1.4.1.534.10.2" },
{ ".1.3.6.1.4.1.534.10.2.1.2.0", "eaton_ats16_nmc", ".1.3.6.1.4.1.705.1" },
{ ".1.3.6.1.4.1.534.10.1.2.1.0", "eaton_ats30", ".1.3.6.1.4.1.534.10.1" },
{ ".1.3.6.1.4.1.17373.3.1.1.0", "aphel_genesisII", ".1.3.6.1.4.1.17373" },
{ ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0", "eaton_epdu", ".1.3.6.1.4.1.534.6.6.7" },
{ ".1.3.6.1.4.1.20677.1", "pulizzi_switched1", ".1.3.6.1.4.1.20677.1" },
{ ".1.3.6.1.4.1.20677.1", "pulizzi_switched2", ".1.3.6.1.4.1.20677.2" },
{ ".1.3.6.1.4.1.534.6.6.6.1.1.12.0", "aphel_revelation", ".1.3.6.1.4.1.534.6.6.6" },
{ ".1.3.6.1.4.1.10418.17.2.1.2.0", "emerson_avocent_pdu", ".1.3.6.1.4.1.10418.17.1.7" },
{ ".1.3.6.1.4.1.232.165.7.1.2.1.3.0", "hpe_epdu", ".1.3.6.1.4.1.232.165.7" },
{ ".1.3.6.1.4.1.2011.6.174.1.2.100.1.2.1", "huawei", ".1.3.6.1.4.1.8072.3.2.10" },
{ NULL, "tripplite", ".1.3.6.1.4.1.850.1" },
{ "1.3.6.1.2.1.33.1.1.1.0", "ietf", ".1.3.6.1.2.1.33" },
{ ".1.3.6.1.4.1.705.1.1.1.0", "mge", ".1.3.6.1.4.1.705.1" },
{ ".1.3.6.1.4.1.4555.1.1.1.1.1.1.0", "netvision", ".1.3.6.1.4.1.4555.1.1.1" },
{ "1.3.6.1.4.1.534.1.1.2.0", "pw", ".1.3.6.1.4.1.534.1" },
{ "1.3.6.1.4.1.534.1.1.2.0", "pxgx_ups", ".1.3.6.1.4.1.534.2.12" },
{ ".1.3.6.1.4.1.13742.1.1.12.0", "raritan", ".1.3.6.1.4.1.13742" },
{ ".1.3.6.1.4.1.13742.6.3.2.1.1.3.1", "raritan-px2", ".1.3.6.1.4.1.13742.6" },
{ NULL, "xppc", ".1.3.6.1.4.1.935" },
/* Terminating entry */
{ NULL, NULL, NULL }
};
#endif /* DEVSCAN_SNMP_H */

View file

@ -19,9 +19,29 @@
#ifndef DEVSCAN_USB_H
#define DEVSCAN_USB_H
#include <usb.h>
#include "nut_stdint.h" /* for uint16_t */
#include "nut_stdint.h" /* for uint16_t etc. */
#include <limits.h> /* for PATH_MAX in usb.h etc. */
#include <sys/param.h> /* for MAXPATHLEN etc. */
/* libusb header file */
#if (!WITH_LIBUSB_1_0) && (!WITH_LIBUSB_0_1)
#error "configure script error: Neither WITH_LIBUSB_1_0 nor WITH_LIBUSB_0_1 is set"
#endif
#if (WITH_LIBUSB_1_0) && (WITH_LIBUSB_0_1)
#error "configure script error: Both WITH_LIBUSB_1_0 and WITH_LIBUSB_0_1 are set"
#endif
#if WITH_LIBUSB_1_0
#include <libusb.h>
#endif
#if WITH_LIBUSB_0_1
#include <usb.h>
/* simple remap to avoid bloating structures */
typedef usb_dev_handle libusb_device_handle;
#endif
typedef struct {
uint16_t vendorID;
uint16_t productID;
@ -31,7 +51,7 @@ typedef struct {
/* USB IDs device table */
static usb_device_id_t usb_device_table[] = {
{ 0x0001, 0x0000, "nutdrv_atcl_usb" },
{ 0x0001, 0x0000, "nutdrv_qx" },
{ 0x03f0, 0x0001, "usbhid-ups" },
{ 0x03f0, 0x1f01, "bcmxcp_usb" },
{ 0x03f0, 0x1f02, "bcmxcp_usb" },
@ -51,6 +71,8 @@ static usb_device_id_t usb_device_table[] = {
{ 0x0463, 0xffff, "usbhid-ups" },
{ 0x047c, 0xffff, "usbhid-ups" },
{ 0x0483, 0x0035, "nutdrv_qx" },
{ 0x0483, 0xa113, "usbhid-ups" },
{ 0x04b3, 0x0001, "usbhid-ups" },
{ 0x04b4, 0x5500, "riello_usb" },
{ 0x04d8, 0xd004, "usbhid-ups" },
{ 0x04d8, 0xd005, "usbhid-ups" },
@ -69,14 +91,16 @@ static usb_device_id_t usb_device_table[] = {
{ 0x051d, 0x0003, "usbhid-ups" },
{ 0x0592, 0x0002, "bcmxcp_usb" },
{ 0x0592, 0x0004, "usbhid-ups" },
{ 0x05b8, 0x0000, "blazer_usb" },
{ 0x0665, 0x5161, "blazer_usb" },
{ 0x06da, 0x0002, "bcmxcp_usb" },
{ 0x06da, 0x0003, "blazer_usb" },
{ 0x06da, 0x0004, "blazer_usb" },
{ 0x06da, 0x0005, "blazer_usb" },
{ 0x06da, 0x0201, "blazer_usb" },
{ 0x06da, 0x0601, "blazer_usb" },
{ 0x05b8, 0x0000, "nutdrv_qx" },
{ 0x05dd, 0x041b, "usbhid-ups" },
{ 0x05dd, 0xa011, "usbhid-ups" },
{ 0x0665, 0x5161, "nutdrv_qx" },
{ 0x06da, 0x0002, "nutdrv_qx" },
{ 0x06da, 0x0003, "nutdrv_qx" },
{ 0x06da, 0x0004, "nutdrv_qx" },
{ 0x06da, 0x0005, "nutdrv_qx" },
{ 0x06da, 0x0201, "nutdrv_qx" },
{ 0x06da, 0x0601, "nutdrv_qx" },
{ 0x06da, 0xffff, "usbhid-ups" },
{ 0x075d, 0x0300, "usbhid-ups" },
{ 0x0764, 0x0005, "usbhid-ups" },
@ -89,6 +113,7 @@ static usb_device_id_t usb_device_table[] = {
{ 0x09ae, 0x1008, "usbhid-ups" },
{ 0x09ae, 0x1009, "usbhid-ups" },
{ 0x09ae, 0x1010, "usbhid-ups" },
{ 0x09ae, 0x1330, "usbhid-ups" },
{ 0x09ae, 0x2005, "usbhid-ups" },
{ 0x09ae, 0x2007, "usbhid-ups" },
{ 0x09ae, 0x2008, "usbhid-ups" },
@ -107,6 +132,7 @@ static usb_device_id_t usb_device_table[] = {
{ 0x09ae, 0x3014, "usbhid-ups" },
{ 0x09ae, 0x3015, "usbhid-ups" },
{ 0x09ae, 0x3016, "usbhid-ups" },
{ 0x09ae, 0x3024, "usbhid-ups" },
{ 0x09ae, 0x4001, "usbhid-ups" },
{ 0x09ae, 0x4002, "usbhid-ups" },
{ 0x09ae, 0x4003, "usbhid-ups" },
@ -122,15 +148,32 @@ static usb_device_id_t usb_device_table[] = {
{ 0x0d9f, 0x00a4, "usbhid-ups" },
{ 0x0d9f, 0x00a5, "usbhid-ups" },
{ 0x0d9f, 0x00a6, "usbhid-ups" },
{ 0x0f03, 0x0001, "blazer_usb" },
{ 0x0f03, 0x0001, "nutdrv_qx" },
{ 0x10af, 0x0001, "usbhid-ups" },
{ 0x10af, 0x0004, "usbhid-ups" },
{ 0x10af, 0x0008, "usbhid-ups" },
{ 0x14f0, 0x00c9, "blazer_usb" },
{ 0x14f0, 0x00c9, "nutdrv_qx" },
{ 0x1cb0, 0x0032, "usbhid-ups" },
{ 0x1cb0, 0x0035, "nutdrv_qx" },
{ 0x1cb0, 0x0038, "usbhid-ups" },
{ 0x2341, 0x0036, "usbhid-ups" },
{ 0x2341, 0x8036, "usbhid-ups" },
{ 0x2A03, 0x0036, "usbhid-ups" },
{ 0x2A03, 0x0040, "usbhid-ups" },
{ 0x2A03, 0x8036, "usbhid-ups" },
{ 0x2A03, 0x8040, "usbhid-ups" },
{ 0x2b2d, 0xffff, "usbhid-ups" },
{ 0xffff, 0x0000, "blazer_usb" },
{ 0x2e51, 0x0000, "usbhid-ups" },
{ 0x2e51, 0xffff, "usbhid-ups" },
{ 0x2e66, 0x0201, "usbhid-ups" },
{ 0x2e66, 0x0202, "usbhid-ups" },
{ 0x2e66, 0x0203, "usbhid-ups" },
{ 0x2e66, 0x0300, "usbhid-ups" },
{ 0x4234, 0x0002, "usbhid-ups" },
{ 0xffff, 0x0000, "nutdrv_qx" },
/* Terminating entry */
{ -1, -1, NULL }
{ 0, 0, NULL }
};
#endif /* DEVSCAN_USB_H */

View file

@ -86,13 +86,14 @@ 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 error */
/* return 0 on error; visible externally */
int nutscan_load_avahi_library(const char *libname_path);
int nutscan_load_avahi_library(const char *libname_path)
{
if( dl_handle != NULL ) {
if (dl_handle != NULL) {
/* if previous init failed */
if( dl_handle == (void *)1 ) {
return 0;
if (dl_handle == (void *)1) {
return 0;
}
/* init has already been done */
return 1;
@ -103,7 +104,7 @@ int nutscan_load_avahi_library(const char *libname_path)
return 0;
}
if( lt_dlinit() != 0 ) {
if (lt_dlinit() != 0) {
fprintf(stderr, "Error initializing lt_init\n");
return 0;
}
@ -115,98 +116,100 @@ int nutscan_load_avahi_library(const char *libname_path)
}
lt_dlerror(); /* Clear any existing error */
*(void **) (&nut_avahi_service_browser_get_client) = lt_dlsym(dl_handle, "avahi_service_browser_get_client");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_simple_poll_loop) = lt_dlsym(dl_handle, "avahi_simple_poll_loop");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_client_free) = lt_dlsym(dl_handle, "avahi_client_free");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_client_errno) = lt_dlsym(dl_handle, "avahi_client_errno");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_free) = lt_dlsym(dl_handle, "avahi_free");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_simple_poll_quit) = lt_dlsym(dl_handle, "avahi_simple_poll_quit");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_client_new) = lt_dlsym(dl_handle, "avahi_client_new");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_simple_poll_free) = lt_dlsym(dl_handle, "avahi_simple_poll_free");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_service_resolver_new) = lt_dlsym(dl_handle, "avahi_service_resolver_new");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_strerror) = lt_dlsym(dl_handle, "avahi_strerror");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_service_resolver_get_client) = lt_dlsym(dl_handle, "avahi_service_resolver_get_client");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_service_browser_new) = lt_dlsym(dl_handle, "avahi_service_browser_new");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_service_resolver_free) = lt_dlsym(dl_handle, "avahi_service_resolver_free");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_simple_poll_new) = lt_dlsym(dl_handle, "avahi_simple_poll_new");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_string_list_to_string) = lt_dlsym(dl_handle, "avahi_string_list_to_string");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_service_browser_free) = lt_dlsym(dl_handle, "avahi_service_browser_free");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_address_snprint) = lt_dlsym(dl_handle, "avahi_address_snprint");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_avahi_simple_poll_get) = lt_dlsym(dl_handle, "avahi_simple_poll_get");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
return 1;
err:
fprintf(stderr, "Cannot load AVAHI library (%s) : %s. AVAHI search disabled.\n", libname_path, dl_error);
fprintf(stderr,
"Cannot load AVAHI library (%s) : %s. AVAHI search disabled.\n",
libname_path, dl_error);
dl_handle = (void *)1;
lt_dlexit();
return 0;
@ -215,9 +218,9 @@ err:
static AvahiSimplePoll *simple_poll = NULL;
static nutscan_device_t * dev_ret = NULL;
static long avahi_usec_timeout = 0;
static useconds_t avahi_usec_timeout = 0;
static void update_device(const char * host_name,const char *ip, uint16_t port,char * text, int proto)
static void update_device(const char * host_name, const char *ip, uint16_t port, char * text, int proto)
{
nutscan_device_t * dev = NULL;
@ -231,113 +234,114 @@ static void update_device(const char * host_name,const char *ip, uint16_t port,c
char * device_saveptr = NULL;
int device_found = 0;
char buf[6];
int buf_size;
size_t buf_size;
if( text == NULL ) {
if (text == NULL) {
return;
}
t = strdup(text);
phrase = strtok_r(t,"\"",&t_saveptr);
while(phrase != NULL ) {
word = strtok_r(phrase,"=",&phrase_saveptr);
if( word == NULL ) {
phrase = strtok_r(NULL,"\"",&t_saveptr);
phrase = strtok_r(t, "\"", &t_saveptr);
while (phrase != NULL) {
word = strtok_r(phrase, "=", &phrase_saveptr);
if (word == NULL) {
phrase = strtok_r(NULL, "\"", &t_saveptr);
continue;
}
value = strtok_r(NULL,"=",&phrase_saveptr);
if( value == NULL ) {
phrase = strtok_r(NULL,"\"",&t_saveptr);
value = strtok_r(NULL, "=", &phrase_saveptr);
if (value == NULL) {
phrase = strtok_r(NULL, "\"", &t_saveptr);
continue;
}
if( strcmp(word,"device_list") != 0 ) {
phrase = strtok_r(NULL,"\"",&t_saveptr);
if (strcmp(word, "device_list") != 0) {
phrase = strtok_r(NULL, "\"", &t_saveptr);
continue;
}
device = strtok_r(value,";",&device_saveptr);
while( device != NULL ) {
device = strtok_r(value, ";", &device_saveptr);
while (device != NULL) {
device_found = 1;
dev = nutscan_new_device();
dev->type = TYPE_NUT;
dev->driver = strdup("nutclient");
if( proto == AVAHI_PROTO_INET) {
nutscan_add_option_to_device(dev,"desc","IPv4");
if (proto == AVAHI_PROTO_INET) {
nutscan_add_option_to_device(dev, "desc", "IPv4");
}
if( proto == AVAHI_PROTO_INET6 ) {
nutscan_add_option_to_device(dev,"desc","IPv6");
if (proto == AVAHI_PROTO_INET6) {
nutscan_add_option_to_device(dev, "desc", "IPv6");
}
if( port != PORT) {
/* +5+1+1+1 is for :
if (port != PORT) {
/* +5+1+1+1 is for :
- port number (max 65535 so 5 characters),
- '@' and ':' characters
- terminating 0 */
buf_size = strlen(device)+strlen(host_name)+
5+1+1+1;
dev->port=malloc(buf_size);
if(dev->port) {
snprintf(dev->port,buf_size,"%s@%s:%u",
device,host_name,port);
buf_size = strlen(device) +
strlen(host_name) +
5 + 1 + 1 + 1;
dev->port = malloc(buf_size);
if (dev->port) {
snprintf(dev->port, buf_size, "%s@%s:%u",
device, host_name, port);
}
}
else {
/*+1+1 is for '@' character and terminating 0 */
buf_size = strlen(device)+strlen(host_name)+1+1;
dev->port=malloc(buf_size);
if(dev->port) {
snprintf(dev->port,buf_size,"%s@%s",
device,host_name);
buf_size = strlen(device) + strlen(host_name) + 1 + 1;
dev->port = malloc(buf_size);
if (dev->port) {
snprintf(dev->port, buf_size, "%s@%s",
device, host_name);
}
}
if( dev->port ) {
dev_ret = nutscan_add_device_to_device(dev_ret,dev);
if (dev->port) {
dev_ret = nutscan_add_device_to_device(dev_ret, dev);
}
else {
nutscan_free_device(dev);
}
device = strtok_r(NULL,";",&device_saveptr);
};
device = strtok_r(NULL, ";", &device_saveptr);
}
phrase = strtok_r(NULL,"\"",&t_saveptr);
};
phrase = strtok_r(NULL, "\"", &t_saveptr);
}
free(t);
/* If no device published in avahi data, try to get the device by
connecting directly to upsd */
if( !device_found) {
snprintf(buf,sizeof(buf),"%u",port);
dev = nutscan_scan_nut(ip,ip,buf,avahi_usec_timeout);
if(dev) {
dev_ret = nutscan_add_device_to_device(dev_ret,dev);
if (!device_found) {
snprintf(buf, sizeof(buf), "%u", port);
dev = nutscan_scan_nut(ip, ip, buf, avahi_usec_timeout);
if (dev) {
dev_ret = nutscan_add_device_to_device(dev_ret, dev);
}
/* add an upsd entry without associated device */
else {
dev = nutscan_new_device();
dev->type = TYPE_NUT;
dev->driver = strdup("nutclient");
if( proto == AVAHI_PROTO_INET) {
nutscan_add_option_to_device(dev,"desc","IPv4");
if (proto == AVAHI_PROTO_INET) {
nutscan_add_option_to_device(dev, "desc", "IPv4");
}
if( proto == AVAHI_PROTO_INET6 ) {
nutscan_add_option_to_device(dev,"desc","IPv6");
if (proto == AVAHI_PROTO_INET6) {
nutscan_add_option_to_device(dev, "desc", "IPv6");
}
if( port != PORT) {
if (port != PORT) {
/*+1+1 is for ':' character and terminating 0 */
/*buf is the string containing the port number*/
buf_size = strlen(host_name)+strlen(buf)+1+1;
dev->port=malloc(buf_size);
if(dev->port) {
snprintf(dev->port,buf_size,"%s:%s",
host_name,buf);
buf_size = strlen(host_name) + strlen(buf) + 1 + 1;
dev->port = malloc(buf_size);
if (dev->port) {
snprintf(dev->port, buf_size, "%s:%s",
host_name, buf);
}
}
else {
dev->port=strdup(host_name);
dev->port = strdup(host_name);
}
if( dev->port ) {
dev_ret = nutscan_add_device_to_device(dev_ret,dev);
if (dev->port) {
dev_ret = nutscan_add_device_to_device(dev_ret, dev);
}
else {
nutscan_free_device(dev);
@ -348,8 +352,8 @@ static void update_device(const char * host_name,const char *ip, uint16_t port,c
static void resolve_callback(
AvahiServiceResolver *r,
AVAHI_GCC_UNUSED AvahiIfIndex interface,
AVAHI_GCC_UNUSED AvahiProtocol protocol,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name,
const char *type,
@ -359,15 +363,23 @@ static void resolve_callback(
uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags,
AVAHI_GCC_UNUSED void* userdata) {
void* userdata)
{
assert(r);
NUT_UNUSED_VARIABLE(interface);
NUT_UNUSED_VARIABLE(protocol);
NUT_UNUSED_VARIABLE(userdata);
/* Called whenever a service has been resolved successfully or timed out */
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, (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_resolver_get_client)(r))));
fprintf(stderr,
"(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
name, type, domain,
(*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_resolver_get_client)(r))));
break;
case AVAHI_RESOLVER_FOUND: {
@ -377,6 +389,8 @@ static void resolve_callback(
(*nut_avahi_address_snprint)(a, sizeof(a), address);
t = (*nut_avahi_string_list_to_string)(txt);
NUT_UNUSED_VARIABLE(flags);
/*
fprintf(stderr,
"\t%s:%u (%s)\n"
@ -396,7 +410,7 @@ static void resolve_callback(
!!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
!!(flags & AVAHI_LOOKUP_RESULT_CACHED));
*/
update_device(host_name,a,port,t,address->proto);
update_device(host_name, a, port, t, address->proto);
(*nut_avahi_free)(t);
}
}
@ -412,18 +426,23 @@ static void browse_callback(
const char *name,
const char *type,
const char *domain,
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
void* userdata) {
AvahiLookupResultFlags flags,
void* userdata)
{
AvahiClient *c = userdata;
assert(b);
NUT_UNUSED_VARIABLE(flags);
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
switch (event) {
case AVAHI_BROWSER_FAILURE:
fprintf(stderr, "(Browser) %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_browser_get_client)(b))));
fprintf(stderr,
"(Browser) %s\n",
(*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_browser_get_client)(b))));
(*nut_avahi_simple_poll_quit)(simple_poll);
return;
@ -435,8 +454,22 @@ static void browse_callback(
the callback function is called the server will free
the resolver for us. */
#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...
*/
if (!((*nut_avahi_service_resolver_new)(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, (*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
#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",
name, (*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
break;
@ -446,33 +479,39 @@ static void browse_callback(
case AVAHI_BROWSER_ALL_FOR_NOW:
(*nut_avahi_simple_poll_quit)(simple_poll);
goto fallthrough_AVAHI_BROWSER_CACHE_EXHAUSTED; /* be explicit */
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"); */
break;
}
}
static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
assert(c);
NUT_UNUSED_VARIABLE(userdata);
/* Called whenever the client or server state changes */
if (state == AVAHI_CLIENT_FAILURE) {
fprintf(stderr, "Server connection failure: %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
fprintf(stderr,
"Server connection failure: %s\n",
(*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
(*nut_avahi_simple_poll_quit)(simple_poll);
}
}
nutscan_device_t * nutscan_scan_avahi(long usec_timeout)
nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout)
{
/* Example service publication
/* Example service publication
* $ avahi-publish -s nut _upsd._tcp 3493 txtvers=1 protovers=1.0.0 device_list="dev1;dev2"
*/
AvahiClient *client = NULL;
AvahiServiceBrowser *sb = NULL;
int error;
if( !nutscan_avail_avahi ) {
if (!nutscan_avail_avahi) {
return NULL;
}
@ -485,17 +524,44 @@ nutscan_device_t * nutscan_scan_avahi(long 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
/* Check wether creating the client object succeeded */
if (!client) {
fprintf(stderr, "Failed to create client: %s\n", (*nut_avahi_strerror)(error));
fprintf(stderr,
"Failed to create client: %s\n",
(*nut_avahi_strerror)(error));
goto fail;
}
/* Create the service browser */
if (!(sb = (*nut_avahi_service_browser_new)(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_upsd._tcp", NULL, 0, browse_callback, client))) {
fprintf(stderr, "Failed to create service browser: %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)(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
/* See comments about flags just a bit above */
if (!(sb = (*nut_avahi_service_browser_new)(
client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
"_upsd._tcp", NULL, 0, browse_callback, client))
) {
#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 service browser: %s\n",
(*nut_avahi_strerror)((*nut_avahi_client_errno)(client)));
goto fail;
}
@ -518,8 +584,10 @@ fail:
}
#else /* WITH_AVAHI */
/* stub function */
nutscan_device_t * nutscan_scan_avahi(long usec_timeout)
nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout)
{
NUT_UNUSED_VARIABLE(usec_timeout);
return NULL;
}
#endif /* WITH_AVAHI */

View file

@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 - EATON
* Copyright (C) 2016-2021 - EATON - Various threads-related improvements
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,9 +20,11 @@
/*! \file scan_eaton_serial.c
\brief detect Eaton serial XCP, SHUT and Q1 devices
\author Arnaud Quette <ArnaudQuette@eaton.com>
\author Jim Klimov <EvgenyKlimov@eaton.com>
*/
#include "common.h"
#include "nut-scan.h"
/* Need this on AIX when using xlc to get alloca */
#ifdef _AIX
@ -30,36 +33,50 @@
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "nut-scan.h"
#include "serial.h"
#include "bcmxcp_io.h"
#include "bcmxcp_ser.h"
#include "bcmxcp.h"
#include "nutscan-serial.h"
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
/* SHUT header */
#define SHUT_SYNC 0x16
#define MAX_TRY 4
/* BCMXCP header */
extern unsigned char AUT[4];
/* BCMXCP header defines these externs now: */
/*
extern unsigned char BCMXCP_AUTHCMD[4];
extern struct pw_baud_rate {
int rate;
int name;
int rate;
int name;
} pw_baud_rates[];
*/
/* Local list of found devices */
static nutscan_device_t * dev_ret = NULL;
/* Remap some functions to avoid undesired behavior (drivers/main.c) */
char *getval(const char *var) { return NULL; }
char *getval(const char *var)
{
NUT_UNUSED_VARIABLE(var);
return NULL;
}
#ifdef HAVE_PTHREAD
static pthread_mutex_t dev_mutex;
@ -102,7 +119,7 @@ unsigned char calc_checksum(const unsigned char *buf)
int i;
c = 0;
for(i = 0; i < 2 + buf[1]; i++)
for (i = 0; i < 2 + buf[1]; i++)
c -= buf[i];
return c;
@ -114,18 +131,22 @@ unsigned char calc_checksum(const unsigned char *buf)
/* Light version of of drivers/libshut.c->shut_synchronise()
* return 1 if OK, 0 otherwise */
int shut_synchronise(int upsfd)
static int shut_synchronise(int arg_upsfd)
{
int try;
u_char reply = '\0';
unsigned char reply = '\0';
/* FIXME? Should we save "arg_upsfd" into global "upsfd" variable?
* This was previously shadowed by function argument named "upsfd"...
*/
/* upsfd = arg_upsfd; */
/* Sync with the UPS according to notification */
for (try = 0; try < MAX_TRY; try++) {
if ((ser_send_char(upsfd, SHUT_SYNC)) == -1) {
if ((ser_send_char(arg_upsfd, SHUT_SYNC)) == -1) {
continue;
}
ser_get_char(upsfd, &reply, 1, 0);
ser_get_char(arg_upsfd, &reply, 1, 0);
if (reply == SHUT_SYNC) {
return 1;
}
@ -137,12 +158,12 @@ int shut_synchronise(int upsfd)
* send SYNC token (0x16) and receive the SYNC token back
* FIXME: maybe try to get device descriptor?!
*/
nutscan_device_t * nutscan_scan_eaton_serial_shut(const char* port_name)
static nutscan_device_t * nutscan_scan_eaton_serial_shut(const char* port_name)
{
nutscan_device_t * dev = NULL;
int devfd = -1;
if ( (devfd = ser_open_nf(port_name)) != -1 ) {
if ((devfd = ser_open_nf(port_name)) != -1) {
/* set RTS to off and DTR to on to allow correct behavior
* with UPS using PnP feature */
if (ser_set_dtr(devfd, 1) != -1) {
@ -186,16 +207,17 @@ nutscan_device_t * nutscan_scan_eaton_serial_shut(const char* port_name)
* Send PW_SET_REQ_ONLY_MODE command (0xA0) and wait for response
* [Get ID Block (PW_ID_BLOCK_REQ) (0x31)]
*/
nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
static nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
{
nutscan_device_t * dev = NULL;
int i, ret, devfd = -1;
int i, devfd = -1;
ssize_t ret;
unsigned char answer[256];
unsigned char sbuf[128];
memset(sbuf, 0, 128);
if ( (devfd = ser_open_nf(port_name)) != -1 ) {
if ((devfd = ser_open_nf(port_name)) != -1) {
#ifdef HAVE_PTHREAD
pthread_mutex_lock(&dev_mutex);
#endif
@ -204,7 +226,7 @@ nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
pthread_mutex_unlock(&dev_mutex);
#endif
for (i=0; (pw_baud_rates[i].rate != 0) && (dev == NULL); i++)
for (i = 0; (pw_baud_rates[i].rate != 0) && (dev == NULL); i++)
{
memset(answer, 0, 256);
@ -216,9 +238,9 @@ nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
break;
usleep(90000);
send_write_command(AUT, 4);
send_write_command(BCMXCP_AUTHCMD, 4);
usleep(500000);
/* Discovery with Baud Hunting (XCP protocol spec. §4.1.2)
* sending PW_SET_REQ_ONLY_MODE should be enough, since
* the unit should send back Identification block */
@ -240,7 +262,7 @@ nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
}
#endif
if ( (ret > 0) && (answer[0] == PW_COMMAND_START_BYTE) ) {
if ((ret > 0) && (answer[0] == PW_COMMAND_START_BYTE)) {
dev = nutscan_new_device();
dev->type = TYPE_EATON_SERIAL;
dev->driver = strdup(XCP_DRIVER_NAME);
@ -275,15 +297,16 @@ nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name)
* - simply try to get Q1 (status) string
* - check its size and first char. which should be '('
*/
nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name)
static nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name)
{
nutscan_device_t * dev = NULL;
struct termios tio;
int ret = 0, retry;
ssize_t ret = 0;
int retry;
int devfd = -1;
char buf[128];
if ( (devfd = ser_open_nf(port_name)) != -1 ) {
if ((devfd = ser_open_nf(port_name)) != -1) {
if (ser_set_speed_nf(devfd, port_name, B2400) != -1) {
if (!tcgetattr(devfd, &tio)) {
@ -318,10 +341,10 @@ nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name)
/* simplified code */
ser_flush_io(devfd);
if ( (ret = ser_send(devfd, "Q1\r")) > 0) {
if ((ret = ser_send(devfd, "Q1\r")) > 0) {
/* Get Q1 reply */
if ( (ret = ser_get_buf(devfd, buf, sizeof(buf), SER_WAIT_SEC, 0)) > 0) {
if ((ret = ser_get_buf(devfd, buf, sizeof(buf), SER_WAIT_SEC, 0)) > 0) {
/* Check answer */
/* should at least (and most) be 46 chars */
@ -360,10 +383,10 @@ static void * nutscan_scan_eaton_serial_device(void * port_arg)
char* port_name = (char*) port_arg;
/* Try SHUT first */
if ( (dev = nutscan_scan_eaton_serial_shut(port_name)) == NULL) {
if ((dev = nutscan_scan_eaton_serial_shut(port_name)) == NULL) {
usleep(100000);
/* Else, try XCP */
if ( (dev = nutscan_scan_eaton_serial_xcp(port_name)) == NULL) {
if ((dev = nutscan_scan_eaton_serial_xcp(port_name)) == NULL) {
/* Else, try Q1 */
usleep(100000);
dev = nutscan_scan_eaton_serial_q1(port_name);
@ -375,66 +398,257 @@ static void * nutscan_scan_eaton_serial_device(void * port_arg)
nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range)
{
bool_t pass = TRUE; /* Track that we may spawn a scanning thread */
struct sigaction oldact;
int change_action_handler = 0;
char *current_port_name = NULL;
char **serial_ports_list;
int current_port_nb;
int i;
#ifdef HAVE_PTHREAD
# ifdef HAVE_SEMAPHORE
sem_t * semaphore = nutscan_semaphore();
# endif
pthread_t thread;
pthread_t * thread_array = NULL;
int thread_count = 0;
nutscan_thread_t * thread_array = NULL;
size_t thread_count = 0, i;
pthread_mutex_init(&dev_mutex,NULL);
#endif
pthread_mutex_init(&dev_mutex, NULL);
#endif /* HAVE_PTHREAD */
/* 1) Get ports_list */
serial_ports_list = nutscan_get_serial_ports_list(ports_range);
if( serial_ports_list == NULL ) {
if (serial_ports_list == NULL) {
return NULL;
}
/* Ignore SIGPIPE if the caller hasn't set a handler for it yet */
if( sigaction(SIGPIPE, NULL, &oldact) == 0 ) {
if( oldact.sa_handler == SIG_DFL ) {
if (sigaction(SIGPIPE, NULL, &oldact) == 0) {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
if (oldact.sa_handler == SIG_DFL) {
change_action_handler = 1;
signal(SIGPIPE,SIG_IGN);
signal(SIGPIPE, SIG_IGN);
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
}
/* port(s) iterator */
current_port_nb = 0;
while(serial_ports_list[current_port_nb] != NULL) {
current_port_name = serial_ports_list[current_port_nb];
while (serial_ports_list[current_port_nb] != NULL) {
#ifdef HAVE_PTHREAD
if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device, (void*)current_port_name) == 0){
thread_count++;
thread_array = realloc(thread_array,
thread_count*sizeof(pthread_t));
thread_array[thread_count-1] = thread;
/* 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 */
sem_wait(semaphore);
pass = TRUE;
} else {
pass = (sem_trywait(semaphore) == 0);
}
#else
nutscan_scan_eaton_serial_device(current_port_name);
#endif
current_port_nb++;
}
# 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) {
upsdebugx(2, "%s: already running %zu scanning threads "
"(launched overall: %zu), "
"waiting until some would finish",
__func__, curr_threads, thread_count);
while (curr_threads >= max_threads) {
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 #%zu joined earlier?", __func__, i);
break;
case 0: /* thread exited */
if (curr_threads > 0) {
curr_threads --;
upsdebugx(4, "%s: Joined a finished thread #%zu", __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 #%zu 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 #%zu reported code %i",
__func__, i, ret);
break;
}
pthread_mutex_unlock(&threadcount_mutex);
}
if (curr_threads >= max_threads) {
usleep (10000); /* microSec's, so 0.01s here */
}
}
upsdebugx(2, "%s: proceeding with scan", __func__);
}
/* 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) {
current_port_name = serial_ports_list[current_port_nb];
#ifdef HAVE_PTHREAD
for ( i = 0; i < thread_count ; i++) {
pthread_join(thread_array[i],NULL);
if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device, (void*)current_port_name) == 0) {
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
curr_threads++;
# endif /* HAVE_PTHREAD_TRYJOIN */
thread_count++;
nutscan_thread_t *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_eaton_serial_device(current_port_name);
#endif /* if HAVE_PTHREAD */
current_port_nb++;
} 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, "
"waiting until older ones would finish",
__func__);
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 %zu to be not active",
__func__, i);
sem_post(semaphore);
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);
}
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);
# 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 #%zu",
__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 */
}
free(thread_array);
upsdebugx(2, "%s: all threads freed", __func__);
}
pthread_mutex_destroy(&dev_mutex);
free(thread_array);
#endif
#endif /* HAVE_PTHREAD */
if(change_action_handler) {
signal(SIGPIPE,SIG_DFL);
if (change_action_handler) {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
signal(SIGPIPE, SIG_DFL);
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
}
/* free everything... */
i=0;
while(serial_ports_list[i] != NULL) {
i = 0;
while (serial_ports_list[i] != NULL) {
free(serial_ports_list[i]);
i++;
}

View file

@ -115,12 +115,13 @@ static void (*nut_ipmi_ctx_destroy) (ipmi_ctx_t ctx);
/* Internal functions */
static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec);
/* Return 0 on error */
/* Return 0 on error; visible externally */
int nutscan_load_ipmi_library(const char *libname_path);
int nutscan_load_ipmi_library(const char *libname_path)
{
if( dl_handle != NULL ) {
if (dl_handle != NULL) {
/* if previous init failed */
if( dl_handle == (void *)1 ) {
if (dl_handle == (void *)1) {
return 0;
}
/* init has already been done */
@ -132,7 +133,7 @@ int nutscan_load_ipmi_library(const char *libname_path)
return 0;
}
if( lt_dlinit() != 0 ) {
if (lt_dlinit() != 0) {
fprintf(stderr, "Error initializing lt_init\n");
return 0;
}
@ -147,97 +148,97 @@ int nutscan_load_ipmi_library(const char *libname_path)
lt_dlerror();
*(void **) (&nut_ipmi_fru_close_device_id) = lt_dlsym(dl_handle, IPMI_FRU_CLOSE_DEVICE_ID);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_ctx_destroy) = lt_dlsym(dl_handle, IPMI_FRU_CTX_DESTROY);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#ifdef HAVE_FREEIPMI_11X_12X
*(void **) (&nut_ipmi_sdr_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_ctx_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#else /* HAVE_FREEIPMI_11X_12X */
*(void **) (&nut_ipmi_sdr_cache_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_cache_ctx_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_sdr_parse_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_parse_ctx_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#endif /* HAVE_FREEIPMI_11X_12X */
*(void **) (&nut_ipmi_fru_ctx_create) = lt_dlsym(dl_handle, IPMI_FRU_CTX_CREATE);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_ctx_set_flags) = lt_dlsym(dl_handle, IPMI_FRU_CTX_SET_FLAGS);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_open_device_id) = lt_dlsym(dl_handle, IPMI_FRU_OPEN_DEVICE_ID);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_ctx_errormsg) = lt_dlsym(dl_handle, IPMI_FRU_CTX_ERRORMSG);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_read_data_area) = lt_dlsym(dl_handle, IPMI_FRU_READ_DATA_AREA);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_fru_next) = lt_dlsym(dl_handle, IPMI_FRU_PARSE_NEXT);
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_create) = lt_dlsym(dl_handle, "ipmi_ctx_create");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_find_inband) = lt_dlsym(dl_handle, "ipmi_ctx_find_inband");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_open_outofband) = lt_dlsym(dl_handle, "ipmi_ctx_open_outofband");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_errnum) = lt_dlsym(dl_handle, "ipmi_ctx_errnum");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_ctx_errormsg");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_close) = lt_dlsym(dl_handle, "ipmi_ctx_close");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ipmi_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_ctx_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
@ -285,12 +286,12 @@ static void nut_freeipmi_cleanup(ipmi_fru_parse_ctx_t fru_parse_ctx,
}
/* Return 1 if supported, 0 otherwise */
int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id)
static int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id)
{
int ret = -1;
unsigned int area_type = 0;
unsigned int area_length = 0;
uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1];
uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX + 1];
ipmi_fru_parse_ctx_t fru_parse_ctx = NULL;
#ifdef HAVE_FREEIPMI_11X_12X
ipmi_sdr_ctx_t sdr_ctx = NULL;
@ -317,7 +318,11 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id)
return 0;
}
if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, ipmi_id) < 0)
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);
return 0;
}
if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, (uint8_t)ipmi_id) < 0)
{
#ifdef HAVE_FREEIPMI_11X_12X
nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx);
@ -384,7 +389,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
int ipmi_id = 0;
char port_id[64];
if( !nutscan_avail_ipmi ) {
if (!nutscan_avail_ipmi) {
return NULL;
}
@ -392,12 +397,12 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ()))
{
/* we have to force cleanup, since exit handler is not yet installed */
fprintf(stderr, "ipmi_ctx_create\n");
fprintf(stderr, "Failed to ipmi_ctx_create\n");
return NULL;
}
/* Are we scanning locally, or over the network? */
if (IPaddr == NULL)
if (IPaddr == NULL)
{
/* FIXME: we need root right to access local IPMI!
if (!ipmi_is_root ()) {
@ -414,7 +419,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
0 /* flags */
)) < 0)
{
fprintf(stderr, "ipmi_ctx_find_inband: %s\n",
upsdebugx(2, "ipmi_ctx_find_inband (local scan): %s",
(*nut_ipmi_ctx_errormsg) (ipmi_ctx));
return NULL;
}
@ -441,7 +446,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
ipmi_sec->username,
ipmi_sec->password,
ipmi_sec->K_g_BMC_key,
??? (ipmi_sec->K_g_BMC_key) ? config->k_g_len : 0,
/*???*/ (ipmi_sec->K_g_BMC_key) ? config->k_g_len : 0,
ipmi_sec->privilege_level,
ipmi_sec->cipher_suite_id,
IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT,
@ -449,7 +454,11 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
ipmi_dev->workaround_flags,
flags) < 0)
{
IPMI_MONITORING_DEBUG (("ipmi_ctx_open_outofband_2_0: %s", ipmi_ctx_errormsg (c->ipmi_ctx)));
upsdebugx(2, "nut_ipmi_ctx_open_outofband_2_0 (%s): %s",
IPaddr, (*nut_ipmi_ctx_errormsg) (c->ipmi_ctx));
IPMI_MONITORING_DEBUG (("ipmi_ctx_open_outofband_2_0 (%s): %s",
IPaddr, ipmi_ctx_errormsg (c->ipmi_ctx)));
if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_USERNAME_INVALID)
c->errnum = IPMI_MONITORING_ERR_USERNAME_INVALID;
else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID)
@ -493,12 +502,28 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
#endif /* 0 */
/* Fall back to IPMI 1.5 */
if (ipmi_sec->authentication_type < 0
|| (unsigned int)ipmi_sec->authentication_type > UINT8_MAX
) {
upsdebugx(2, "nutscan_scan_ipmi_device (%s): "
"authentication_type=%d is out of range!",
IPaddr, ipmi_sec->authentication_type);
return 0;
}
if (ipmi_sec->privilege_level < 0
|| (unsigned int)ipmi_sec->privilege_level > UINT8_MAX
) {
upsdebugx(2, "nutscan_scan_ipmi_device (%s): "
"privilege_level=%d is out of range!",
IPaddr, ipmi_sec->privilege_level);
return 0;
}
if ((ret = (*nut_ipmi_ctx_open_outofband) (ipmi_ctx,
IPaddr,
ipmi_sec->username,
ipmi_sec->password,
ipmi_sec->authentication_type,
ipmi_sec->privilege_level,
(uint8_t)ipmi_sec->authentication_type,
(uint8_t)ipmi_sec->privilege_level,
IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT,
IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT,
ipmi_sec->workaround_flags,
@ -516,8 +541,8 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
|| (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) { */
/* FIXME: don't log timeout errors */
fprintf(stderr, "nut_ipmi_ctx_open_outofband: %s\n",
(*nut_ipmi_ctx_errormsg) (ipmi_ctx));
upsdebugx(2, "nut_ipmi_ctx_open_outofband (%s): %s",
IPaddr, (*nut_ipmi_ctx_errormsg) (ipmi_ctx));
return NULL;
/*}*/
}
@ -528,8 +553,8 @@ 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");
if ((nut_dev = nutscan_new_device()) == NULL) {
fprintf(stderr, "Memory allocation error\n");
nutscan_free_device(current_nut_dev);
break;
}
@ -547,13 +572,14 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t
nut_dev->port = strdup(port_id);
/* FIXME: also dump device.serial?
* using drivers/libfreeipmi_get_board_info() */
current_nut_dev = nutscan_add_device_to_device(
current_nut_dev,
nut_dev);
memset (port_id, 0, sizeof(port_id));
}
}
/* Final cleanup */
@ -576,13 +602,13 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip
nutscan_device_t * nut_dev = NULL;
nutscan_device_t * current_nut_dev = NULL;
if( !nutscan_avail_ipmi ) {
if (!nutscan_avail_ipmi) {
return NULL;
}
/* Are we scanning locally, or through the network? */
if (start_ip == NULL)
if (start_ip == NULL)
{
/* Local PSU scan */
current_nut_dev = nutscan_scan_ipmi_device(NULL, NULL);
@ -590,7 +616,7 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip
else {
ip_str = nutscan_ip_iter_init(&ip, start_ip, stop_ip);
while(ip_str != NULL) {
while (ip_str != NULL) {
tmp_sec = malloc(sizeof(nutscan_ipmi_t));
memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t));
@ -600,7 +626,7 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip
}
/* Prepare the next iteration */
ip_str = nutscan_ip_iter_inc(&ip);
};
}
}
return nutscan_rewind_device(current_nut_dev);
@ -609,6 +635,10 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip
/* stub function */
nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec)
{
NUT_UNUSED_VARIABLE(startIP);
NUT_UNUSED_VARIABLE(stopIP);
NUT_UNUSED_VARIABLE(sec);
return NULL;
}
#endif /* WITH_IPMI */

View file

@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 - EATON
* Copyright (C) 2016-2021 - EATON - Various threads-related improvements
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,27 +20,25 @@
/*! \file scan_nut.c
\brief detect remote NUT services
\author Frederic Bohe <fredericbohe@eaton.com>
\author Jim Klimov <EvgenyKlimov@eaton.com>
*/
#include "common.h"
#include "upsclient.h"
#include "nut-scan.h"
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#include <ltdl.h>
/* dynamic link library stuff */
static lt_dlhandle dl_handle = NULL;
static const char *dl_error = NULL;
static int (*nut_upscli_splitaddr)(const char *buf,char **hostname, int *port);
static int (*nut_upscli_splitaddr)(const char *buf, char **hostname, int *port);
static int (*nut_upscli_tryconnect)(UPSCONN_t *ups, const char *host, int port,
int flags,struct timeval * timeout);
static int (*nut_upscli_list_start)(UPSCONN_t *ups, unsigned int numq,
int flags, struct timeval * timeout);
static int (*nut_upscli_list_start)(UPSCONN_t *ups, size_t numq,
const char **query);
static int (*nut_upscli_list_next)(UPSCONN_t *ups, unsigned int numq,
const char **query,unsigned int *numa, char ***answer);
static int (*nut_upscli_list_next)(UPSCONN_t *ups, size_t numq,
const char **query, size_t *numa, char ***answer);
static int (*nut_upscli_disconnect)(UPSCONN_t *ups);
static nutscan_device_t * dev_ret = NULL;
@ -47,17 +46,25 @@ static nutscan_device_t * dev_ret = NULL;
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
struct scan_nut_arg {
char * hostname;
long timeout;
useconds_t timeout;
};
/* return 0 on error */
/* 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 (dl_handle != NULL) {
/* if previous init failed */
if( dl_handle == (void *)1 ) {
if (dl_handle == (void *)1) {
return 0;
}
/* init has already been done */
@ -69,7 +76,7 @@ int nutscan_load_upsclient_library(const char *libname_path)
return 0;
}
if( lt_dlinit() != 0 ) {
if (lt_dlinit() != 0) {
fprintf(stderr, "Error initializing lt_init\n");
return 0;
}
@ -84,31 +91,31 @@ int nutscan_load_upsclient_library(const char *libname_path)
*(void **) (&nut_upscli_splitaddr) = lt_dlsym(dl_handle,
"upscli_splitaddr");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_upscli_tryconnect) = lt_dlsym(dl_handle,
"upscli_tryconnect");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_upscli_list_start) = lt_dlsym(dl_handle,
"upscli_list_start");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_upscli_list_next) = lt_dlsym(dl_handle,
"upscli_list_next");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_upscli_disconnect) = lt_dlsym(dl_handle,
"upscli_disconnect");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
@ -127,13 +134,13 @@ static void * list_nut_devices(void * arg)
char *target_hostname = nut_arg->hostname;
struct timeval tv;
int port;
unsigned int numq, numa;
size_t numq, numa;
const char *query[4];
char **answer;
char *hostname = NULL;
UPSCONN_t *ups = malloc(sizeof(*ups));
nutscan_device_t * dev = NULL;
int buf_size;
size_t buf_size;
tv.tv_sec = nut_arg->timeout / (1000*1000);
tv.tv_usec = nut_arg->timeout % (1000*1000);
@ -148,14 +155,14 @@ static void * list_nut_devices(void * arg)
return NULL;
}
if ((*nut_upscli_tryconnect)(ups, hostname, port,UPSCLI_CONN_TRYSSL,&tv) < 0) {
if ((*nut_upscli_tryconnect)(ups, hostname, port, UPSCLI_CONN_TRYSSL, &tv) < 0) {
free(target_hostname);
free(nut_arg);
free(ups);
return NULL;
}
if((*nut_upscli_list_start)(ups, numq, query) < 0) {
if ((*nut_upscli_list_start)(ups, numq, query) < 0) {
(*nut_upscli_disconnect)(ups);
free(target_hostname);
free(nut_arg);
@ -163,7 +170,7 @@ static void * list_nut_devices(void * arg)
return NULL;
}
while ((*nut_upscli_list_next)(ups,numq, query, &numa, &answer) == 1) {
while ((*nut_upscli_list_next)(ups, numq, query, &numa, &answer) == 1) {
/* UPS <upsname> <description> */
if (numa < 3) {
(*nut_upscli_disconnect)(ups);
@ -177,26 +184,25 @@ static void * list_nut_devices(void * arg)
/* FIXME:
* - also print answer[2] if != "Unavailable"?
* - for upsmon.conf or ups.conf (using dummy-ups)? */
if (numa >= 3) {
dev = nutscan_new_device();
dev->type = TYPE_NUT;
dev->driver = strdup("nutclient");
/* +1+1 is for '@' character and terminating 0 */
buf_size = strlen(answer[1])+strlen(hostname)+1+1;
dev->port = malloc(buf_size);
if( dev->port ) {
snprintf(dev->port,buf_size,"%s@%s",answer[1],
hostname);
#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
}
dev = nutscan_new_device();
dev->type = TYPE_NUT;
dev->driver = strdup("nutclient");
/* +1+1 is for '@' character and terminating 0 */
buf_size = strlen(answer[1]) + strlen(hostname) + 1 + 1;
dev->port = malloc(buf_size);
if (dev->port) {
snprintf(dev->port, buf_size, "%s@%s", answer[1],
hostname);
#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
}
}
(*nut_upscli_disconnect)(ups);
@ -206,85 +212,330 @@ static void * list_nut_devices(void * arg)
return NULL;
}
nutscan_device_t * nutscan_scan_nut(const char* startIP, const char* stopIP, const char* port,long usec_timeout)
nutscan_device_t * nutscan_scan_nut(const char* startIP, const char* stopIP, const char* port, useconds_t usec_timeout)
{
bool_t pass = TRUE; /* Track that we may spawn a scanning thread */
nutscan_ip_iter_t ip;
char * ip_str = NULL;
char * ip_dest = NULL;
char buf[SMALLBUF];
struct sigaction oldact;
int change_action_handler = 0;
int i;
struct scan_nut_arg *nut_arg;
#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;
pthread_t * thread_array = NULL;
int thread_count = 0;
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_oldnut;
# endif
pthread_mutex_init(&dev_mutex,NULL);
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;
}
sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype);
}
# endif /* HAVE_SEMAPHORE */
if( !nutscan_avail_nut ) {
return NULL;
}
#endif /* HAVE_PTHREAD */
if (!nutscan_avail_nut) {
return NULL;
}
/* Ignore SIGPIPE if the caller hasn't set a handler for it yet */
if( sigaction(SIGPIPE, NULL, &oldact) == 0 ) {
if( oldact.sa_handler == SIG_DFL ) {
if (sigaction(SIGPIPE, NULL, &oldact) == 0) {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
if (oldact.sa_handler == SIG_DFL) {
change_action_handler = 1;
signal(SIGPIPE,SIG_IGN);
signal(SIGPIPE, SIG_IGN);
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
}
ip_str = nutscan_ip_iter_init(&ip,startIP,stopIP);
ip_str = nutscan_ip_iter_init(&ip, startIP, stopIP);
while( ip_str != NULL )
{
if( port ) {
if( ip.type == IPv4 ) {
snprintf(buf,sizeof(buf),"%s:%s",ip_str,port);
while (ip_str != NULL) {
#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 {
pass = ((max_threads_scantype == 0 || sem_trywait(semaphore_scantype) == 0) &&
sem_trywait(semaphore) == 0);
}
# 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 %zu scanning threads "
"(launched overall: %zu), "
"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 #%zu joined earlier?", __func__, i);
break;
case 0: /* thread exited */
if (curr_threads > 0) {
curr_threads --;
upsdebugx(4, "%s: Joined a finished thread #%zu", __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 #%zu 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 #%zu 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__);
}
/* 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) {
if (port) {
if (ip.type == IPv4) {
snprintf(buf, sizeof(buf), "%s:%s", ip_str, port);
}
else {
snprintf(buf, sizeof(buf), "[%s]:%s", ip_str, port);
}
ip_dest = strdup(buf);
}
else {
snprintf(buf,sizeof(buf),"[%s]:%s",ip_str,port);
ip_dest = strdup(ip_str);
}
ip_dest = strdup(buf);
}
else {
ip_dest = strdup(ip_str);
}
if ((nut_arg = malloc(sizeof(struct scan_nut_arg))) == NULL) {
free(ip_dest);
break;
}
if((nut_arg = malloc(sizeof(struct scan_nut_arg))) == NULL ) {
free(ip_dest);
break;
}
nut_arg->timeout = usec_timeout;
nut_arg->hostname = ip_dest;
#ifdef HAVE_PTHREAD
if (pthread_create(&thread,NULL,list_nut_devices,(void*)nut_arg)==0){
thread_count++;
thread_array = realloc(thread_array,
thread_count*sizeof(pthread_t));
thread_array[thread_count-1] = thread;
}
#else
list_nut_devices(nut_arg);
#endif
free(ip_str);
ip_str = nutscan_ip_iter_inc(&ip);
}
nut_arg->timeout = usec_timeout;
nut_arg->hostname = ip_dest;
#ifdef HAVE_PTHREAD
for ( i=0; i < thread_count ; i++) {
pthread_join(thread_array[i],NULL);
if (pthread_create(&thread, NULL, list_nut_devices, (void*)nut_arg) == 0) {
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
curr_threads++;
# endif /* HAVE_PTHREAD_TRYJOIN */
thread_count++;
nutscan_thread_t *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 /* not HAVE_PTHREAD */
list_nut_devices(nut_arg);
#endif /* if HAVE_PTHREAD */
free(ip_str);
ip_str = nutscan_ip_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, "
"waiting until older ones would finish",
__func__);
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 %zu 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 #%zu",
__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 */
}
free(thread_array);
upsdebugx(2, "%s: all threads freed", __func__);
}
pthread_mutex_destroy(&dev_mutex);
free(thread_array);
#endif
if(change_action_handler) {
signal(SIGPIPE,SIG_DFL);
# ifdef HAVE_SEMAPHORE
if (max_threads_scantype > 0)
sem_destroy(semaphore_scantype);
# endif /* HAVE_SEMAPHORE */
#endif /* HAVE_PTHREAD */
if (change_action_handler) {
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
signal(SIGPIPE, SIG_DFL);
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
}
return nutscan_rewind_device(dev_ret);

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 - EATON
* Copyright (C) 2011-2016 - EATON
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,6 +19,7 @@
/*! \file scan_usb.c
\brief detect NUT supported USB devices
\author Frederic Bohe <fredericbohe@eaton.com>
\author Arnaud Quette <ArnaudQuette@Eaton.com>
*/
#include "common.h"
@ -34,22 +35,46 @@
/* dynamic link library stuff */
static lt_dlhandle dl_handle = NULL;
static const char *dl_error = NULL;
static int (*nut_usb_close)(usb_dev_handle *dev);
static int (*nut_usb_find_busses)(void);
static char * (*nut_usb_strerror)(void);
static void (*nut_usb_init)(void);
static int (*nut_usb_get_string_simple)(usb_dev_handle *dev, int index,
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);
static struct usb_bus * (*nut_usb_busses);
static usb_dev_handle * (*nut_usb_open)(struct usb_device *dev);
static int (*nut_usb_find_devices)(void);
/* return 0 on error */
/* Compatibility layer between libusb 0.1 and 1.0 */
#if WITH_LIBUSB_1_0
#define USB_INIT_SYMBOL "libusb_init"
#define USB_OPEN_SYMBOL "libusb_open"
#define USB_CLOSE_SYMBOL "libusb_close"
#define USB_STRERROR_SYMBOL "libusb_strerror"
static int (*nut_usb_open)(libusb_device *dev, libusb_device_handle **handle);
static int (*nut_usb_init)(libusb_context **ctx);
static void (*nut_usb_exit)(libusb_context *ctx);
static char * (*nut_usb_strerror)(enum libusb_error errcode);
static ssize_t (*nut_usb_get_device_list)(libusb_context *ctx, libusb_device ***list);
static void (*nut_usb_free_device_list)(libusb_device **list, int unref_devices);
static uint8_t (*nut_usb_get_bus_number)(libusb_device *dev);
static int (*nut_usb_get_device_descriptor)(libusb_device *dev,
struct libusb_device_descriptor *desc);
#else
#define USB_INIT_SYMBOL "usb_init"
#define USB_OPEN_SYMBOL "usb_open"
#define USB_CLOSE_SYMBOL "usb_close"
#define USB_STRERROR_SYMBOL "usb_strerror"
static libusb_device_handle * (*nut_usb_open)(struct usb_device *dev);
static void (*nut_usb_init)(void);
static int (*nut_usb_find_busses)(void);
static struct usb_bus * (*nut_usb_busses);
static int (*nut_usb_find_devices)(void);
static char * (*nut_usb_strerror)(void);
#endif
/* return 0 on error; visible externally */
int nutscan_load_usb_library(const char *libname_path);
int nutscan_load_usb_library(const char *libname_path)
{
if( dl_handle != NULL ) {
if (dl_handle != NULL) {
/* if previous init failed */
if( dl_handle == (void *)1 ) {
if (dl_handle == (void *)1) {
return 0;
}
/* init has already been done */
@ -61,7 +86,7 @@ int nutscan_load_usb_library(const char *libname_path)
return 0;
}
if( lt_dlinit() != 0 ) {
if (lt_dlinit() != 0) {
fprintf(stderr, "Error initializing lt_init\n");
return 0;
}
@ -71,49 +96,84 @@ int nutscan_load_usb_library(const char *libname_path)
dl_error = lt_dlerror();
goto err;
}
*(void **) (&nut_usb_init) = lt_dlsym(dl_handle, USB_INIT_SYMBOL);
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_open) = lt_dlsym(dl_handle, USB_OPEN_SYMBOL);
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
lt_dlerror(); /* Clear any existing error */
*(void **) (&nut_usb_close) = lt_dlsym(dl_handle, "usb_close");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **) (&nut_usb_close) = lt_dlsym(dl_handle, USB_CLOSE_SYMBOL);
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_strerror) = lt_dlsym(dl_handle, USB_STRERROR_SYMBOL);
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#if WITH_LIBUSB_1_0
*(void **) (&nut_usb_exit) = lt_dlsym(dl_handle, "libusb_exit");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_get_device_list) = lt_dlsym(dl_handle, "libusb_get_device_list");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_free_device_list) = lt_dlsym(dl_handle, "libusb_free_device_list");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_get_bus_number) = lt_dlsym(dl_handle, "libusb_get_bus_number");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_get_device_descriptor) = lt_dlsym(dl_handle, "libusb_get_device_descriptor");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_get_string_simple) = lt_dlsym(dl_handle,
"libusb_get_string_descriptor_ascii");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#else /* for libusb 0.1 */
*(void **) (&nut_usb_find_busses) = lt_dlsym(dl_handle, "usb_find_busses");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_strerror) = lt_dlsym(dl_handle, "usb_strerror");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **) (&nut_usb_busses) = lt_dlsym(dl_handle, "usb_busses");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_init) = lt_dlsym(dl_handle, "usb_init");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **)(&nut_usb_find_devices) = lt_dlsym(dl_handle, "usb_find_devices");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_get_string_simple) = lt_dlsym(dl_handle,
"usb_get_string_simple");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_busses) = lt_dlsym(dl_handle, "usb_busses");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_usb_open) = lt_dlsym(dl_handle, "usb_open");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **)(&nut_usb_find_devices) = lt_dlsym(dl_handle,"usb_find_devices");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
#endif /* WITH_LIBUSB_1_0 */
return 1;
err:
fprintf(stderr, "Cannot load USB library (%s) : %s. USB search disabled.\n", libname_path, dl_error);
dl_handle = (void *)1;
@ -127,10 +187,10 @@ static char* is_usb_device_supported(usb_device_id_t *usb_device_id_list,
{
usb_device_id_t *usbdev;
for (usbdev=usb_device_id_list; usbdev->driver_name != NULL; usbdev++) {
if ( (usbdev->vendorID == dev_VendorID)
&& (usbdev->productID == dev_ProductID) ) {
for (usbdev = usb_device_id_list; usbdev->driver_name != NULL; usbdev++) {
if ((usbdev->vendorID == dev_VendorID)
&& (usbdev->productID == dev_ProductID)
) {
return usbdev->driver_name;
}
}
@ -147,128 +207,259 @@ nutscan_device_t * nutscan_scan_usb()
char *serialnumber = NULL;
char *device_name = NULL;
char *vendor_name = NULL;
uint8_t iManufacturer = 0, iProduct = 0, iSerialNumber = 0;
uint16_t VendorID;
uint16_t ProductID;
char *busname;
#if WITH_LIBUSB_1_0
libusb_device *dev;
libusb_device **devlist;
uint8_t bus;
#else /* => WITH_LIBUSB_0_1 */
struct usb_device *dev;
struct usb_bus *bus;
usb_dev_handle *udev;
#endif /* WITH_LIBUSB_1_0 */
libusb_device_handle *udev;
nutscan_device_t * nut_dev = NULL;
nutscan_device_t * current_nut_dev = NULL;
if( !nutscan_avail_usb ) {
return NULL;
}
if (!nutscan_avail_usb) {
return NULL;
}
/* libusb base init */
/* Initialize Libusb */
#if WITH_LIBUSB_1_0
if ((*nut_usb_init)(NULL) < 0) {
(*nut_usb_exit)(NULL);
fatal_with_errno(EXIT_FAILURE, "Failed to init libusb 1.0");
}
#else /* => WITH_LIBUSB_0_1 */
(*nut_usb_init)();
(*nut_usb_find_busses)();
(*nut_usb_find_devices)();
#endif /* WITH_LIBUSB_1_0 */
#if WITH_LIBUSB_1_0
ssize_t devcount = 0;
struct libusb_device_descriptor dev_desc;
int i;
devcount = (*nut_usb_get_device_list)(NULL, &devlist);
if (devcount <= 0) {
(*nut_usb_exit)(NULL);
fatal_with_errno(EXIT_FAILURE, "No USB device found");
}
for (i = 0; i < devcount; i++) {
dev = devlist[i];
(*nut_usb_get_device_descriptor)(dev, &dev_desc);
VendorID = dev_desc.idVendor;
ProductID = dev_desc.idProduct;
iManufacturer = dev_desc.iManufacturer;
iProduct = dev_desc.iProduct;
iSerialNumber = dev_desc.iSerialNumber;
bus = (*nut_usb_get_bus_number)(dev);
busname = (char *)malloc(4);
if (busname == NULL) {
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
fatal_with_errno(EXIT_FAILURE, "Out of memory");
}
snprintf(busname, 4, "%03d", bus);
#else /* => WITH_LIBUSB_0_1 */
for (bus = (*nut_usb_busses); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
VendorID = dev->descriptor.idVendor;
ProductID = dev->descriptor.idProduct;
iManufacturer = dev->descriptor.iManufacturer;
iProduct = dev->descriptor.iProduct;
iSerialNumber = dev->descriptor.iSerialNumber;
busname = bus->dirname;
#endif
if ((driver_name =
is_usb_device_supported(usb_device_table,
dev->descriptor.idVendor,
dev->descriptor.idProduct)) != NULL) {
VendorID, ProductID)) != NULL) {
/* open the device */
#if WITH_LIBUSB_1_0
ret = (*nut_usb_open)(dev, &udev);
if (!udev || ret != LIBUSB_SUCCESS) {
fprintf(stderr,"Failed to open device "
"bus '%s', skipping: %s\n",
busname,
(*nut_usb_strerror)(ret));
/* Note: closing is not applicable
* it seems, and can even segfault
* (even though an udev is not NULL
* when e.g. permissions problem)
*/
free (busname);
continue;
}
#else /* => WITH_LIBUSB_0_1 */
udev = (*nut_usb_open)(dev);
if (!udev) {
fprintf(stderr,"Failed to open device, \
skipping. (%s)\n",
/* TOTHINK: any errno or similar to test? */
fprintf(stderr, "Failed to open device "
"bus '%s',skipping: %s\n",
busname,
(*nut_usb_strerror)());
continue;
}
#endif
/* get serial number */
if (dev->descriptor.iSerialNumber) {
if (iSerialNumber) {
ret = (*nut_usb_get_string_simple)(udev,
dev->descriptor.iSerialNumber,
string, sizeof(string));
iSerialNumber, string, sizeof(string));
if (ret > 0) {
serialnumber = strdup(str_rtrim(string, ' '));
if (serialnumber == NULL) {
(*nut_usb_close)(udev);
#if WITH_LIBUSB_1_0
free(busname);
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
#endif /* WITH_LIBUSB_1_0 */
fatal_with_errno(EXIT_FAILURE, "Out of memory");
}
}
}
/* get product name */
if (dev->descriptor.iProduct) {
if (iProduct) {
ret = (*nut_usb_get_string_simple)(udev,
dev->descriptor.iProduct,
string, sizeof(string));
iProduct, string, sizeof(string));
if (ret > 0) {
device_name = strdup(str_rtrim(string, ' '));
if (device_name == NULL) {
free(serialnumber);
(*nut_usb_close)(udev);
#if WITH_LIBUSB_1_0
free(busname);
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
#endif /* WITH_LIBUSB_1_0 */
fatal_with_errno(EXIT_FAILURE, "Out of memory");
}
}
}
/* get vendor name */
if (dev->descriptor.iManufacturer) {
if (iManufacturer) {
ret = (*nut_usb_get_string_simple)(udev,
dev->descriptor.iManufacturer,
string, sizeof(string));
iManufacturer, string, sizeof(string));
if (ret > 0) {
vendor_name = strdup(str_rtrim(string, ' '));
if (vendor_name == NULL) {
free(serialnumber);
free(device_name);
(*nut_usb_close)(udev);
#if WITH_LIBUSB_1_0
free(busname);
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
#endif /* WITH_LIBUSB_1_0 */
fatal_with_errno(EXIT_FAILURE, "Out of memory");
}
}
}
nut_dev = nutscan_new_device();
if(nut_dev == NULL) {
fprintf(stderr,"Memory allocation \
error\n");
if (nut_dev == NULL) {
fprintf(stderr,
"Memory allocation error\n");
nutscan_free_device(current_nut_dev);
free(serialnumber);
free(device_name);
free(vendor_name);
(*nut_usb_close)(udev);
#if WITH_LIBUSB_1_0
free(busname);
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
#endif /* WITH_LIBUSB_1_0 */
return NULL;
}
nut_dev->type = TYPE_USB;
if(driver_name) {
if (driver_name) {
nut_dev->driver = strdup(driver_name);
}
nut_dev->port = strdup("auto");
sprintf(string,"%04X",dev->descriptor.idVendor);
nutscan_add_option_to_device(nut_dev,"vendorid",
string);
sprintf(string,"%04X",
dev->descriptor.idProduct);
nutscan_add_option_to_device(nut_dev,"productid",
string);
if(device_name) {
sprintf(string, "%04X", VendorID);
nutscan_add_option_to_device(nut_dev,
"vendorid",
string);
sprintf(string, "%04X", ProductID);
nutscan_add_option_to_device(nut_dev,
"productid",
string);
if (device_name) {
nutscan_add_option_to_device(nut_dev,
"product",
device_name);
"product",
device_name);
free(device_name);
device_name = NULL;
}
if(serialnumber) {
if (serialnumber) {
nutscan_add_option_to_device(nut_dev,
"serial",
serialnumber);
"serial",
serialnumber);
free(serialnumber);
serialnumber = NULL;
}
if(vendor_name) {
if (vendor_name) {
nutscan_add_option_to_device(nut_dev,
"vendor",
vendor_name);
"vendor",
vendor_name);
free(vendor_name);
vendor_name = NULL;
}
nutscan_add_option_to_device(nut_dev,"bus",
bus->dirname);
nutscan_add_option_to_device(nut_dev,
"bus",
busname);
current_nut_dev = nutscan_add_device_to_device(
current_nut_dev,
nut_dev);
current_nut_dev,
nut_dev);
memset (string, 0, sizeof(string));
(*nut_usb_close)(udev);
}
#if WITH_LIBUSB_0_1
}
}
#else /* not WITH_LIBUSB_0_1 */
free(busname);
}
(*nut_usb_free_device_list)(devlist, 1);
(*nut_usb_exit)(NULL);
#endif /* WITH_LIBUSB_0_1 */
return nutscan_rewind_device(current_nut_dev);
}
#else /* WITH_USB */
#else /* not WITH_USB */
nutscan_device_t * nutscan_scan_usb()
{
return NULL;
}
#endif /* WITH_USB */

View file

@ -1,5 +1,7 @@
/*
* Copyright (C) 2011 - EATON
* Copyright (C) 2016 - EATON - IP addressed XML scan
* Copyright (C) 2016-2021 - EATON - Various threads-related improvements
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,10 +21,13 @@
/*! \file scan_xml_http.c
\brief detect NUT supported XML HTTP devices
\author Frederic Bohe <fredericbohe@eaton.com>
\author Michal Vyskocil <MichalVyskocil@eaton.com>
\author Jim Klimov <EvgenyKlimov@eaton.com>
*/
#include "common.h"
#include "nut-scan.h"
#ifdef WITH_NEON
#include <sys/types.h>
#include <sys/socket.h>
@ -37,7 +42,7 @@
#include <ltdl.h>
/* dynamic link library stuff */
static char * libname = "libneon";
static char * libname = "libneon"; /* Note: this is for info messages, not the SONAME */
static lt_dlhandle dl_handle = NULL;
static const char *dl_error = NULL;
@ -47,15 +52,29 @@ static void (*nut_ne_xml_push_handler)(ne_xml_parser *p,
ne_xml_endelm_cb *endelm,
void *userdata);
static void (*nut_ne_xml_destroy)(ne_xml_parser *p);
static int (*nut_ne_xml_failed)(ne_xml_parser *p);
static ne_xml_parser * (*nut_ne_xml_create)(void);
static int (*nut_ne_xml_parse)(ne_xml_parser *p, const char *block, size_t len);
/* return 0 on error */
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
/* return 0 on error; visible externally */
int nutscan_load_neon_library(const char *libname_path);
int nutscan_load_neon_library(const char *libname_path)
{
if( dl_handle != NULL ) {
if (dl_handle != NULL) {
/* if previous init failed */
if( dl_handle == (void *)1 ) {
if (dl_handle == (void *)1) {
return 0;
}
/* init has already been done */
@ -67,7 +86,7 @@ int nutscan_load_neon_library(const char *libname_path)
return 0;
}
if( lt_dlinit() != 0 ) {
if (lt_dlinit() != 0) {
fprintf(stderr, "Error initializing lt_init\n");
return 0;
}
@ -81,22 +100,27 @@ int nutscan_load_neon_library(const char *libname_path)
lt_dlerror(); /* Clear any existing error */
*(void **) (&nut_ne_xml_push_handler) = lt_dlsym(dl_handle,
"ne_xml_push_handler");
if ((dl_error = lt_dlerror()) != NULL) {
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ne_xml_destroy) = lt_dlsym(dl_handle,"ne_xml_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **) (&nut_ne_xml_destroy) = lt_dlsym(dl_handle, "ne_xml_destroy");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ne_xml_create) = lt_dlsym(dl_handle,"ne_xml_create");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **) (&nut_ne_xml_create) = lt_dlsym(dl_handle, "ne_xml_create");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ne_xml_parse) = lt_dlsym(dl_handle,"ne_xml_parse");
if ((dl_error = lt_dlerror()) != NULL) {
*(void **) (&nut_ne_xml_parse) = lt_dlsym(dl_handle, "ne_xml_parse");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
*(void **) (&nut_ne_xml_failed) = lt_dlsym(dl_handle, "ne_xml_failed");
if ((dl_error = lt_dlerror()) != NULL) {
goto err;
}
@ -108,142 +132,585 @@ err:
return 0;
}
/* 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) {
nutscan_device_t * dev = (nutscan_device_t *)userdata;
char buf[SMALLBUF];
int i = 0;
while( atts[i] != NULL ) {
if(strcmp(atts[i],"type") == 0) {
snprintf(buf,sizeof(buf),"%s",atts[i+1]);
nutscan_add_option_to_device(dev,"desc",buf);
return 0;
int result = -1;
while (atts[i] != NULL) {
upsdebugx(5, "startelm_cb() : parent=%d nspace='%s' name='%s' atts[%d]='%s' atts[%d]='%s'",
parent, nspace, name, i, atts[i], (i + 1), atts[i + 1]);
/* The Eaton/MGE ePDUs almost exclusively support only XMLv4 protocol
* (only the very first generation of G2/G3 NMCs supported an older
* protocol, but all should have been FW upgraded by now), which NUT
* drivers don't yet support. To avoid failing drivers later, the
* nut-scanner should not suggest netxml-ups configuration for ePDUs
* at this time. */
if (strcmp(atts[i], "class") == 0 && strcmp(atts[i + 1], "DEV.PDU") == 0) {
upsdebugx(3, "startelm_cb() : XML v4 protocol is not supported by current NUT drivers, skipping device!");
/* netxml-ups currently only supports XML version 3 (for UPS),
* and not version 4 (for UPS and PDU)! */
return -1;
}
i=i+2;
if (strcmp(atts[i], "type") == 0) {
snprintf(buf, sizeof(buf), "%s", atts[i + 1]);
nutscan_add_option_to_device(dev, "desc", buf);
result = 0;
}
i = i + 2;
}
return 0;
return result;
}
nutscan_device_t * nutscan_scan_xml_http(long usec_timeout)
static void * nutscan_scan_xml_http_generic(void * arg)
{
nutscan_xml_t * sec = (nutscan_xml_t *)arg;
char *scanMsg = "<SCAN_REQUEST/>";
int port = 4679;
/* 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 */
char *ip = NULL;
useconds_t usec_timeout = 0;
int peerSocket;
int sockopt_on = 1;
struct sockaddr_in sockAddress;
socklen_t sockAddressLength = sizeof(sockAddress);
memset(&sockAddress, 0, sizeof(sockAddress));
struct sockaddr_in sockAddress_udp;
socklen_t sockAddressLength = sizeof(sockAddress_udp);
memset(&sockAddress_udp, 0, sizeof(sockAddress_udp));
fd_set fds;
struct timeval timeout;
int ret;
char buf[SMALLBUF];
char buf[SMALLBUF + 8];
char string[SMALLBUF];
ssize_t recv_size;
int i;
nutscan_device_t * nut_dev = NULL;
nutscan_device_t * current_nut_dev = NULL;
if (sec != NULL) {
/* if (sec->port_http > 0 && sec->port_http <= 65534)
* port_http = sec->port_http; */
if (sec->port_udp > 0 && sec->port_udp <= 65534)
port_udp = sec->port_udp;
if (sec->usec_timeout > 0)
usec_timeout = sec->usec_timeout;
ip = sec->peername; /* NULL or not... */
}
if( !nutscan_avail_xml_http ) {
return NULL;
}
if (usec_timeout <= 0)
usec_timeout = 5000000; /* Driver default : 5sec */
if((peerSocket = socket(AF_INET, SOCK_DGRAM, 0)) != -1)
{
if (!nutscan_avail_xml_http) {
return NULL;
}
if ((peerSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Error creating socket\n");
return NULL;
}
/* 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.sin_family = AF_INET;
sockAddress.sin_addr.s_addr = INADDR_BROADCAST;
sockAddress.sin_port = htons(port);
setsockopt(peerSocket, SOL_SOCKET, SO_BROADCAST, &sockopt_on,
sockAddress_udp.sin_family = AF_INET;
if (ip == NULL) {
upsdebugx(2,
"nutscan_scan_xml_http_generic() : scanning connected network segment(s) "
"with a broadcast, attempt %d of %d with a timeout of %jd usec",
(i + 1), MAX_RETRIES, (uintmax_t)usec_timeout);
sockAddress_udp.sin_addr.s_addr = INADDR_BROADCAST;
setsockopt(peerSocket, SOL_SOCKET, SO_BROADCAST, &sockopt_on,
sizeof(sockopt_on));
} else {
upsdebugx(2,
"nutscan_scan_xml_http_generic() : scanning IP '%s' with a unicast, "
"attempt %d of %d with a timeout of %jd usec",
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);
/* Send scan request */
if(sendto(peerSocket, scanMsg, strlen(scanMsg), 0,
(struct sockaddr *)&sockAddress,
sockAddressLength) <= 0)
{
fprintf(stderr,"Error sending Eaton <SCAN_REQUEST/>\n");
if (sendto(peerSocket, scanMsg, strlen(scanMsg), 0,
(struct sockaddr *)&sockAddress_udp,
sockAddressLength) <= 0
) {
fprintf(stderr,
"Error sending Eaton <SCAN_REQUEST/> to %s, #%d/%d\n",
(ip ? ip : "<broadcast>"), (i + 1), MAX_RETRIES);
usleep(usec_timeout);
continue;
}
else
{
int retNum = 0;
FD_ZERO(&fds);
FD_SET(peerSocket,&fds);
FD_SET(peerSocket, &fds);
timeout.tv_sec = usec_timeout / 1000000;
timeout.tv_usec = usec_timeout % 1000000;
while ((ret=select(peerSocket+1,&fds,NULL,NULL,
&timeout) )) {
upsdebugx(5, "nutscan_scan_xml_http_generic() : sent request to %s, "
"loop #%d/%d, waiting for responses",
(ip ? ip : "<broadcast>"), (i + 1), MAX_RETRIES);
while ((ret = select(peerSocket + 1, &fds, NULL, NULL,
&timeout))
) {
retNum ++;
upsdebugx(5, "nutscan_scan_xml_http_generic() : request to %s, "
"loop #%d/%d, response #%d",
(ip ? ip : "<broadcast>"), (i + 1), MAX_RETRIES, retNum);
timeout.tv_sec = usec_timeout / 1000000;
timeout.tv_usec = usec_timeout % 1000000;
if( ret == -1 ) {
if (ret == -1) {
fprintf(stderr,
"Error waiting on \
socket: %d\n",errno);
socket: %d\n", errno);
break;
}
sockAddressLength = sizeof(struct sockaddr_in);
recv_size = recvfrom(peerSocket,buf,
sizeof(buf),0,
(struct sockaddr *)&sockAddress,
&sockAddressLength);
recv_size = recvfrom(peerSocket, buf,
sizeof(buf), 0,
(struct sockaddr *)&sockAddress_udp,
&sockAddressLength);
if(recv_size==-1) {
if (recv_size < 0) {
fprintf(stderr,
"Error reading \
socket: %d\n",errno);
socket: %d, #%d/%d\n", errno, (i + 1), MAX_RETRIES);
usleep(usec_timeout);
continue;
}
if( getnameinfo(
(struct sockaddr *)&sockAddress,
sizeof(struct sockaddr_in),string,
sizeof(string),NULL,0,
NI_NUMERICHOST) != 0) {
if (getnameinfo(
(struct sockaddr *)&sockAddress_udp,
sizeof(struct sockaddr_in), string,
sizeof(string), NULL, 0,
NI_NUMERICHOST) != 0
) {
fprintf(stderr,
"Error converting IP address \
: %d\n",errno);
"Error converting IP address: %d\n", errno);
usleep(usec_timeout);
continue;
}
nut_dev = nutscan_new_device();
if(nut_dev == NULL) {
fprintf(stderr,"Memory allocation \
error\n");
return NULL;
}
nut_dev = nutscan_new_device();
if (nut_dev == NULL) {
fprintf(stderr, "Memory allocation error\n");
goto end_abort;
}
nut_dev->type = TYPE_XML;
#ifdef HAVE_PTHREAD
pthread_mutex_lock(&dev_mutex);
#endif
upsdebugx(5,
"Some host at IP %s replied to NetXML UDP request on port %d, "
"inspecting the response...",
string, port_udp);
nut_dev->type = TYPE_XML;
/* Try to read device type */
ne_xml_parser *parser = (*nut_ne_xml_create)();
(*nut_ne_xml_push_handler)(parser, startelm_cb,
NULL, NULL, nut_dev);
(*nut_ne_xml_parse)(parser, buf, recv_size);
/* recv_size is a ssize_t, so in range of size_t */
(*nut_ne_xml_parse)(parser, buf, (size_t)recv_size);
int parserFailed = (*nut_ne_xml_failed)(parser); /* 0 = ok, nonzero = fail */
(*nut_ne_xml_destroy)(parser);
nut_dev->driver = strdup("netxml-ups");
sprintf(buf,"http://%s",string);
nut_dev->port = strdup(buf);
current_nut_dev = nutscan_add_device_to_device(
current_nut_dev,nut_dev);
if (parserFailed == 0) {
nut_dev->driver = strdup("netxml-ups");
sprintf(buf, "http://%s", string);
nut_dev->port = strdup(buf);
upsdebugx(3,
"nutscan_scan_xml_http_generic(): "
"Adding configuration for driver='%s' port='%s'",
nut_dev->driver, nut_dev->port);
dev_ret = nutscan_add_device_to_device(
dev_ret, nut_dev);
#ifdef HAVE_PTHREAD
pthread_mutex_unlock(&dev_mutex);
#endif
}
else
{
fprintf(stderr,
"Device at IP %s replied with NetXML but was not deemed compatible "
"with 'netxml-ups' driver (unsupported protocol version, etc.)\n",
string);
nutscan_free_device(nut_dev);
nut_dev = NULL;
#ifdef HAVE_PTHREAD
pthread_mutex_unlock(&dev_mutex);
#endif
if (ip == NULL) {
/* skip this device; note that for a
* broadcast scan there may be more
* in the loop's queue */
continue;
}
}
if (ip != NULL) {
upsdebugx(2,
"nutscan_scan_xml_http_generic(): we collected one reply "
"to unicast for %s (repsponse from %s), done",
ip, string);
goto end;
}
} /* while select() responses */
if (ip == NULL && dev_ret != NULL) {
upsdebugx(2,
"nutscan_scan_xml_http_generic(): we collected one round of replies "
"to broadcast with no errors, done");
goto end;
}
}
}
else
{
fprintf(stderr,"Error creating socket\n");
}
upsdebugx(2,
"nutscan_scan_xml_http_generic(): no replies collected for %s, done",
(ip ? ip : "<broadcast>"));
goto end;
return nutscan_rewind_device(current_nut_dev);
}
#else /* WITH_NEON */
nutscan_device_t * nutscan_scan_xml_http(long usec_timeout)
{
end_abort:
upsdebugx(1,
"Had to abort nutscan_scan_xml_http_generic() for %s, see fatal details above",
(ip ? ip : "<broadcast>"));
end:
if (ip != NULL) /* do not free "ip", it comes from caller */
close(peerSocket);
return NULL;
}
nutscan_device_t * nutscan_scan_xml_http_range(const char * start_ip, const char * end_ip, 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;
if (!nutscan_avail_xml_http) {
return NULL;
}
if (start_ip == NULL && end_ip != NULL) {
start_ip = end_ip;
}
if (start_ip == NULL) {
upsdebugx(1, "Scanning XML/HTTP bus using broadcast.");
} else {
if ((start_ip == end_ip) || (end_ip == NULL) || (0 == strncmp(start_ip, end_ip, 128))) {
upsdebugx(1, "Scanning XML/HTTP bus for single IP (%s).", start_ip);
} else {
/* Iterate the range of IPs to scan */
nutscan_ip_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_netxml;
# endif
pthread_mutex_init(&dev_mutex, NULL);
# ifdef HAVE_SEMAPHORE
if (max_threads_scantype > 0) {
if (SIZE_MAX > UINT_MAX && max_threads_scantype > UINT_MAX) {
upsdebugx(1,
"WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()",
__func__);
max_threads_scantype = UINT_MAX - 1;
}
sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype);
}
# endif /* HAVE_SEMAPHORE */
#endif /* HAVE_PTHREAD */
ip_str = nutscan_ip_iter_init(&ip, start_ip, end_ip);
while (ip_str != NULL) {
#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 {
pass = ((max_threads_scantype == 0 || sem_trywait(semaphore_scantype) == 0) &&
sem_trywait(semaphore) == 0);
}
# 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 %zu scanning threads "
"(launched overall: %zu), "
"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 #%zu joined earlier?", __func__, i);
break;
case 0: /* thread exited */
if (curr_threads > 0) {
curr_threads --;
upsdebugx(4, "%s: Joined a finished thread #%zu", __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 #%zu 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 #%zu 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__);
}
/* 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_xml_t));
if (tmp_sec == NULL) {
fprintf(stderr,
"Memory allocation error\n");
return NULL;
}
memcpy(tmp_sec, sec, sizeof(nutscan_xml_t));
tmp_sec->peername = ip_str;
if (tmp_sec->usec_timeout <= 0) {
tmp_sec->usec_timeout = usec_timeout;
}
#ifdef HAVE_PTHREAD
if (pthread_create(&thread, NULL, nutscan_scan_xml_http_generic, (void *)tmp_sec) == 0) {
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
curr_threads++;
# endif /* HAVE_PTHREAD_TRYJOIN */
thread_count++;
nutscan_thread_t *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 /* not HAVE_PTHREAD */
nutscan_scan_xml_http_generic((void *)tmp_sec);
#endif /* if HAVE_PTHREAD */
/* free(ip_str); */ /* One of these free()s seems to cause a double-free instead */
ip_str = nutscan_ip_iter_inc(&ip);
/* free(tmp_sec); */
} 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, "
"waiting until older ones would finish",
__func__);
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 %zu 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 #%zu",
__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 */
}
free(thread_array);
upsdebugx(2, "%s: all threads freed", __func__);
}
pthread_mutex_destroy(&dev_mutex);
# ifdef HAVE_SEMAPHORE
if (max_threads_scantype > 0)
sem_destroy(semaphore_scantype);
# endif /* HAVE_SEMAPHORE */
#endif /* HAVE_PTHREAD */
result = nutscan_rewind_device(dev_ret);
dev_ret = NULL;
return result;
}
}
tmp_sec = malloc(sizeof(nutscan_xml_t));
if (tmp_sec == NULL) {
fprintf(stderr,
"Memory allocation error\n");
return NULL;
}
memcpy(tmp_sec, sec, sizeof(nutscan_xml_t));
if (start_ip == NULL) {
tmp_sec->peername = NULL;
} else {
tmp_sec->peername = strdup(start_ip);
}
if (tmp_sec->usec_timeout <= 0) {
tmp_sec->usec_timeout = usec_timeout;
}
nutscan_scan_xml_http_generic(tmp_sec);
result = nutscan_rewind_device(dev_ret);
dev_ret = NULL;
free(tmp_sec);
return result;
}
#else /* WITH_NEON */
nutscan_device_t * nutscan_scan_xml_http_range(const char * start_ip, const char * end_ip, useconds_t usec_timeout, nutscan_xml_t * sec)
{
NUT_UNUSED_VARIABLE(start_ip);
NUT_UNUSED_VARIABLE(end_ip);
NUT_UNUSED_VARIABLE(usec_timeout);
NUT_UNUSED_VARIABLE(sec);
return NULL;
}
#endif /* WITH_NEON */