diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3087cbeb6a..a381dad424 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,6 +13,11 @@ to look out for. PRs to update this template are also welcome :) * Local build iterations can be augmented with the ci_build.sh script. + Note that if your system has both GCC and CLANG, they can expose different + kinds of issues in their static analysis warnings, so incantations like + `CC=clang CXX=clang++ ./ci_build.sh` or `BUILD_TYPE=fightwarn ./ci_build.sh` + (to iterate a matrix of some build dependency combos and compilers) can + be useful. --> ## General points @@ -27,6 +32,12 @@ of "real" changes in the other commits. Similarly for typo fixes in comments or text documents. +- [ ] Use of coding helper tools and AI should be disclosed in the commit + or PR comments (it is interesting to know which ones do a decent job). + As with other contributions, a human is responsible and thanked for the + quality and content of the change, and is presumed to have the right to + post that code to be published further under the project's license terms. + - [ ] Please star NUT on GitHub, this helps with sponsorships! ;) ## Frequent "underwater rocks" for driver addition/update PRs @@ -92,6 +103,10 @@ Also note below, a point about PR posting for NUT DDL ## General documentation updates +- [ ] Added a bullet point into `NEWS.adoc`, possibly also `UPGRADING.adoc` + if there is something packagers or custom-build users should take into + account (new driver categories, configuration options, dependencies...) + - [ ] Updated `docs/acknowledgements.txt` (for vendor-backed device support) - [ ] Added or updated manual page information in `docs/man/*.txt` files diff --git a/.github/workflows/01-make-dist.yml b/.github/workflows/01-make-dist.yml index 5dad7a7122..863420c565 100644 --- a/.github/workflows/01-make-dist.yml +++ b/.github/workflows/01-make-dist.yml @@ -141,6 +141,7 @@ jobs: libfreeipmi-dev libipmimonitoring-dev \ libavahi-common-dev libavahi-core-dev libavahi-client-dev \ libgpiod-dev \ + libglib2.0-dev \ bash dash ksh busybox \ libneon27-gnutls-dev \ build-essential git-core libi2c-dev i2c-tools lm-sensors \ diff --git a/.github/workflows/05-codeql.yml b/.github/workflows/05-codeql.yml index 1bcb5d5f78..b9c5ffba73 100644 --- a/.github/workflows/05-codeql.yml +++ b/.github/workflows/05-codeql.yml @@ -88,7 +88,7 @@ jobs: sudo dpkg-reconfigure man-db sudo apt update case x"${{matrix.compiler}}" in x*clang*) sudo apt install clang ;; x*) sudo apt install gcc g++ ;; esac - sudo apt install libltdl-dev libtool libtool-bin cppcheck ccache libgd-dev libcppunit-dev libsystemd-dev libssl-dev libnss3-dev augeas-tools libaugeas-dev augeas-lenses libusb-dev libusb-1.0-0-dev libmodbus-dev libsnmp-dev libpowerman0-dev libfreeipmi-dev libipmimonitoring-dev libavahi-common-dev libavahi-core-dev libavahi-client-dev libgpiod-dev libneon27-dev libi2c-dev i2c-tools lm-sensors ccache + sudo apt install libltdl-dev libtool libtool-bin cppcheck ccache libgd-dev libcppunit-dev libsystemd-dev libssl-dev libnss3-dev augeas-tools libaugeas-dev augeas-lenses libusb-dev libusb-1.0-0-dev libmodbus-dev libsnmp-dev libpowerman0-dev libfreeipmi-dev libipmimonitoring-dev libavahi-common-dev libavahi-core-dev libavahi-client-dev libgpiod-dev libglib2.0-dev libneon27-dev libi2c-dev i2c-tools lm-sensors ccache date > .timestamp-init - name: Prepare ccache diff --git a/.github/workflows/08-PyNUTClient.yml b/.github/workflows/08-PyNUTClient.yml index 353394e9bd..541eed1d8a 100644 --- a/.github/workflows/08-PyNUTClient.yml +++ b/.github/workflows/08-PyNUTClient.yml @@ -61,8 +61,8 @@ jobs: run: >- set -e ; cd scripts/python/module ; - cp -f Makefile.am Makefile ; - make -f Makefile.am clean-local dist NUT_SOURCE_GITREV_NUMERIC="${{ steps.tag.outputs.TAG_NAME }}" PYTHON_DEFAULT="${{ steps.pythoncmd.outputs.PYTHON_DEFAULT }}" top_srcdir="../../.." srcdir="." builddir="." ; + sed 's,@dotMAKE@,,' < Makefile.am > Makefile ; + make -f Makefile clean-local dist NUT_SOURCE_GITREV_NUMERIC="${{ steps.tag.outputs.TAG_NAME }}" PYTHON_DEFAULT="${{ steps.pythoncmd.outputs.PYTHON_DEFAULT }}" top_srcdir="../../.." srcdir="." builddir="." ; find . -ls - name: Publish master distribution 📦 to Test PyPI # https://github.com/pypa/gh-action-pypi-publish diff --git a/.gitignore b/.gitignore index 2d32fbb90d..de8f6c43df 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ /_install_pkgprotodir/ Makefile Makefile.in +tags ## Parent directory only /aclocal.m4 diff --git a/Makefile.am b/Makefile.am index fef1bdb21e..44d2866857 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,7 +98,7 @@ SUBDIR_MAKE_VERBOSE = default # Run the standard build if going sequential (or with unknown MAKEFLAGS), # or fanout if parallel (presuming GNU/BSD/Sun make at least): -all-fanout-maybe: +all-fanout-maybe: @dotMAKE@ +@if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - NUT_MAKE_SKIP_FANOUT is set" ; \ @@ -130,7 +130,7 @@ all-fanout-maybe: # FIXME: Alas, we still tend to step on our toes when making everything at # once from scratch, so still do benefit from pre-making the libraries: -all-fanout-staged: +all-fanout-staged: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) NUT_VERSION_H_GENERATED=false all/include +$(MAKE) $(AM_MAKEFLAGS) NUT_VERSION_H_GENERATED=true all/common +$(MAKE) $(AM_MAKEFLAGS) NUT_VERSION_H_GENERATED=true all-fanout-libs @@ -140,7 +140,7 @@ all-fanout-subdirs: $(SUBDIRS_ALL_RECURSIVE) all-fanout-libs all-libs-local: $(SUBDIRS_ALL_LIBS_LOCAL) -#all all-am-local all-local: +#all all-am-local all-local: @dotMAKE@ # +@cd common && $(MAKE) $(AM_MAKEFLAGS) all # +@$(MAKE) $(AM_MAKEFLAGS) all-recursive # +@$(MAKE) $(AM_MAKEFLAGS) doc @@ -214,7 +214,7 @@ SUBDIR_TGT_RULE = ( \ # git grep -E '(LTLIBRARIES|\.la([ :'"`printf '\t'`"']|$))' '*.am' ### Delivers: nut_version.h -all-libs-local/include: +all-libs-local/include: @dotMAKE@ +@NUT_VERSION_H_GENERATED=false; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -225,7 +225,7 @@ all-libs-local/include: ### May deliver: libnutprivate-$(SEMVER)-common-all.la and libnutprivate-$(SEMVER)-common-client.la for dynamic shared-object linking, libcommonversion-private.la (dependency for the above) ### Requires-ext: include/nut_version.h ### Requires-int: libparseconf.la libcommonclient.la -all-libs-local/common: all-libs-local/include +all-libs-local/common: all-libs-local/include @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -237,7 +237,7 @@ all-libs-local/common: all-libs-local/include ### Requires-ext: common/libparseconf.la ### For dynamic builds, alternately LIB-Requires-ext and Requires-ext: libnutprivate-$(SEMVER)-common*.la ### Requires-int: libupsclient.la -all-libs-local/clients: all-libs-local/common +all-libs-local/clients: all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -250,7 +250,7 @@ all-libs-local/clients: all-libs-local/common ### Requires-int: libdummy_serial.la ### For dynamic builds, alternately LIB-Requires-ext and Requires-ext: libnutprivate-$(SEMVER)-common*.la ### and may deliver: libnutprivate-$(SEMVER)-drivers-common.la and libnutprivate-$(SEMVER)-drivers-serial.la -all-libs-local/drivers: all-libs-local/common +all-libs-local/drivers: all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -260,14 +260,14 @@ all-libs-local/drivers: all-libs-local/common ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la -all-libs-local/tests: all-libs-local/common +all-libs-local/tests: all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) ### Delivers: generated sources and/or headers for nut-scanner ### No dependencies: actually runs as part of autogen.sh but may be ### re-run during development when USB or SNMP driver sources change. -all-libs-local/tools: +all-libs-local/tools: @dotMAKE@ +@$(SUBDIR_TGT_RULE) ### Delivers: libnutscan.la @@ -282,7 +282,7 @@ all-libs-local/tools: ### Note: indirectly (ltdl) may use installed libupsclient.so ### however does directly use libupsclient-version.h ### for hints to find it at run-time -all-libs-local/tools/nut-scanner: all-libs-local/drivers all-libs-local/common all-libs-local/clients all-libs-local/tools +all-libs-local/tools/nut-scanner: all-libs-local/drivers all-libs-local/common all-libs-local/clients all-libs-local/tools @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -297,22 +297,22 @@ all/conf \ all/lib \ .ChangeLog.adoc-parsed.latest/docs \ ChangeLog.adoc-parsed/docs \ -all-recursive/data: +all-recursive/data: @dotMAKE@ +@$(SUBDIR_TGT_RULE) -all/include: all-libs-local/include +all/include: all-libs-local/include @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) -prep-src-docs/docs/man: +prep-src-docs/docs/man: @dotMAKE@ +@SUBDIR_TGT_MAKEFLAGS='MAINTAINER_DOCS_PREP_MAN_DELAY=3'; export SUBDIR_TGT_MAKEFLAGS; \ $(SUBDIR_TGT_RULE) -prep-src-docs/docs: +prep-src-docs/docs: @dotMAKE@ +@DOCS_NO_MAN=true; export DOCS_NO_MAN; \ $(SUBDIR_TGT_RULE) -all/docs/man: prep-src-docs/docs/man +all/docs/man: prep-src-docs/docs/man @dotMAKE@ +@$(SUBDIR_TGT_RULE) # Note: we optionally sort of depend on ChangeLog.adoc so it is pre-made and @@ -321,7 +321,7 @@ all/docs/man: prep-src-docs/docs/man # BUT we do not want to (re-)build ChangeLog if no (relevant) DOC_BUILD_LIST # types are enabled. MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY = 0 -all/docs: prep-src-docs/docs/man +all/docs: prep-src-docs/docs/man @dotMAKE@ +@case "@DOC_BUILD_LIST@" in \ *pdf*|*html-single*|*html-chunked*) \ echo " DOC-CHANGELOG-ASCIIDOC Pre-generate ChangeLog artifacts before the bulk of $@ ..." ; \ @@ -335,7 +335,7 @@ all/docs: prep-src-docs/docs/man +@$(MAKE) $(AM_MAKEFLAGS) prep-src-docs/docs +@DOCS_NO_MAN=true; export DOCS_NO_MAN; $(SUBDIR_TGT_RULE) -all-recursive/docs: all/docs all/docs/man +all-recursive/docs: all/docs all/docs/man @dotMAKE@ +@$(SUBDIR_TGT_RULE) # Dependencies below are dictated by who needs whose library from another dir @@ -346,7 +346,7 @@ all-recursive/docs: all/docs all/docs/man # that the top-level make completes needed (all-libs*) targets before drilling. ### Requires-int: libparseconf.la libcommonclient.la -all/common: all/include all-libs-local/common +all/common: all/include all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -355,7 +355,7 @@ all/common: all/include all-libs-local/common ### Requires-ext: common/libcommonversion.la ### Requires-ext: common/libcommonstrjson.la ### Requires-int: libupsclient.la -all/clients: all/common all-libs-local/clients +all/clients: all/common all-libs-local/clients @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -379,7 +379,7 @@ if SOME_DRIVERS # build whichever drivers are enabled (no idea if dummy-ups is # in the default list - FIXME: configure.ac could tell us, so # we could provide it for tests/NIT anyway...) -all/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers +all/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -392,21 +392,21 @@ else !SOME_DRIVERS # separate target with separate dependency trail, then "all-drivers" # should depend on both "dummy-ups" and the rest in so constrained # "all/drivers". This allows to ultimately not order one after another. -dummy-ups$(EXEEXT)/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers +dummy-ups$(EXEEXT)/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) -all/drivers: all/common all-libs-local/drivers +all/drivers: all/common all-libs-local/drivers @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ SUBDIR_TGT_MAKEFLAGS='NUTSW_DRIVERLIST_DUMMY_UPS=dummy'; export SUBDIR_TGT_MAKEFLAGS; \ $(SUBDIR_TGT_RULE) -all-drivers: dummy-ups$(EXEEXT)/drivers all/drivers +all-drivers: dummy-ups$(EXEEXT)/drivers all/drivers @dotMAKE@ endif !SOME_DRIVERS ### Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: common/libcommonversion.la -all/server: all-libs-local/common +all/server: all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -417,7 +417,7 @@ all/server: all-libs-local/common ### Requires-int: libnutscan.la all/tools/nut-scanner: all-libs-local/include all-libs-local/common \ all-libs-local/drivers all-libs-local/clients \ - all-libs-local/tools/nut-scanner + all-libs-local/tools/nut-scanner @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -426,11 +426,11 @@ all/tools/nut-scanner: all-libs-local/include all-libs-local/common \ ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: common/libcommonversion.la ### Requires-ext: tools/nut-scanner/libnutscan.la -all/tools/nutconf: all-libs-local/tools/nut-scanner all-libs-local/common +all/tools/nutconf: all-libs-local/tools/nut-scanner all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) -all-recursive/tools: all/tools/nutconf all/tools/nut-scanner +all-recursive/tools: all/tools/nutconf all/tools/nut-scanner @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -441,7 +441,7 @@ all-recursive/tools: all/tools/nutconf all/tools/nut-scanner # if it is not enabled among SOME_DRIVERS, things can get funny... # But then we should also consider what is enabled by configure and what is not. # Maybe we are doing a quick build not to be tested at all? :-/ -all/tests/NIT: all/clients all/server all-drivers all-recursive/tools all-recursive/data +all/tests/NIT: all/clients all/server all-drivers all-recursive/tools all-recursive/data @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -450,11 +450,11 @@ all/tests/NIT: all/clients all/server all-drivers all-recursive/tools all-recurs ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la -all/tests: all-libs-local/tests all-libs-local/drivers all-libs-local/common all-libs-local/clients +all/tests: all-libs-local/tests all-libs-local/drivers all-libs-local/common all-libs-local/clients @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) -all-recursive/tests: all/tests/NIT all/tests +all-recursive/tests: all/tests/NIT all/tests @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -462,16 +462,16 @@ if HAVE_MINGW_RESGEN if HAVE_WINDOWS ### Requires-ext: common/libcommon.la ### Requires-ext: common/libcommonversion.la -all/scripts/Windows: all-libs-local/common +all/scripts/Windows: all-libs-local/common @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) else !HAVE_WINDOWS -all/scripts/Windows: +all/scripts/Windows: @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) endif !HAVE_WINDOWS else !HAVE_MINGW_RESGEN -all/scripts/Windows: +all/scripts/Windows: @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) endif !HAVE_MINGW_RESGEN @@ -485,11 +485,11 @@ DMF_DEP_NUTSCAN = if WITH_REGENERATE_DMF_NUTSCAN DMF_DEP_NUTSCAN += all-libs-local/tools/nut-scanner endif WITH_REGENERATE_DMF_NUTSCAN -all/scripts/DMF: all-libs-local/drivers all-libs-local/common $(DMF_DEP_NUTSCAN) +all/scripts/DMF: all-libs-local/drivers all-libs-local/common $(DMF_DEP_NUTSCAN) @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) -all-recursive/scripts: all/scripts/Windows all/scripts/DMF +all-recursive/scripts: all/scripts/Windows all/scripts/DMF @dotMAKE@ +@NUT_VERSION_H_GENERATED=true; export NUT_VERSION_H_GENERATED; \ $(SUBDIR_TGT_RULE) @@ -580,7 +580,7 @@ endif !KNOWN_UNABLE_MANS # Helper for a number of recipes below that explicitly agree to not require # always real man pages (but require them to dist => distcheck-something) # for CI or developer iterations on environments with incomplete tool kits: -distcheck-light-DIST_ALL_PAGES: +distcheck-light-DIST_ALL_PAGES: @dotMAKE@ @echo "Starting $@" >&2 +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) all +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) distcheck-light-DIST_ALL_PAGES @@ -589,7 +589,7 @@ distcheck-light-DIST_ALL_PAGES: # In some recipes we `configure --with-docs=skip`, so "make dist" should not # hiccup on lack of the page files (nor try to make them); not using simple # distcheck-light-DIST_ALL_PAGES step due to custom logic! -distcheck-light-DIST_ALL_PAGES-docs-skipped: +distcheck-light-DIST_ALL_PAGES-docs-skipped: @dotMAKE@ @echo "Starting $@" >&2 +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) prep-src-docs +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) FAKE_PAGES_BUMP_SRC=false distcheck-light-DIST_ALL_PAGES @@ -598,7 +598,7 @@ distcheck-light-DIST_ALL_PAGES-docs-skipped: # Here we generate man pages (if absent) or fake them # Require other dependencies as usual distcheck does; # be sure to pass through caller's DISTCHECK_FLAGS (if any) -distcheck-fake-man: distcheck-light-DIST_ALL_PAGES +distcheck-fake-man: distcheck-light-DIST_ALL_PAGES @dotMAKE@ @echo "Starting $@" >&2 +prefix='$${prefix}'; if test x"$(DISTCHECK_FLAGS)" = x ; then \ $(MAKE) $(AM_MAKEFLAGS) distcheck ; \ @@ -607,7 +607,7 @@ distcheck-fake-man: distcheck-light-DIST_ALL_PAGES fi @echo "Completed $@: strict distcheck, but with possibly faked pre-built man pages" >&2 -dist-fake-man: distcheck-light-DIST_ALL_PAGES +dist-fake-man: distcheck-light-DIST_ALL_PAGES @dotMAKE@ @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) dist @echo "Completed $@: strict dist, but with possibly faked pre-built man pages" >&2 @@ -615,21 +615,21 @@ dist-fake-man: distcheck-light-DIST_ALL_PAGES # Here we allow to skip docs if tools are absent, so "make dist" # should not hiccup on lack of the page files (but MAY make them # if it can); be relaxed toward other dependencies. -distcheck-light: distcheck-light-DIST_ALL_PAGES +distcheck-light: distcheck-light-DIST_ALL_PAGES @dotMAKE@ @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with possibly faked pre-built man pages" >&2 # Require man pages to be built (or fail trying), but not other docs; # be relaxed toward other dependencies. -distcheck-light-man: +distcheck-light-man: @dotMAKE@ @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_MAN_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with real man pages" >&2 if HAVE_VALGRIND # Make the check in current build, if possible -memcheck: +memcheck: @dotMAKE@ @echo "Starting $@" >&2 @echo "See also scripts/valgrind in NUT sources for a helper tool" +@cd $(builddir)/tests && $(MAKE) $(AM_MAKEFLAGS) -s $@ @@ -638,7 +638,7 @@ memcheck: # Here we skip docs so "make dist" should not hiccup on lack of the page files # (nor try to make them); not using simple distcheck-light-DIST_ALL_PAGES step # due to custom logic! -distcheck-valgrind: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-valgrind: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ @echo "Starting $@" >&2 @echo "See also scripts/valgrind in NUT sources for a helper tool" +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_VALGRIND_FLAGS)" distcheck @@ -650,43 +650,43 @@ memcheck distcheck-valgrind: @echo " SKIP $@ : valgrind was not detected on this system by configure script" >&2 endif !HAVE_VALGRIND -distcheck-dmf-features-REGEN_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-REGEN_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_REGEN_NO_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_REGEN_NO_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-LTDL_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-LTDL_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_LTDL_YES_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_LTDL_YES_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-LTDL_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-LTDL_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_LTDL_NO_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_LTDL_NO_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-LUA_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-LUA_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_LUA_YES_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_LUA_YES_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-LUA_YESNO: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-LUA_YESNO: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_LUA_YESNO_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_LUA_YESNO_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-LUA_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-LUA_NO: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_LUA_NO_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_LUA_NO_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-features-REGEN_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features-REGEN_YES: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_WITH_REGEN_YES_FLAGS)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_WITH_REGEN_YES_FLAGS" >&2; exit $$RES; } echo "PASSED $@ suite!" # Intentionally done as one rule, to avoid parallelization and conflicts -distcheck-dmf-features: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-features: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-dmf-features-REGEN_NO +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-dmf-features-LTDL_YES +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-dmf-features-LTDL_NO @@ -698,21 +698,21 @@ distcheck-dmf-features: distcheck-light-DIST_ALL_PAGES-docs-skipped # Just test the common useful case of enabling (requiring) everything # related to DMF at once -distcheck-dmf-all-yes: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-all-yes: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_ALL)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_ALL" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-no: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-no: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" DISTCHECK_FLAGS="$(DISTCHECK_DMF_NO)" distcheck \ || { RES=$$? ; echo "FAILED with DISTCHECK_DMF_NO" >&2; exit $$RES; } echo "PASSED $@ suite!" -distcheck-dmf-warnings: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf-warnings: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS) --enable-Werror --enable-warnings" DISTCHECK_FLAGS="$(DISTCHECK_DMF_ALL)" distcheck echo "PASSED $@ suite!" -distcheck-dmf: distcheck-light-DIST_ALL_PAGES-docs-skipped +distcheck-dmf: distcheck-light-DIST_ALL_PAGES-docs-skipped @dotMAKE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-light-man +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-dmf-features +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_CONFIGURE_FLAGS="$(DISTCHECK_CONFIGURE_FLAGS)" distcheck-dmf-warnings @@ -720,7 +720,7 @@ distcheck-dmf: distcheck-light-DIST_ALL_PAGES-docs-skipped # Shortcut for DMF development - only checks its specifics after building NUT # The extent of actions and tests called below depends on project configuration -check-dmf: all +check-dmf: all @dotMAKE@ +cd $(top_srcdir)/scripts/DMF && $(MAKE) $(AM_MAKEFLAGS) check # workaround the dist generated files that are also part of the distribution @@ -768,7 +768,7 @@ maintainer-clean-local: # are included by generated Makefiles from other subdirectories, so they # should be available during their clean-up). Just in case, we make sure # here that their sub-distcleans complete first. -distclean-local: +distclean-local: @dotMAKE@ +@for DIR in $(SUBDIRS) ; do \ if test -f "$${DIR}/Makefile" ; then \ echo " DISTCLEAN in $${DIR}" >&2 ; \ @@ -808,10 +808,10 @@ SPELLCHECK_DIRS_LAST = spellcheck/tests/NIT SPELLCHECK_DIRS = $(SPELLCHECK_DIRS_MOST) $(SPELLCHECK_DIRS_LAST) -$(SPELLCHECK_DIRS_MOST): prep-src-docs/docs/man prep-src-docs/docs +$(SPELLCHECK_DIRS_MOST): prep-src-docs/docs/man prep-src-docs/docs @dotMAKE@ +@TGT="$(SPELLCHECK_TGT)"; export TGT; $(SUBDIR_TGT_RULE) -$(SPELLCHECK_DIRS_LAST): prep-src-docs/docs/man prep-src-docs/docs $(SPELLCHECK_DIRS_MOST) +$(SPELLCHECK_DIRS_LAST): prep-src-docs/docs/man prep-src-docs/docs $(SPELLCHECK_DIRS_MOST) @dotMAKE@ +@SUBDIR_TGT_MAKEFLAGS="SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes"; \ export SUBDIR_TGT_MAKEFLAGS; \ TGT="$(SPELLCHECK_TGT)"; export TGT; \ @@ -822,7 +822,7 @@ $(SPELLCHECK_DIRS_LAST): prep-src-docs/docs/man prep-src-docs/docs $(SPELLCHECK_ # but using the correct make target for this goal: # FIXME: fanned-out recipes tend to fail early despite "make -ks", so for # now we retry with a not-fanned-out attempt to cover most touch-files -spellcheck spellcheck-interactive: +spellcheck spellcheck-interactive: @dotMAKE@ +@SUBDIR_TGT_MAKEFLAGS="$${SUBDIR_TGT_MAKEFLAGS-} -k -s " ; export SUBDIR_TGT_MAKEFLAGS ; \ if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ RES=0 ; \ @@ -857,7 +857,7 @@ spellcheck spellcheck-interactive: # Auto-parallel recipe (if current 'make' implementation supports the "-j N" # syntax; the optional MAXPARMAKES may be set in NUT CI farm style builds): SET_PARMAKES_OPT = \ - +@PARMAKES_OPT=""; \ + PARMAKES_OPT=""; \ case " $(MAKEFLAGS) $(AM_MAKEFLAGS)" in \ *"j"*) ;; \ *) \ @@ -868,12 +868,12 @@ SET_PARMAKES_OPT = \ ;; \ esac -spellcheck-quick: +spellcheck-quick: @dotMAKE@ +@$(SET_PARMAKES_OPT); \ $(MAKE) $(AM_MAKEFLAGS) -k -s ${PARMAKES_OPT} spellcheck # Run auto-parallel recipe, and if something fails - re-run interactively: -spellcheck-interactive-quick: +spellcheck-interactive-quick: @dotMAKE@ +@$(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck-quick && exit ; \ echo "WARNING: in $@: make spellcheck-quick failed, retrying with spellcheck-interactive" >&2 ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" = xdefault ] ; then \ @@ -888,12 +888,12 @@ spellcheck-interactive-quick: # texts, man pages and HTML rendering of man pages, as enabled by tools. doc spellcheck-sortdict spellcheck-report-dict-usage \ all-docs check-docs \ -man all-man man-man check-man check-man-man html-man all-html: +man all-man man-man check-man check-man-man html-man all-html: @dotMAKE@ +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/.prep-src-docs +cd $(abs_top_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/man/.prep-src-docs +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) $@ -INSTALL.nut UPGRADING NEWS README: +INSTALL.nut UPGRADING NEWS README: @dotMAKE@ +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../$(@F).adoc-parsed && cp -f ../$(@F).adoc-parsed ../$(@F) # Workarounds for https://github.com/github/markup/issues/1095 @@ -956,7 +956,7 @@ maintainer-asciidocs: fi; \ ) -check-NIT check-NIT-devel check-NIT-sandbox check-NIT-sandbox-devel: +check-NIT check-NIT-devel check-NIT-sandbox check-NIT-sandbox-devel: @dotMAKE@ +cd $(builddir)/tests/NIT && $(MAKE) $(AM_MAKEFLAGS) $@ VERSION_DEFAULT: dummy-stamp @@ -1015,7 +1015,7 @@ shellcheck-disclaimer: # Note: currently not part of shellcheck target, because the script below # can test the logic with numerous SHELL_PROGS in a CI setting, and because # check-scripts-syntax probably has checked the basic syntax above already. -nut-driver-enumerator.sh/scripts/upsdrvsvcctl: +nut-driver-enumerator.sh/scripts/upsdrvsvcctl: @dotMAKE@ +@$(SUBDIR_TGT_RULE) shellcheck-nde: nut-driver-enumerator.sh/scripts/upsdrvsvcctl @@ -1057,7 +1057,7 @@ cppcheck: @echo "CPPCHECK analysis not available since 'cppcheck' was not found." endif !HAVE_CPPCHECK -sockdebug: +sockdebug: @dotMAKE@ +cd $(builddir)/server && $(MAKE) $(AM_MAKEFLAGS) sockdebug$(EXEEXT) # ---------------------------------------------------------------------- @@ -1081,7 +1081,7 @@ GITLOG_END_POINT=@GITLOG_END_POINT@ # the current dir, and defaults to generate a "ChangeLog" in the current dir. # The script itself is generated from a template, so resides in builddir. dummy-stamp: -ChangeLog: dummy-stamp +ChangeLog: dummy-stamp @dotMAKE@ +@$(MAKE) $(AM_MAKEFLAGS) $(abs_top_builddir)/ChangeLog if WITH_PDF_NONASCII_TITLES @@ -1150,21 +1150,21 @@ $(abs_top_builddir)/ChangeLog: tools/gitlog2changelog.py dummy-stamp fi ; \ fi -ChangeLog.adoc: ChangeLog +ChangeLog.adoc: ChangeLog @dotMAKE@ +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../ChangeLog.adoc -nut_version.h include/nut_version.h: +nut_version.h include/nut_version.h: @dotMAKE@ +cd $(abs_top_builddir)/include && $(MAKE) $(AM_MAKEFLAGS) nut_version.h # May involve (re-)build of libupsclient.la -libupsclient-version.h clients/libupsclient-version.h: +libupsclient-version.h clients/libupsclient-version.h: @dotMAKE@ +cd $(abs_top_builddir)/include && $(MAKE) $(AM_MAKEFLAGS) libupsclient-version.h -tools/gitlog2changelog.py: tools/gitlog2changelog.py.in +tools/gitlog2changelog.py: tools/gitlog2changelog.py.in @dotMAKE@ +cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) -s $(@F) # Partially snatched from automake generated code -distcheck-completeness: dist +distcheck-completeness: dist @dotMAKE@ @chmod -R +w $(distdir) $(distdir)-orig-* $(distdir)-derived-* || true @rm -rf $(distdir) $(distdir)-orig-* $(distdir)-derived-* || true @case '$(DIST_ARCHIVES)' in \ @@ -1293,12 +1293,12 @@ dist-docs: all-docs WARN="----------------------------------------------------------------------" -build: +build: @dotMAKE@ @echo $(WARN) @echo "Warning: 'make build' is deprecated. Use 'make all' instead." @echo $(WARN) +$(MAKE) $(AM_MAKEFLAGS) all -install-bin: +install-bin: @dotMAKE@ @echo $(WARN) @echo "Warning: 'make install-bin' is deprecated." @echo "Use 'make install-exec' instead for a similar effect." @@ -1307,20 +1307,20 @@ install-bin: +cd drivers; $(MAKE) $(AM_MAKEFLAGS) install +cd server; $(MAKE) $(AM_MAKEFLAGS) install +cd clients; $(MAKE) $(AM_MAKEFLAGS) install -install-man: install-data-recursive +install-man: install-data-recursive @dotMAKE@ @echo $(WARN) @echo "Warning: 'make install-man' is deprecated." @echo "Use 'cd docs/man; make install' instead." @echo $(WARN) +cd docs/man; $(MAKE) $(AM_MAKEFLAGS) install -install-conf: +install-conf: @dotMAKE@ @echo $(WARN) @echo "Warning: 'make install-conf' is deprecated." @echo "Use 'cd conf; make install' instead." @echo $(WARN) +cd conf; $(MAKE) $(AM_MAKEFLAGS) install # The target install-data already has a standardized meaning under automake -install-dirs: +install-dirs: @dotMAKE@ @echo $(WARN) @echo "Warning: 'make install-dirs' is deprecated." @echo "Use 'make installdirs' instead." @@ -1408,7 +1408,7 @@ endif !WITH_SOLARIS_INIT # using OS-specific `useradd`/`groupadd`, etc. # Note that as we stop services, we may be dealing with (older) # distros that do not follow current naming in NUT code base. -install-as-root: +install-as-root: @dotMAKE@ @+echo "$@: starting (no-op if not root)" >&2 ; \ case "$(target_os)" in *mingw*) echo "$@: SKIP: not supported for this target_os='$(target_os)'" >&2 ; exit 0;; esac ; \ if [ x"$(host_os)" != x"$(build_os)" ]; then echo "$@: SKIP: build_os='$(build_os)' is not host_os='$(host_os)'" >&2 ; exit 0 ; fi ; \ @@ -1581,7 +1581,7 @@ MAINTAINERCLEANFILES_PACKAGES += *.p5p MAINTAINERCLEANFILES += $(MAINTAINERCLEANFILES_DISTBALL) MAINTAINERCLEANFILES += $(MAINTAINERCLEANFILES_PACKAGES) -package: dist +package: all @dotMAKE@ +DESTDIR="$(abs_builddir)/_install_pkgprotodir" ; export DESTDIR; \ rm -rf "$$DESTDIR"; \ case "`uname -s`" in \ @@ -1621,12 +1621,12 @@ if HAVE_WINDOWS # some NUT build without drivers/tools/daemons). Subject to change if needed. # Currently this is handled by a CHECKING... step that should fail if it hits # anything. -install-win-bundle: all +install-win-bundle: all @dotMAKE@ @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install-win-bundle-thirdparty -install-win-bundle-thirdparty: +install-win-bundle-thirdparty: @dotMAKE@ @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi @echo "Searching which DLLs need to be bundled with NUT for Windows..." >&2 @if test -z "$$ARCH" ; then \ @@ -1762,7 +1762,7 @@ CHECK_PARALLEL_BUILDS_REGEN = true # the `./config.status` line -- and fails there. Hence the `cd top_builddir`. # Auto-parallel recipe (if current 'make' implementation supports the "-j N" # syntax; the optional MAXPARMAKES may be set in NUT CI farm style builds): -check-parallel-builds: +check-parallel-builds: @dotMAKE@ if [ x"$(CHECK_PARALLEL_BUILDS_REGEN)" = xtrue ] ; then cd '$(top_srcdir)' && $(AUTOMAKE) -f ; fi if [ x"$(CHECK_PARALLEL_BUILDS_REGEN)" = xtrue ] ; then cd '$(top_builddir)' && ./config.status ; fi +@$(SET_PARMAKES_OPT); \ diff --git a/NEWS.adoc b/NEWS.adoc index c30766204a..e18dc2bc09 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -12,7 +12,6 @@ For a complete and more detailed list of changes, please refer to the ChangeLog file (generated for release archives), or to the Git version control history for "live" codebase. - PLANNED: Release notes for NUT 2.8.5 - what's new since 2.8.4 ------------------------------------------------------------- @@ -67,6 +66,8 @@ https://github.com/networkupstools/nut/milestone/12 reality agrees with a status reported by device/protocol (if any). This is also a step in direction of eventually providing a common `runtimecal` style fallback to all drivers. [issue #3146, PR #3156] + * Generalize `elapsed_since_timeval()` code, originally repeated in + several modbus drivers. [issue #1938, PR #3321] * Introduced `NOTIFY_STATE_EXTEND_TIMEOUT` option and relevant variables for `upsnotify()` method, so we can tell systemd to not kill the service unit if its shutdown takes long (see also the `SHUTDOWNEXIT` option in @@ -83,6 +84,26 @@ https://github.com/networkupstools/nut/milestone/12 * Fixed thread-safety of IP address printout in `libupsclient` method `upscli_tryconnect()` (practical bug seen in `nut-scanner` parallel scans). [issue #3234] + * The `upsdrvquery` code base was revised to handle SIGPIPE without crashing + (if the consumers did not neuter the signal themselves), although this + behavior is optional by `upsdrvquery_NOSIGPIPE`. + Separated an `upsdrvquery_ping()` operation from earlier code, so it can + be directly used by consumers (in-tree this is drivers and `upsdrvctl`). + [issue #3276, PR #3277] + * Revised `void*` pointer casting into specific types for values returned + by `xmalloc()` and friends, or iterated in loops via `something->next`, + as `clang-21` now warns about not-casting void pointers (formally valid, + practically uncertain if that code matches the developer's intention), + and (better safe than sorry) added `NULL`-return checks although we should + not normally get into those code paths with the `x*()` methods which + should bail out and abort the program with a common error message when + an allocation fails. [#3293] + * We have long abstracted `(s)size_t` value printing in debug logs etc. + using `PRIuSIZE` and similar macros. They fell back to `"%zu"` when not + provided otherwise, but not all platforms actually deliver these format + characters. Now it is evaluated at `configure` time (to check that the + characters may be used), and if not -- during `nut_stdint.h` parsing to + fit known `int`/`long`/`long long` types. [#3300] - NUT for Windows specific updates: * Revised detection of (relative) paths to program and configuration files @@ -94,6 +115,11 @@ https://github.com/networkupstools/nut/milestone/12 operations. (Re-)registration of the "Network UPS Tools" service should now populate a nice description of it. The `-U` (uninstall) action should now also try to stop the service first. [PR #3235] + * Using `nut.exe -N` for testing and pressing 'Ctrl+C' should now cause the + started daemons to be killed off. Previously they would linger and e.g. + preclude subsequent experiments with the service wrapper. Console close + events are ignored, so there is a way to indefinitely keep the daemons + started by test-mode wrapper running (kill via Task Manager). [#3312] * Revised WIN32 `WSAStartup()` and registration of `atexit(WSACleanup)` to only be done once per program (and cleanups to be always registered); this impacts the C `libupsclient` and C++ `libnutclient` libraries (and so most @@ -127,12 +153,22 @@ https://github.com/networkupstools/nut/milestone/12 referenced by this table, so now several higher speeds would be compiled conditionally. [issue #3163] + - `nut-ipmipsu` driver updates: + * Fixed an issue where multiple calls to clean-up crashed the program. + Special thanks to maintainer of libfreeipmi for helping catch it. [#3193] + - `nutdrv_qx` driver updates: * Define an internal `QX_FLAG_MAPPING_HANDLED` to check if the subdriver code (mapping table) and the data found from device walk sit together well -- namely, that we successfully use reasonably many of the existing mappings. Suggest how user can help improve the driver if too few data points were seen. [PR #3095] + * The `qx_process_answer()` method was extended to raise `errno=ETIMEDOUT` + (rather than `EINVAL`) for short reads that are zero length (and/or that + `errno` value was set in caller's context already). This was used to make + `Voltronic` protocol initial connections more reliable when the device + controller lags upon first contact (is booting itself?) [issue #3276, + PR #3283] * New `nutdrv_qx_innovatae` adds support for Ippon INNOVA TAE series which are similar to Q1 except in reporting of nominal `voltage`, `current`, `frequency` data (that along with `battery_voltage_reports_one_pack` and @@ -182,6 +218,9 @@ https://github.com/networkupstools/nut/milestone/12 mappings. Suggest how user can help improve the driver if too few data points were seen, or if the `mibs=auto` detection only found the fallback IETF mapping. [PR #3095] + * Added new vendor extension mappings for Vertiv Liebert UPS, tested with + PSI5-750MT120 UPS model and IS-UNITY-DP (Firmware 8.4.7.0) SNMP card. + [issue #3296, PR #3299] - `tripplite_usb` driver updates: * Added support for Tripplite protocol 3017 (mostly ASCII). [issue #2258, @@ -189,6 +228,14 @@ https://github.com/networkupstools/nut/milestone/12 * Fixed default `unit_id`, apparently broken by changes in NUT v2.8.1. [issue #3191, PR #3192] + - `tripplitesu` driver updates: + * Added configurable command delay to prevent read timeouts. [PR #3273] + + - Introduced a new NUT driver named `nut-upower` which provides support + for monitoring UPS and battery devices managed by the UPower daemon + via D-Bus. This also introduces a new category of drivers that talk to + operating system services to obtain power state information. [PR #3279] + - `usbhid-ups` driver updates: * Declared support for APC with USB ID `051d:0005` (details may evolve as the devices become better known). [issue #3047, PR #3081] @@ -217,18 +264,30 @@ https://github.com/networkupstools/nut/milestone/12 fixed to use the same mapping helper as other subdrivers. [issue #3246] * `powercom-hid` subdriver improved with a `powercom_hack_voltage_lkp` to query `battery.voltage`. [issue #2766] + * `powercom-hid` subdriver now honours configured `offdelay` and `ondelay` + driver options in `ups.conf`, and prefers them (if present) over the + values received from the UPS itself (like `ups.delay.shutdown` and + `ups.delay.start`), to fix implementations of shutdown/stayoff/startup + instant commands. [PR #3288] * Improved handling of transient `LIBUSB_ERROR_IO` failures during polling. Some devices (CyberPower, etc.) have firmware bugs causing random I/O errors on certain HID reports. The driver now skips failing reports and continues polling rather than triggering expensive reconnection attempts. True disconnections are still detected via other error codes or when all polls fail. [issue #3116] + * `arduino-hid` subdriver enhanced with `ups.load`, `input.voltage` and + `output.voltage` readings where supported (e.g. Ugreen US3000). [#3281] - `nut-scanner` tool updates: * Fixed `nut-scanner` search for "simulation devices" to not use only the built-in NUT configuration path on all platforms, but to also consider `NUT_CONFPATH` and other fallback locations, like other code does. [PR #3249] + * Enhance debug-logging of dynamic library loading with information about + any missing method in the library discovered at run-time, if lack of such + prevents us from using that library, and blocks scanning of corresponding + protocol and/or media to discover possibly supported devices. [PR #3310] + * Introduced `nut-scanner` support for new `nut-upower` driver. [PR #3293] - `upsd` data server updates: * Sometimes "Data for UPS [X] is stale" and "UPS [X] data is no longer @@ -238,10 +297,22 @@ https://github.com/networkupstools/nut/milestone/12 comes into play and breaks things. [issue #661] * Fixed `LISTEN *` handling for `upsd.exe` in NUT for Windows builds. [PR #3237] + * Extended processing of `MAXCONN` setting to allow larger values than the + operating system allows, by only waiting for that amount of Unix sockets + or Windows `HANDLE`'s at a time, and moving on to another chunk. + The system-provided value can be further limited by `NUT_SYSMAXCONN_LIMIT` + environment variable (e.g. in tests). [#3302] - `upsdrvctl` tool updates: * Make use of `setproctag()` and `getproctag()` to report parent/child process names. [#3084] + * The global-level `debug_min` setting in `ups.conf` now also applies + to bumping the debug verbosity of `upsdrvctl` tool. [#3276] + * If we fail to stop a driver by signal (e.g. PID file was not saved), + retry to `INSTCMD driver.exit` it by socket protocol. [#3277] + * The NUT Integration Testing suite now also involves `upsdrvctl` to + run one driver instance indirectly, helping make check-NIT` catch + portability issues with different builds of the tool. [#2800, #3292] - `upslog` tool updates: * Updated `help()` and failure messages to suggest `-m '*,-'` for logging @@ -277,11 +348,16 @@ several `FSD` notifications into one executed action. [PR #3097] * Now has JSON output mode via `?json` (or `&json`) CGI query parameter. New `@TREELINK_JSON@` keyword added and HTML templates updated to expose these JSON documents when browsing. [issue #2524, PRs #3171, #3249] + * The `@STATUS@` directive now optionally supports separators (not only + the hard-coded `
` of the older versions. [issue #2525, PR #3318] * Handle `device.model` in addition to `ups.model` in upsstats HTML templates. [#3180] * Introduced a `@NUT_UPSSTATS_TEMPLATE@` command which the HTML template files now MUST start with (safety check that we are reading a template). [issue #3252, PR #3249] + * (Experimental) Custom templates other than `upsstats{,-single}.html` can + now be specified as CGI parameters, if locally permitted via `hosts.conf`. + [issue #2524, PR #3304] - `upssched` tool updates: * Previously in PR #2896 (NUT releases v2.8.3 and v2.8.4) the `UPSNAME` and @@ -379,11 +455,25 @@ several `FSD` notifications into one executed action. [PR #3097] installed on every system capable of using it; this is a niche capability for users of specific devices via a cloud portal. [follow-up to PR #2813 for issue #2807] + * Fixed `m4/ax_realpath_lib.m4` up with more ways to try and gauge the + build-time library name from linker/compiler, to improve the chances + that `nut-scanner` would find them. [#3293] + * Added an option to (primarily) `--disable-threading` for systems with + detected but broken `libpthread` support, or to test alternate code + paths during development or in CI. [#3300] - Recipes, CI and helper script updates not classified above: * Fixed CI recipes for PyPI publication of PyNUT(Client) module to also include the source distribution (was posted for NUT v2.8.1 and v2.8.2 tagged releases, but absent for v2.8.3 and v2.8.4). [#3056] + * A new version of BSD `make` in NetBSD 11 (Beta) aka `bmake` in some other + operating systems, complains about some of our sub-`$(MAKE)` calls despite + the explicit `+` prefix in corresponding lines, possibly because that call + happens not directly in a rule definition, but in a substituted shell code + snippet. The recommended workaround was to add a "Special Source" called + `.MAKE` to let the tool know that we expect sub-makes in that recipe. + However, *other* `make` implementations do not know about this token, + so its support is tried and detected at `configure` time. [PR #3300] * Updated `make spellcheck` to help avoid asciidoc admonition blocks with visually invalid sentences (after rendering as a box in HTML or PDF). [#3077] diff --git a/UPGRADING.adoc b/UPGRADING.adoc index fdfcdabd60..534bdf8e04 100644 --- a/UPGRADING.adoc +++ b/UPGRADING.adoc @@ -93,6 +93,12 @@ Changes from 2.8.4 to 2.8.5 of this new facility to keep working under both old and new file names. [#3101] +- The `upsdrvquery*` semi-internal API for talking on the driver socket was + updated with default handling for SIGPIPE. If your consumer wants to catch + it themselves, instead of using `errno=EPIPE` after a failed call, you can + use `upsdrvquery_NOSIGPIPE=0` to disable neutering of the signal inside + the API itself. [PR #3277] + - Fixed man page naming for `nutdrv_siemens-sitop(.8)` (dash vs. underscore) to match the driver program name. Packaging recipes may have to be updated. Follow-up from slightly botched renaming in original contribution. [PR #545] @@ -119,6 +125,15 @@ Changes from 2.8.4 to 2.8.5 updated, either to explicitly package the binding for several versions, or to not-deliver files no longer installed into the prototype area. [#1792] +- Added a `configure` script option to (primarily) `--disable-threading` + for systems with detected but broken `libpthread` support, which can + cause `nut-scanner` to crash while loading system libraries. [#3300] + +- Introduced a new driver category for interaction with OS-reported UPS + devices via D-Bus, with the `nut-upower` driver as the first implementation. + This driver requires `glib-2.0` and `gio-2.0` development libraries to be + available at build time. For packagers, this adds new dependencies if the + build should include this driver. [PR #3279] Changes from 2.8.3 to 2.8.4 --------------------------- diff --git a/clients/Makefile.am b/clients/Makefile.am index f9e4450fb8..f2ca5a3d27 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -23,7 +23,7 @@ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libcommonversion.la \ $(top_builddir)/common/libcommonstrjson.la \ -$(top_builddir)/common/libparseconf.la: dummy +$(top_builddir)/common/libparseconf.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Builds from root dir arrange stuff decently. Make sure parallel builds @@ -39,7 +39,7 @@ LDADD_CLIENT = if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h @@ -238,8 +238,16 @@ libnutclient_la_SOURCES = nutclient.h nutclient.cpp libnutclient_la_LDFLAGS = -version-info 2:2:0 # Needed in not-standalone builds with -DHAVE_NUTCOMMON=1 # which is defined for in-tree CXX builds above: +if ENABLE_SHARED_PRIVATE_LIBS +libnutclient_la_LIBADD = \ + $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la +if HAVE_WINDOWS + libnutclient_la_LIBADD += $(NETLIBS) +endif HAVE_WINDOWS +else !ENABLE_SHARED_PRIVATE_LIBS libnutclient_la_LIBADD = \ $(top_builddir)/common/libcommonclient.la +endif !ENABLE_SHARED_PRIVATE_LIBS if HAVE_WINDOWS # Many versions of MingW seem to fail to build non-static DLL without this libnutclient_la_LDFLAGS += -no-undefined diff --git a/clients/cgilib.c b/clients/cgilib.c index 687eed8c5b..044432c1b0 100644 --- a/clients/cgilib.c +++ b/clients/cgilib.c @@ -31,7 +31,10 @@ static char *unescape(char *buf) char ch, *newbuf, hex[8]; buflen = strlen(buf) + 2; - newbuf = xmalloc(buflen); + newbuf = (char *)xmalloc(buflen); + if (newbuf == NULL) { + return NULL; + } *newbuf = '\0'; fflush(stdout); @@ -84,8 +87,15 @@ void extractcgiargs(void) while (ptr) { varname = ptr; eq = strchr(varname, '='); - if (!eq) { - ptr = strchr(varname, '&'); + amp = strchr(varname, '&'); + if (!eq + || (eq && amp && amp < eq) + ) { + /* Last token is a flag (without assignment in sight), + * OR we've got a flag token in the middle of a query + * string, followed by another key=value pair later on. + */ + ptr = amp; if (ptr) *ptr++ = '\0'; @@ -96,6 +106,8 @@ void extractcgiargs(void) continue; } + /* The nearest point of interest is a key=value pair, + * maybe followed by another amp and flag or assignment... */ *eq = '\0'; value = eq + 1; amp = strchr(value, '&'); @@ -108,6 +120,8 @@ void extractcgiargs(void) cleanvar = unescape(varname); cleanval = unescape(value); + upsdebugx(3, "%s: parsearg('%s', '%s')
", + __func__, NUT_STRARG(cleanvar), NUT_STRARG(cleanval)); parsearg(cleanvar, cleanval); free(cleanvar); free(cleanval); diff --git a/clients/nutclientmem.cpp b/clients/nutclientmem.cpp index 45430b29cc..1b8492a06e 100644 --- a/clients/nutclientmem.cpp +++ b/clients/nutclientmem.cpp @@ -37,7 +37,10 @@ Device MemClientStub::getDevice(const std::string& name) std::set MemClientStub::getDeviceNames() { - throw NutException("Not implemented"); + volatile bool not_implemented = true; + if (not_implemented) + throw NutException("Not implemented"); + return std::set(); } std::string MemClientStub::getDeviceDescription(const std::string& name) @@ -176,7 +179,10 @@ TrackingID MemClientStub::executeDeviceCommand(const std::string& dev, const std std::map> MemClientStub::listDeviceClients(void) { - throw NutException("Not implemented"); + volatile bool not_implemented = true; + if (not_implemented) + throw NutException("Not implemented"); + return std::map>(); } std::set MemClientStub::deviceGetClients(const std::string& dev) diff --git a/clients/upsc.c b/clients/upsc.c index d8801f7496..f3736b8a4f 100644 --- a/clients/upsc.c +++ b/clients/upsc.c @@ -87,7 +87,7 @@ static void usage(const char *prog) printf("\nCommon arguments:\n"); printf(" -V - display the version of this software\n"); printf(" -W - network timeout for initial connections (default: %s)\n", - UPSCLI_DEFAULT_CONNECT_TIMEOUT); + UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf(" -h - display this help text\n"); nut_report_config_flags(); @@ -463,7 +463,7 @@ int main(int argc, char **argv) upsdebugx(1, "upsname='%s' hostname='%s' port='%" PRIu16 "'", NUT_STRARG(upsname), NUT_STRARG(hostname), port); - ups = xmalloc(sizeof(*ups)); + ups = (UPSCONN_t *)xmalloc(sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { fatalx_error_json_simple(0, upscli_strerror(ups)); diff --git a/clients/upsclient.c b/clients/upsclient.c index b72d1c36b7..63bbc7051e 100644 --- a/clients/upsclient.c +++ b/clients/upsclient.c @@ -501,7 +501,7 @@ int upscli_init(int certverify, const char *certpath, void upscli_add_host_cert(const char* hostname, const char* certname, int certverify, int forcessl) { #ifdef WITH_NSS - HOST_CERT_t* cert = xmalloc(sizeof(HOST_CERT_t)); + HOST_CERT_t* cert = (HOST_CERT_t *)xmalloc(sizeof(HOST_CERT_t)); cert->next = first_host_cert; cert->host = xstrdup(hostname); cert->certname = xstrdup(certname); @@ -1167,9 +1167,9 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags close(sock_fd); /* if timeout, break out so client can continue */ /* match Linux behavior that updates timeout struct */ - if (timeout != NULL && - ups->upserror == UPSCLI_ERR_CONNFAILURE && - ups->syserrno == ETIMEDOUT + if (timeout != NULL + && ups->upserror == UPSCLI_ERR_CONNFAILURE + && ups->syserrno == ETIMEDOUT ) { const char *addrstr = xinet_ntopAI(ai); upslogx(LOG_WARNING, "%s: Connection to host timed out: '%s'", @@ -1972,7 +1972,7 @@ int upscli_init_default_connect_timeout(const char *cli_secs, const char *config } upsdebugx(1, "%s: upscli_default_connect_timeout=%" PRIiMAX - ".%06" PRIiMAX " sec assigned from: %s", + ".%06" PRIiMAX " sec assigned from: %s", __func__, (intmax_t)upscli_default_connect_timeout.tv_sec, (intmax_t)upscli_default_connect_timeout.tv_usec, cause); diff --git a/clients/upscmd.c b/clients/upscmd.c index 47efe29161..561d7d5bb6 100644 --- a/clients/upscmd.c +++ b/clients/upscmd.c @@ -70,7 +70,7 @@ static void usage(const char *prog) printf("\nCommon arguments:\n"); printf(" -V - display the version of this software\n"); printf(" -W - network timeout for initial connections (default: %s)\n", - UPSCLI_DEFAULT_CONNECT_TIMEOUT); + UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf(" -h - display this help text\n"); nut_report_config_flags(); @@ -133,9 +133,9 @@ static void listcmds(void) } /* we must first read the entire list of commands, - before we can start reading the descriptions */ + * before we can start reading the descriptions */ - ltmp = xcalloc(1, sizeof(*ltmp)); + ltmp = (struct list_t *)xcalloc(1, sizeof(*ltmp)); ltmp->name = xstrdup(answer[2]); if (llast) { @@ -377,7 +377,7 @@ int main(int argc, char **argv) fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]"); } - ups = xcalloc(1, sizeof(*ups)); + ups = (UPSCONN_t *)xcalloc(1, sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); @@ -429,7 +429,7 @@ int main(int argc, char **argv) /* getpass leaks slightly - use -p when testing in valgrind */ if (!have_pw) { /* using getpass or getpass_r might not be a - good idea here (marked obsolete in POSIX) */ + * good idea here (marked obsolete in POSIX) */ char *pwtmp = GETPASS("Password: "); if (!pwtmp) { diff --git a/clients/upsimage.c b/clients/upsimage.c index 909841704f..18d7cf882b 100644 --- a/clients/upsimage.c +++ b/clients/upsimage.c @@ -20,6 +20,7 @@ Copyrights: (C) 1998 Russell Kroll (C) 2002 Simon Rozman + (C) 2020-2026 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -359,9 +360,9 @@ static void noimage(const char *fmt, ...) } /* draws bar indicator when minimum, nominal or maximum values for the given - UPS variable can be determined. - deviation < 0 means that values below nom should be grey instead of - green */ + * UPS variable can be determined. + * deviation < 0 means that values below nom should be grey instead of green + */ static void drawgeneralbar(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); @@ -388,7 +389,7 @@ static void drawgeneralbar(double var, int min, int nom, int max, max = nom + 3*deviation; } else { /* if nominal value isn't available, assume, it's the - average between min and max */ + * average between min and max */ nom = (min + max) / 2; } @@ -619,14 +620,14 @@ int main(int argc, char **argv) double var = 0; #ifdef WIN32 - /* Required ritual before calling any socket functions */ - static WSADATA WSAdata; - static int WSA_Started = 0; - if (!WSA_Started) { - WSAStartup(2, &WSAdata); - atexit((void(*)(void))WSACleanup); - WSA_Started = 1; - } + /* Required ritual before calling any socket functions */ + static WSADATA WSAdata; + static int WSA_Started = 0; + if (!WSA_Started) { + WSAStartup(2, &WSAdata); + atexit((void(*)(void))WSACleanup); + WSA_Started = 1; + } /* Avoid binary output conversions, e.g. * mangling what looks like CRLF on WIN32 */ @@ -646,6 +647,23 @@ int main(int argc, char **argv) nut_debug_level = i; } +#ifdef NUT_CGI_DEBUG_UPSIMAGE +# if (NUT_CGI_DEBUG_UPSIMAGE - 0 < 1) +# undef NUT_CGI_DEBUG_UPSIMAGE +# define NUT_CGI_DEBUG_UPSIMAGE 6 +# endif + /* Un-comment via make flags when developer-troubleshooting: */ + nut_debug_level = NUT_CGI_DEBUG_UPSIMAGE; +#endif + + if (nut_debug_level > 0) { + cgilogbit_set(); + printf("Content-type: text/html\n"); + printf("Pragma: no-cache\n"); + printf("\n"); + printf("

NUT CGI Debugging enabled, level: %d

\n\n", nut_debug_level); + } + extractcgiargs(); upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT); @@ -678,7 +696,7 @@ int main(int argc, char **argv) if (!strcmp(cmd, imgvar[i].name)) { /* sanity check whether we have draw function - registered with this variable */ + * registered with this variable */ if (!imgvar[i].drawfunc) { noimage("Draw function N/A"); #ifndef HAVE___ATTRIBUTE__NORETURN @@ -700,9 +718,10 @@ int main(int argc, char **argv) } /* when getting minimum, nominal and maximum values, - we first look if the marginal value is supported - by the UPS driver, if not, we look it up in the - imgarg table under the SAME name */ + * we first look if the marginal value is supported + * by the UPS driver, if not, we look it up in the + * imgarg table under the SAME name + */ /* get the minimum value */ if (imgvar[i].minimum) { diff --git a/clients/upsimagearg.h b/clients/upsimagearg.h index 7064b7f82a..9590ff38d0 100644 --- a/clients/upsimagearg.h +++ b/clients/upsimagearg.h @@ -59,8 +59,8 @@ static struct { typedef struct { char *name; /* name of the UPS variable */ - char *minimum; /* name of minimum value UPS variable - or variable in imgarg table */ + char *minimum; /* name of minimum value UPS variable */ + /* or variable in imgarg table */ char *nominal; /* as above, only for nominal value */ char *maximum; /* as above, only for maximum value */ int deviation; /* variable deviation - width of green zone */ diff --git a/clients/upslog.c b/clients/upslog.c index 16b5791cd4..c5c6a9a038 100644 --- a/clients/upslog.c +++ b/clients/upslog.c @@ -99,7 +99,7 @@ static struct logtarget_t *add_logfile(const char *logfn_arg) if (!logfn_arg || !(*logfn_arg)) return p; - p = xcalloc(1, sizeof(struct monhost_ups_t)); + p = (struct logtarget_t *)xcalloc(1, sizeof(struct logtarget_t)); p->logfn = xstrdup(logfn_arg); p->logfile = NULL; @@ -114,9 +114,10 @@ static void reopen_log(void) { struct logtarget_t *p; - for (p = logfile_anchor; - p != NULL; - p = p->next + for ( + p = logfile_anchor; + p != NULL; + p = p->next ) { /* Never opened, e.g. removed asterisk entry */ if (!p->logfile) @@ -128,8 +129,8 @@ static void reopen_log(void) } if ((p->logfile = freopen( - p->logfn, "a", - p->logfile)) == NULL + p->logfn, "a", + p->logfile)) == NULL ) { fatal_with_errno(EXIT_FAILURE, "could not reopen logfile %s", p->logfn); @@ -224,7 +225,7 @@ static void help(const char *prog) printf("\nCommon arguments:\n"); printf(" -V - display the version of this software\n"); printf(" -W - network timeout for initial connections (default: %s)\n", - UPSCLI_DEFAULT_CONNECT_TIMEOUT); + UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf(" -h - display this help text\n"); printf("\n"); printf("Some valid format string escapes:\n"); @@ -373,7 +374,7 @@ static void add_call(void (*fptr)(const char *arg, const struct monhost_ups_t *m tmp = tmp->next; } - tmp = xmalloc(sizeof(flist_t)); + tmp = (flist_t *)xmalloc(sizeof(flist_t)); tmp->fptr = fptr; @@ -542,7 +543,7 @@ int main(int argc, char **argv) char *m_arg, *s; monhost_ups_prev = monhost_ups_current; - monhost_ups_current = xmalloc(sizeof(struct monhost_ups_t)); + monhost_ups_current = (struct monhost_ups_t *)xmalloc(sizeof(struct monhost_ups_t)); if (monhost_ups_anchor == NULL) monhost_ups_anchor = monhost_ups_current; else @@ -684,7 +685,7 @@ int main(int argc, char **argv) if (argc >= 4) { /* read out the remaining argv entries to the format string */ - logformat = xmalloc(LARGEBUF); + logformat = (char *)xmalloc(LARGEBUF); memset(logformat, '\0', LARGEBUF); logformat_allocated = 1; @@ -702,7 +703,7 @@ int main(int argc, char **argv) /* May be or not be NULL here: */ monhost_ups_prev = monhost_ups_current; - monhost_ups_current = xmalloc(sizeof(struct monhost_ups_t)); + monhost_ups_current = (struct monhost_ups_t *)xmalloc(sizeof(struct monhost_ups_t)); if (monhost_ups_anchor == NULL) { /* Become the single-entry list */ monhost_ups_anchor = monhost_ups_current; @@ -730,7 +731,7 @@ int main(int argc, char **argv) char *s = xstrdup(logformat); if (s) { if (!logformat_allocated) { - logformat = xmalloc(LARGEBUF); + logformat = (char *)xmalloc(LARGEBUF); if (!logformat) fatalx(EXIT_FAILURE, "Failed re-allocation to prepend UPSHOST to formatting string"); memset(logformat, '\0', LARGEBUF); @@ -748,9 +749,10 @@ int main(int argc, char **argv) fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s -l , or use -m ; consider -m '*,-' to view updates of all known local devices"); /* Split the system specs in a common fashion for tuples and legacy args */ - for (monhost_ups_current = monhost_ups_anchor, monhost_ups_prev = NULL; - monhost_ups_current != NULL; - monhost_ups_current = monhost_ups_current->next + for ( + monhost_ups_current = monhost_ups_anchor, monhost_ups_prev = NULL; + monhost_ups_current != NULL; + monhost_ups_current = monhost_ups_current->next ) { if (upscli_splitname(monhost_ups_current->monhost, &(monhost_ups_current->upsname), &(monhost_ups_current->hostname), &(monhost_ups_current->port)) != 0) { fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]\n"); @@ -781,7 +783,7 @@ int main(int argc, char **argv) monhost_ups_current->port ); - conn = xmalloc(sizeof(*conn)); + conn = (UPSCONN_t *)xmalloc(sizeof(*conn)); if (upscli_connect(conn, monhost_ups_current->hostname, monhost_ups_current->port, UPSCLI_CONN_TRYSSL) < 0) { fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(conn)); @@ -809,7 +811,13 @@ int main(int argc, char **argv) found++; upsdebugx(1, "FOUND: %s: %s", answer[1], answer[2]); - mu = xmalloc(sizeof(struct monhost_ups_t)); + mu = (struct monhost_ups_t *)xmalloc(sizeof(struct monhost_ups_t)); + if (mu == NULL) { + upslogx(LOG_ERR, "Failed to get memory for monitoring host structure. Not adding %s@%s:%" PRIu16, + answer[1], monhost_ups_current->hostname, monhost_ups_current->port); + continue; + } + snprintf(buf, sizeof(buf), "%s@%s:%" PRIu16, answer[1], monhost_ups_current->hostname, @@ -880,9 +888,10 @@ int main(int argc, char **argv) fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s -l , or use -m ; consider -m '*,-' to view updates of all known local devices"); /* Report the logged systems, open the log files as needed */ - for (monhost_ups_current = monhost_ups_anchor; - monhost_ups_current != NULL; - monhost_ups_current = monhost_ups_current->next + for ( + monhost_ups_current = monhost_ups_anchor; + monhost_ups_current != NULL; + monhost_ups_current = monhost_ups_current->next ) { printf("logging status of %s to %s (%is intervals)\n", monhost_ups_current->monhost, @@ -894,7 +903,7 @@ int main(int argc, char **argv) fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]\n"); } - monhost_ups_current->ups = xmalloc(sizeof(UPSCONN_t)); + monhost_ups_current->ups = (UPSCONN_t *)xmalloc(sizeof(UPSCONN_t)); if (upscli_connect(monhost_ups_current->ups, monhost_ups_current->hostname, monhost_ups_current->port, UPSCLI_CONN_TRYSSL) < 0) fprintf(stderr, "Warning: initial connect failed: %s\n", @@ -969,9 +978,10 @@ int main(int argc, char **argv) upsnotify(NOTIFY_STATE_READY, NULL); } - for (monhost_ups_current = monhost_ups_anchor; - monhost_ups_current != NULL; - monhost_ups_current = monhost_ups_current->next + for ( + monhost_ups_current = monhost_ups_anchor; + monhost_ups_current != NULL; + monhost_ups_current = monhost_ups_current->next ) { /* reconnect if necessary */ if (upscli_fd(monhost_ups_current->ups) < 0) { @@ -1003,9 +1013,10 @@ int main(int argc, char **argv) upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); upsnotify(NOTIFY_STATE_STOPPING, "Signal %d: exiting", exit_flag); - for (monhost_ups_current = monhost_ups_anchor; - monhost_ups_current != NULL; - monhost_ups_current = monhost_ups_current->next + for ( + monhost_ups_current = monhost_ups_anchor; + monhost_ups_current != NULL; + monhost_ups_current = monhost_ups_current->next ) { /* we might have several systems logged into same file; * take care to not close stdout though */ diff --git a/clients/upsmon.c b/clients/upsmon.c index c349b193b5..1e29250ce9 100644 --- a/clients/upsmon.c +++ b/clients/upsmon.c @@ -236,8 +236,9 @@ static void wall(const char *text) char *command; /* first +1 is for the space between message and text - second +1 is for trailing 0 - +2 is for "" */ + * second +1 is for trailing 0 + * +2 is for "" + */ size_t commandsz = strlen(MESSAGE_CMD) + 1 + 2 + strlen(text) + 1; command = malloc (commandsz); @@ -1103,7 +1104,7 @@ static void doshutdown(void) /* Contact the data server(s) regularly so this * client is not assumed dead while looping */ - for (ups = firstups; ups != NULL && !exit_flag; ups = ups->next) { + for (ups = firstups; ups != NULL && !exit_flag; ups = (utype_t *)ups->next) { set_alarm(); if (get_var(ups, "numlogins", temp, sizeof(temp)) >= 0) { @@ -1336,7 +1337,7 @@ static void sync_secondaries(void) upsnotify(NOTIFY_STATE_WATCHDOG, NULL); - for (ups = firstups; ups != NULL; ups = ups->next) { + for (ups = firstups; ups != NULL; ups = (utype_t *)ups->next) { /* only check login count on devices we are the primary for */ if (!flag_isset(ups->status, ST_PRIMARY)) @@ -1403,7 +1404,7 @@ static void forceshutdown(void) userfsd, exit_flag, use_pipe); /* set FSD on any "primary" UPS entries (forced shutdown in progress) */ - for (ups = firstups; ups != NULL; ups = ups->next) + for (ups = firstups; ups != NULL; ups = (utype_t *)ups->next) if (flag_isset(ups->status, ST_PRIMARY)) { isaprimary = 1; upsdebugx(2, "%s: tell data server to setfsd(%s@%s)", @@ -1593,7 +1594,7 @@ static int is_ups_critical(utype_t *ups) if (flag_isset(ups->status, ST_CAL)) { upslogx(LOG_WARNING, "%s: seems that UPS [%s] is OB+LB now, but " "it is also calibrating - not declaring a critical state", - __func__, ups->upsname); + __func__, ups->upsname); return 0; } @@ -1722,7 +1723,7 @@ static void recalc(void) else val_ol += ups->pv; - ups = ups->next; + ups = (utype_t *)ups->next; } upsdebugx(3, "Current power value: %u", val_ol); @@ -2129,10 +2130,10 @@ static void addups(int reloading, const char *sys, const char *pvs, return; } - tmp = tmp->next; + tmp = (utype_t *)tmp->next; } - tmp = xcalloc(1, sizeof(utype_t)); + tmp = (utype_t *)xcalloc(1, sizeof(utype_t)); /* TOTHINK: init (UPSCONN_t)tmp->conn struct fields too? */ tmp->sys = xstrdup(sys); tmp->pv = pv; @@ -2619,7 +2620,7 @@ static void loadconfig(void) while (ups) { ups->pollfail_log_throttle_count = -1; ups->pollfail_log_throttle_state = UPSCLI_ERR_NONE; - ups = ups->next; + ups = (utype_t *)ups->next; } } } @@ -2739,7 +2740,7 @@ static void upsmon_cleanup(void) utmp = firstups; while (utmp) { - unext = utmp->next; + unext = (utype_t *)utmp->next; drop_connection(utmp); ups_free(utmp); @@ -3441,7 +3442,7 @@ static void help(const char *arg_progname) printf("\nCommon arguments:\n"); printf(" -V - display the version of this software\n"); printf(" -W - network timeout for initial connections (default: %s)\n", - UPSCLI_DEFAULT_CONNECT_TIMEOUT); + UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf(" -h - display this help text\n"); nut_report_config_flags(); @@ -3624,7 +3625,7 @@ static void delete_ups(utype_t *target) /* about to delete the first ups? */ if (ptr == last) - firstups = ptr->next; + firstups = (utype_t *)ptr->next; else last->next = ptr->next; @@ -3636,7 +3637,7 @@ static void delete_ups(utype_t *target) } last = ptr; - ptr = ptr->next; + ptr = (utype_t *)ptr->next; } /* shouldn't happen */ @@ -3676,7 +3677,7 @@ static void reload_conf(void) while (tmp) { tmp->retain = 0; - tmp = tmp->next; + tmp = (utype_t *)tmp->next; } /* reset paranoia checker */ @@ -3687,9 +3688,8 @@ static void reload_conf(void) /* go through the utype_t struct again */ tmp = firstups; - while (tmp) { - next = tmp->next; + next = (utype_t *)tmp->next; /* !retain means it wasn't in the .conf this time around */ if (tmp->retain == 0) @@ -3815,9 +3815,9 @@ int main(int argc, char *argv[]) print_banner_once(prog, 0); /* if no configuration file is specified on the command line, use default */ - configfile = xmalloc(SMALLBUF); + configfile = (char *)xmalloc(SMALLBUF); snprintf(configfile, SMALLBUF, "%s/upsmon.conf", confpath()); - configfile = xrealloc(configfile, strlen(configfile) + 1); + configfile = (char *)xrealloc(configfile, strlen(configfile) + 1); run_as_user = xstrdup(RUN_AS_USER); @@ -4257,7 +4257,7 @@ int main(int argc, char *argv[]) gettimeofday(&now, NULL); time(&ttNow); - for (ups = firstups; ups != NULL; ups = ups->next) { + for (ups = firstups; ups != NULL; ups = (utype_t *)ups->next) { ups->status = 0; ups->lastpoll = ttNow; } @@ -4279,7 +4279,7 @@ int main(int argc, char *argv[]) /* Reset the value, regardless of support */ sleep_inhibitor_status = -2; - for (ups = firstups; ups != NULL; ups = ups->next) { + for (ups = firstups; ups != NULL; ups = (utype_t *)ups->next) { if (isPreparingForSleepSupported() && (sleep_inhibitor_status = isPreparingForSleep()) >= 0) { upsdebugx(2, "Aborting UPS polling sub-loop because OS is preparing for sleep or just woke up"); goto end_loop_cycle; diff --git a/clients/upsrw.c b/clients/upsrw.c index 79c6ffa87e..797445eeee 100644 --- a/clients/upsrw.c +++ b/clients/upsrw.c @@ -69,7 +69,7 @@ static void usage(const char *prog) printf("\nCommon arguments:\n"); printf(" -V - display the version of this software\n"); printf(" -W - network timeout for initial connections (default: %s)\n", - UPSCLI_DEFAULT_CONNECT_TIMEOUT); + UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf(" -h - display this help text\n"); printf("\n"); printf("Call without -s to show all possible read/write variables (same as -l).\n"); @@ -617,7 +617,7 @@ static void print_rwlist(void) /* sock this entry away for later */ - ltmp = xmalloc(sizeof(struct list_t)); + ltmp = (struct list_t *)xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; @@ -731,7 +731,7 @@ int main(int argc, char **argv) fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]"); } - ups = xcalloc(1, sizeof(*ups)); + ups = (UPSCONN_t *)xcalloc(1, sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); diff --git a/clients/upssched.c b/clients/upssched.c index fe8f914a12..b201d82c1d 100644 --- a/clients/upssched.c +++ b/clients/upssched.c @@ -151,7 +151,7 @@ static char* collect_string(char **string_arr, char *logtag, char *sep, size_t * if (!string_arr || !(*string_arr) || !(**string_arr)) return NULL; - buf = xcalloc(bufsize, sizeof(char)); + buf = (char *)xcalloc(bufsize, sizeof(char)); if (!buf) { upsdebugx(1, "%s: failed to allocate buffer, will not report any %s values", __func__, logtag); return NULL; @@ -187,7 +187,7 @@ static char* collect_string(char **string_arr, char *logtag, char *sep, size_t * if (bufsize < SIZE_MAX - LARGEBUF) { bufsize += LARGEBUF; upsdebugx(1, "%s: buffer overflowed, trying to re-allocate as %" PRIuSIZE, __func__, bufsize); - buf = realloc(buf, bufsize); + buf = (char *)realloc(buf, bufsize); if (!buf) { upsdebugx(1, "%s: buffer overflowed and failed to re-allocate, will not report any %s values", __func__, logtag); @@ -435,12 +435,12 @@ static void start_timer(const char *name, const char *ofsstr, const char *notify } if (*ps == NULL) { - tmp->notifytypes = xrealloc(tmp->notifytypes, count + 2); + tmp->notifytypes = (char **)xrealloc(tmp->notifytypes, count + 2); tmp->notifytypes[count] = xstrdup(notifytype); tmp->notifytypes[count + 1] = NULL; } } else { - tmp->notifytypes = xcalloc(2, sizeof(char*)); + tmp->notifytypes = (char **)xcalloc(2, sizeof(char*)); tmp->notifytypes[0] = xstrdup(notifytype); tmp->notifytypes[1] = NULL; } @@ -458,12 +458,12 @@ static void start_timer(const char *name, const char *ofsstr, const char *notify } if (*ps == NULL) { - tmp->notifymsgs = xrealloc(tmp->notifymsgs, count + 2); + tmp->notifymsgs = (char **)xrealloc(tmp->notifymsgs, count + 2); tmp->notifymsgs[count] = xstrdup(notifymsg); tmp->notifymsgs[count + 1] = NULL; } } else { - tmp->notifymsgs = xcalloc(2, sizeof(char*)); + tmp->notifymsgs = (char **)xcalloc(2, sizeof(char*)); tmp->notifymsgs[0] = xstrdup(notifymsg); tmp->notifymsgs[1] = NULL; } @@ -481,12 +481,12 @@ static void start_timer(const char *name, const char *ofsstr, const char *notify } if (*ps == NULL) { - tmp->upsnames = xrealloc(tmp->upsnames, count + 2); + tmp->upsnames = (char **)xrealloc(tmp->upsnames, count + 2); tmp->upsnames[count] = xstrdup(upsname); tmp->upsnames[count + 1] = NULL; } } else { - tmp->upsnames = xcalloc(2, sizeof(char*)); + tmp->upsnames = (char **)xcalloc(2, sizeof(char*)); tmp->upsnames[0] = xstrdup(upsname); tmp->upsnames[1] = NULL; } @@ -515,7 +515,7 @@ static void start_timer(const char *name, const char *ofsstr, const char *notify } } /* else we already know */ - tmp = xmalloc(sizeof(ttype_t)); + tmp = (ttype_t *)xmalloc(sizeof(ttype_t)); tmp->name = xstrdup(name); tmp->etime = now + ofs; tmp->notifytypes = NULL; @@ -524,19 +524,19 @@ static void start_timer(const char *name, const char *ofsstr, const char *notify tmp->next = NULL; if (notifytype && *notifytype) { - tmp->notifytypes = xcalloc(2, sizeof(char*)); + tmp->notifytypes = (char **)xcalloc(2, sizeof(char*)); tmp->notifytypes[0] = xstrdup(notifytype); tmp->notifytypes[1] = NULL; } if (notifymsg && *notifymsg) { - tmp->notifymsgs = xcalloc(2, sizeof(char*)); + tmp->notifymsgs = (char **)xcalloc(2, sizeof(char*)); tmp->notifymsgs[0] = xstrdup(notifymsg); tmp->notifymsgs[1] = NULL; } if (upsname && *upsname) { - tmp->upsnames = xcalloc(2, sizeof(char*)); + tmp->upsnames = (char **)xcalloc(2, sizeof(char*)); tmp->upsnames[0] = xstrdup(upsname); tmp->upsnames[1] = NULL; } @@ -927,7 +927,7 @@ static TYPE_FD conn_add(TYPE_FD sockfd) tmp = tmp->next; } - tmp = xmalloc(sizeof(conn_t)); + tmp = (conn_t *)xmalloc(sizeof(conn_t)); tmp->fd = acc; tmp->next = NULL; @@ -945,7 +945,7 @@ static TYPE_FD conn_add(TYPE_FD sockfd) conn_t *conn, *tmp, *last; /* We have detected a connection on the opened pipe. So we start - by saving its handle and create a new pipe for future connection */ + * by saving its handle and creating a new pipe for future connection */ conn = xcalloc(1, sizeof(*conn)); conn->fd = sockfd; @@ -983,9 +983,11 @@ static TYPE_FD conn_add(TYPE_FD sockfd) ConnectNamedPipe(acc,&connect_overlapped); /* A new pipe waiting for new client connection has been created. - We could manage the current connection now */ - /* Start a read operation on the newly connected pipe so we could wait - on the event associated to this IO */ + * We could manage the current connection now. + */ + + /* Start a read operation on the newly connected pipe so we could + * wait on the event associated to this IO */ memset(&conn->read_overlapped,0,sizeof(conn->read_overlapped)); memset(conn->buf,0,sizeof(conn->buf)); conn->read_overlapped.hEvent = CreateEvent(NULL, /*Security*/ diff --git a/clients/upsset.c b/clients/upsset.c index 03e10b504f..3074bf63ef 100644 --- a/clients/upsset.c +++ b/clients/upsset.c @@ -1,6 +1,7 @@ /* upsset - CGI program to manage read/write variables Copyright (C) 1999 Russell Kroll + Copyright (C) 2020-2026 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,6 +71,11 @@ void parsearg(char *var, char *value) uvtype_t *last, *tmp = NULL; static int upsvc = 0; + if (var == NULL || value == NULL) { + upslogx(LOG_ERR, "parsearg() called with var null or value null"); + return; + } + /* store variables from a SET command for the later commit */ if (!strncmp(var, "UPSVAR_", 7)) { @@ -91,10 +97,10 @@ void parsearg(char *var, char *value) tmp = last = firstuv; while (tmp) { last = tmp; - tmp = tmp->next; + tmp = (uvtype_t *)tmp->next; } - tmp = xmalloc(sizeof(uvtype_t)); + tmp = (uvtype_t *)xmalloc(sizeof(uvtype_t)); tmp->var = xstrdup(ptr); tmp->value = xstrdup(value); tmp->next = NULL; @@ -437,7 +443,7 @@ static void showcmds(void) return; } - ltmp = xmalloc(sizeof(struct list_t)); + ltmp = (struct list_t *)xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; @@ -789,8 +795,9 @@ static void do_type(const char *varname) } /* RANGE is usually paired with NUMBER. - We can ignore 'RANGE' and let the 'NUMBER' - case (which should come next) handle it. */ + * We can ignore 'RANGE' and let the 'NUMBER' + * case (which should come next) handle it. + */ if (!strcasecmp(answer[i], "RANGE")) { continue; } @@ -870,7 +877,7 @@ static void showsettings(void) /* sock this entry away for later */ - ltmp = xmalloc(sizeof(struct list_t)); + ltmp = (struct list_t *)xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; @@ -1001,7 +1008,7 @@ static void savesettings(void) while (upsvar) { changed += setvar(upsvar->var, upsvar->value); - upsvar = upsvar->next; + upsvar = (uvtype_t *)upsvar->next; } if (changed == 0) @@ -1110,14 +1117,14 @@ int main(int argc, char **argv) int i; #ifdef WIN32 - /* Required ritual before calling any socket functions */ - static WSADATA WSAdata; - static int WSA_Started = 0; - if (!WSA_Started) { - WSAStartup(2, &WSAdata); - atexit((void(*)(void))WSACleanup); - WSA_Started = 1; - } + /* Required ritual before calling any socket functions */ + static WSADATA WSAdata; + static int WSA_Started = 0; + if (!WSA_Started) { + WSAStartup(2, &WSAdata); + atexit((void(*)(void))WSACleanup); + WSA_Started = 1; + } /* Avoid binary output conversions, e.g. * mangling what looks like CRLF on WIN32 */ @@ -1130,7 +1137,9 @@ int main(int argc, char **argv) NUT_UNUSED_VARIABLE(argv); username = password = function = monups = NULL; - printf("Content-type: text/html\n\n"); + printf("Content-type: text/html\n"); + printf("Pragma: no-cache\n"); + printf("\n"); /* NOTE: Caller must `export NUT_DEBUG_LEVEL` to see debugs for upsc * and NUT methods called from it. This line aims to just initialize @@ -1142,6 +1151,20 @@ int main(int argc, char **argv) nut_debug_level = i; } +#ifdef NUT_CGI_DEBUG_UPSSET +# if (NUT_CGI_DEBUG_UPSSET - 0 < 1) +# undef NUT_CGI_DEBUG_UPSSET +# define NUT_CGI_DEBUG_UPSSET 6 +# endif + /* Un-comment via make flags when developer-troubleshooting: */ + nut_debug_level = NUT_CGI_DEBUG_UPSSET; +#endif + + if (nut_debug_level > 0) { + cgilogbit_set(); + printf("

NUT CGI Debugging enabled, level: %d

\n\n", nut_debug_level); + } + /* see if the magic string is present in the config file */ check_conf(); diff --git a/clients/upsstats.c b/clients/upsstats.c index 4ec650c451..04c74c70e5 100644 --- a/clients/upsstats.c +++ b/clients/upsstats.c @@ -2,6 +2,7 @@ Copyright (C) 1998 Russell Kroll Copyright (C) 2005 Arnaud Quette + Copyright (C) 2020-2026 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -62,13 +63,18 @@ static char *monhostdesc = NULL; static uint16_t port; static char *upsname, *hostname; -static char *upsimgpath="upsimage.cgi" EXEEXT, *upsstatpath="upsstats.cgi" EXEEXT; +static char *upsimgpath = "upsimage.cgi" EXEEXT, *upsstatpath = "upsstats.cgi" EXEEXT, + *template_single = NULL, *template_list = NULL; static UPSCONN_t ups; static FILE *tf; static long forofs = 0; -static ulist_t *ulhead = NULL, *currups = NULL; +static ulist_t *ulhead = NULL, *currups = NULL, + /* hijack the linked-list structure to store + * just filenames (as "sys") so far */ + *allowed_template_single_lhead = NULL, + *allowed_template_list_lhead = NULL; static int skip_clause = 0, skip_block = 0; @@ -99,6 +105,18 @@ void parsearg(char *var, char *value) output_json = 1; } + if (!strcmp(var, "template_single")) { + /* Error-checking in display_template(), when we have all options in place */ + free(template_single); + template_single = xstrdup(value); + } + + if (!strcmp(var, "template_list")) { + /* Error-checking in display_template(), when we have all options in place */ + free(template_list); + template_list = xstrdup(value); + } + upsdebug_call_finished0(); } @@ -209,9 +227,9 @@ static void parse_var(const char *var) upsdebug_call_finished0(); } -static void do_status(void) +static void do_status(const char *sep) { - int i; + int i, count = 0; char status[SMALLBUF], *ptr, *last = NULL; upsdebug_call_starting0(); @@ -226,7 +244,9 @@ static void do_status(void) for (i = 0; stattab[i].name != NULL; i++) { if (!strcasecmp(ptr, stattab[i].name)) { - printf("%s
", stattab[i].desc); + /* Note: sep="\0" is a valid case so we do not check for *sep */ + printf("%s%s", count ? (sep ? sep : "
") : "", stattab[i].desc); + count++; } } } @@ -526,6 +546,14 @@ static void do_hostlink(void) printf("sys); + if (template_single && strcmp(template_single, "upsstats-single.html")) { + printf("&template_single=%s", template_single); + } + + if (template_list && strcmp(template_list, "upsstats.html")) { + printf("&template_list=%s", template_list); + } + if (refreshdelay > 0) { printf("&refresh=%d", refreshdelay); } @@ -543,8 +571,22 @@ static void do_treelink_json(const char *text) return; } - printf("%s", - upsstatpath, currups->sys, + printf("sys); + + if (template_single && strcmp(template_single, "upsstats-single.html")) { + printf("&template_single=%s", template_single); + } + + if (template_list && strcmp(template_list, "upsstats.html")) { + printf("&template_list=%s", template_list); + } + + if (refreshdelay > 0) { + printf("&refresh=%d", refreshdelay); + } + + printf("\">%s", ((text && *text) ? text : "JSON")); upsdebug_call_finished0(); @@ -559,8 +601,22 @@ static void do_treelink(const char *text) return; } - printf("%s", - upsstatpath, currups->sys, + printf("sys); + + if (template_single && strcmp(template_single, "upsstats-single.html")) { + printf("&template_single=%s", template_single); + } + + if (template_list && strcmp(template_list, "upsstats.html")) { + printf("&template_list=%s", template_list); + } + + if (refreshdelay > 0) { + printf("&refresh=%d", refreshdelay); + } + + printf("\">%s", ((text && *text) ? text : "All data")); upsdebug_call_finished0(); @@ -872,8 +928,14 @@ static int do_command(char *cmd) return 1; } + if (!strncmp(cmd, "STATUS ", 7)) { + do_status(&cmd[7]); + upsdebug_call_finished0(); + return 1; + } + if (!strcmp(cmd, "STATUS")) { - do_status(); + do_status(NULL); upsdebug_call_finished0(); return 1; } @@ -940,7 +1002,7 @@ static int do_command(char *cmd) upsdebugx(2, "%s: ENDFOR: done with UPS [%s] [%s]", __func__, NUT_STRARG(currups->sys), NUT_STRARG(currups->desc)); upsdebugx(2, "%s: current skip_clause=%d skip_block=%d", __func__, skip_clause, skip_block); - currups = currups->next; + currups = (ulist_t *)currups->next; if (currups) { upsdebugx(2, "%s: ENDFOR: proceed with next UPS [%s]", __func__, NUT_STRARG(currups->desc)); @@ -1087,29 +1149,85 @@ static void parse_line(const char *buf) upsdebug_call_finished0(); } -static void display_template(const char *tfn) +/* type = 1 for upsstats-single.html (or custom copy), 2 for upsstats.html (list) */ +static void display_template(const char *tfn, int type) { char fn[NUT_PATH_MAX + 1], buf[LARGEBUF]; + ulist_t *tmp = NULL; upsdebug_call_starting_for_str1(tfn); + if (!tfn || !*tfn || strstr(tfn, "/") || strstr(tfn, "\\")) { + /* We only allow pre-configured templates in one managed location, with ".htm" in the name */ + errno = EPERM; + fprintf(stderr, "upsstats: Can't open %s: %s: asked to look not exactly in the managed location
\n", tfn, strerror(errno)); + + printf("Error: can't open template file (%s): Not authorized
\n", tfn); + + upsdebug_call_finished1(": subdir in template"); + exit(EXIT_FAILURE); + } + + if (!strstr(tfn, ".htm")) { + /* We only allow pre-configured templates with ".htm" in the name */ + errno = EPERM; + fprintf(stderr, "upsstats: Can't open %s: %s: asked to look at not a *.htm* file
\n", tfn, strerror(errno)); + + printf("Error: can't open template file (%s): Not authorized
\n", tfn); + + upsdebug_call_finished1(": not a *.htm* file"); + exit(EXIT_FAILURE); + } + + if (type == 1) { + /* Check if [custom] single template is allowed + * (built-in/legacy default starts the list) */ + tmp = allowed_template_single_lhead; + while (tmp) { + if (!strcmp(tmp->sys, tfn)) + break; + tmp = (ulist_t *)tmp->next; + } + } else + if (type == 2) { + /* Check if [custom] list template is allowed + * (built-in/legacy default starts the list) */ + tmp = allowed_template_list_lhead; + while (tmp) { + if (!strcmp(tmp->sys, tfn)) + break; + tmp = (ulist_t *)tmp->next; + } + } + + if (!tmp) { + /* We only allow pre-configured templates permitted via hosts.conf */ + errno = EPERM; + fprintf(stderr, "upsstats: Can't open %s: %s: Not authorized: template not permitted via hosts.conf
\n", tfn, strerror(errno)); + + printf("Error: can't open template file (%s): Not authorized
\n", tfn); + + upsdebug_call_finished1(": template not permitted via hosts.conf"); + exit(EXIT_FAILURE); + } + snprintf(fn, sizeof(fn), "%s/%s", confpath(), tfn); tf = fopen(fn, "rb"); if (!tf) { - fprintf(stderr, "upsstats: Can't open %s: %s\n", fn, strerror(errno)); + fprintf(stderr, "upsstats: Can't open %s: %s
\n", fn, strerror(errno)); - printf("Error: can't open template file (%s)\n", tfn); + printf("Error: can't open template file (%s)
\n", tfn); upsdebug_call_finished1(": no template"); exit(EXIT_FAILURE); } if (!fgets(buf, sizeof(buf), tf)) { - fprintf(stderr, "upsstats: template file %s seems to be empty (fgets failed): %s\n", fn, strerror(errno)); + fprintf(stderr, "upsstats: template file %s seems to be empty (fgets failed): %s
\n", fn, strerror(errno)); - printf("Error: template file %s seems to be empty\n", tfn); + printf("Error: template file %s seems to be empty
\n", tfn); upsdebug_call_finished1(": empty template"); exit(EXIT_FAILURE); @@ -1119,9 +1237,9 @@ static void display_template(const char *tfn) if (!strncmp(buf, "@NUT_UPSSTATS_TEMPLATE", 22)) { parse_line(buf); } else { - fprintf(stderr, "upsstats: template file %s does not start with NUT_UPSSTATS_TEMPLATE command\n", fn); + fprintf(stderr, "upsstats: template file %s does not start with NUT_UPSSTATS_TEMPLATE command
\n", fn); - printf("Error: template file %s does not start with NUT_UPSSTATS_TEMPLATE command\n", tfn); + printf("Error: template file %s does not start with NUT_UPSSTATS_TEMPLATE command
\n", tfn); upsdebug_call_finished1(": not a valid template"); exit(EXIT_FAILURE); @@ -1195,7 +1313,7 @@ static void display_tree(int verbose) printf("%s\n", answer[2]); printf(":\n"); - printf("%s
\n", answer[3]); + printf("%s\n", answer[3]); printf("\n"); } @@ -1216,10 +1334,10 @@ static void add_ups(char *sys, char *desc) while (tmp) { last = tmp; - tmp = tmp->next; + tmp = (ulist_t *)tmp->next; } - tmp = xmalloc(sizeof(ulist_t)); + tmp = (ulist_t *)xmalloc(sizeof(ulist_t)); tmp->sys = xstrdup(sys); tmp->desc = xstrdup(desc); @@ -1231,13 +1349,69 @@ static void add_ups(char *sys, char *desc) ulhead = tmp; } +static void add_allowed_template_list(char *tfn) +{ + ulist_t *tmp, *last; + + if (!tfn || !*tfn) + return; + + tmp = last = allowed_template_list_lhead; + + while (tmp) { + if (!strcmp(tmp->sys, tfn)) + return; + last = tmp; + tmp = (ulist_t *)tmp->next; + } + + tmp = (ulist_t *)xmalloc(sizeof(ulist_t)); + + tmp->sys = xstrdup(tfn); + tmp->desc = NULL; + tmp->next = NULL; + + if (last) + last->next = tmp; + else + allowed_template_list_lhead = tmp; +} + +static void add_allowed_template_single(char *tfn) +{ + ulist_t *tmp, *last; + + if (!tfn || !*tfn) + return; + + tmp = last = allowed_template_single_lhead; + + while (tmp) { + if (!strcmp(tmp->sys, tfn)) + return; + last = tmp; + tmp = (ulist_t *)tmp->next; + } + + tmp = (ulist_t *)xmalloc(sizeof(ulist_t)); + + tmp->sys = xstrdup(tfn); + tmp->desc = NULL; + tmp->next = NULL; + + if (last) + last->next = tmp; + else + allowed_template_single_lhead = tmp; +} + /* called for fatal errors in parseconf like malloc failures */ static void upsstats_hosts_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg); } -static void load_hosts_conf(void) +static void load_hosts_conf(int handle_MONITOR) { char fn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; @@ -1275,18 +1449,29 @@ static void load_hosts_conf(void) continue; } + if (ctx.numargs < 2) + continue; + + /* CUSTOM_TEMPLATE_LIST */ + if (!strcmp(ctx.arglist[0], "CUSTOM_TEMPLATE_LIST")) + add_allowed_template_list(ctx.arglist[1]); + + /* CUSTOM_TEMPLATE_SINGLE */ + if (!strcmp(ctx.arglist[0], "CUSTOM_TEMPLATE_SINGLE")) + add_allowed_template_single(ctx.arglist[1]); + if (ctx.numargs < 3) continue; /* MONITOR */ - if (!strcmp(ctx.arglist[0], "MONITOR")) + if (handle_MONITOR && !strcmp(ctx.arglist[0], "MONITOR")) add_ups(ctx.arglist[1], ctx.arglist[2]); } pconf_finish(&ctx); - if (!ulhead) { + if (!ulhead && handle_MONITOR) { /* Don't print HTML here if we are in JSON mode. * The JSON function will handle the error. */ @@ -1326,7 +1511,7 @@ static void display_single(void) if (treemode) display_tree(1); else - display_template("upsstats-single.html"); + display_template(template_single, 1); upscli_disconnect(&ups); upsdebug_call_finished0(); @@ -1368,7 +1553,7 @@ static void display_json(void) add_ups(monhost, monhostdesc); currups = ulhead; } else { - load_hosts_conf(); /* This populates ulhead */ + load_hosts_conf(1); /* This populates ulhead */ currups = ulhead; } @@ -1387,7 +1572,7 @@ static void display_json(void) } /* Loop through all devices (in single-host mode, this is just one) */ - for (currups = ulhead; currups != NULL; currups = currups->next) { + for (currups = ulhead; currups != NULL; currups = (ulist_t *)currups->next) { ups_connect(); if (!is_first_ups) printf(",\n"); @@ -1489,14 +1674,14 @@ int main(int argc, char **argv) int i; #ifdef WIN32 - /* Required ritual before calling any socket functions */ - static WSADATA WSAdata; - static int WSA_Started = 0; - if (!WSA_Started) { - WSAStartup(2, &WSAdata); - atexit((void(*)(void))WSACleanup); - WSA_Started = 1; - } + /* Required ritual before calling any socket functions */ + static WSADATA WSAdata; + static int WSA_Started = 0; + if (!WSA_Started) { + WSAStartup(2, &WSAdata); + atexit((void(*)(void))WSACleanup); + WSA_Started = 1; + } /* Avoid binary output conversions, e.g. * mangling what looks like CRLF on WIN32 */ @@ -1516,6 +1701,28 @@ int main(int argc, char **argv) nut_debug_level = i; } + +#ifdef NUT_CGI_DEBUG_UPSSTATS +# if (NUT_CGI_DEBUG_UPSSTATS - 0 < 1) +# undef NUT_CGI_DEBUG_UPSSTATS +# define NUT_CGI_DEBUG_UPSSTATS 6 +# endif + /* Un-comment via make flags when developer-troubleshooting: */ + nut_debug_level = NUT_CGI_DEBUG_UPSSTATS; +#endif + + if (nut_debug_level > 0) { + cgilogbit_set(); + printf("Content-type: text/html\n"); + printf("Pragma: no-cache\n"); + printf("\n"); + printf("

NUT CGI Debugging enabled, level: %d

\n\n", nut_debug_level); + } + + /* Built-in defaults */ + template_single = xstrdup("upsstats-single.html"); + template_list = xstrdup("upsstats.html"); + extractcgiargs(); upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT); @@ -1533,7 +1740,7 @@ int main(int argc, char **argv) /* Clean up memory */ free(monhost); while (ulhead) { - currups = ulhead->next; + currups = (ulist_t *)ulhead->next; free(ulhead->sys); free(ulhead->desc); free(ulhead); @@ -1541,6 +1748,8 @@ int main(int argc, char **argv) } free(upsname); free(hostname); + free(template_single); + free(template_list); exit(EXIT_SUCCESS); } @@ -1551,14 +1760,18 @@ int main(int argc, char **argv) printf("Pragma: no-cache\n"); printf("\n"); - /* if a host is specified, use upsstats-single.html instead */ + /* if a host is specified, use upsstats-single.html instead + * of listing whatever we know about with upsstats.html */ + add_allowed_template_single("upsstats-single.html"); + add_allowed_template_list("upsstats.html"); if (monhost) { + load_hosts_conf(0); display_single(); } else { /* default: multimon replacement mode */ - load_hosts_conf(); + load_hosts_conf(1); currups = ulhead; - display_template("upsstats.html"); + display_template(template_list, 2); } /* Clean up memory */ @@ -1567,12 +1780,31 @@ int main(int argc, char **argv) free(upsname); free(hostname); while (ulhead) { - currups = ulhead->next; + currups = (ulist_t *)ulhead->next; free(ulhead->sys); free(ulhead->desc); free(ulhead); ulhead = currups; } + free(template_single); + free(template_list); + + /* Free storage of allowed template names (reusing same kind of structure as UPSes) */ + while (allowed_template_single_lhead) { + currups = (ulist_t *)allowed_template_single_lhead->next; + free(allowed_template_single_lhead->sys); + free(allowed_template_single_lhead->desc); + free(allowed_template_single_lhead); + allowed_template_single_lhead = currups; + } + + while (allowed_template_list_lhead) { + currups = (ulist_t *)allowed_template_list_lhead->next; + free(allowed_template_list_lhead->sys); + free(allowed_template_list_lhead->desc); + free(allowed_template_list_lhead); + allowed_template_list_lhead = currups; + } return 0; } diff --git a/common/Makefile.am b/common/Makefile.am index 3064f4fc09..211998cf79 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -92,7 +92,7 @@ else !BUILDING_IN_TREE BUILT_SOURCES = common-nut_version.c endif !BUILDING_IN_TREE -$(top_builddir)/include/nut_version.h: +$(top_builddir)/include/nut_version.h: @dotMAKE@ +@if [ -s '$@' ] && ( [ x"$(NUT_VERSION_H_GENERATED)" = xtrue ] || [ x"$${NUT_VERSION_H_GENERATED}" = xtrue ] ) ; then \ if [ x"$(MAINTAINER_GENERATE_HEADER_DEBUG)" = xyes ] ; then \ echo "=== SKIP (common) $@ (NUT_VERSION_H_GENERATED makevar=$(NUT_VERSION_H_GENERATED) shellvar=$${NUT_VERSION_H_GENERATED})" >&2; \ @@ -220,7 +220,12 @@ endif HAVE_WINDOWS endif WITH_DEV_LIBNUTCONF libnutconf_la_CXXFLAGS = $(AM_CXXFLAGS) # NOTE: No @LTLIBOBJS@ here, because libcommonclient.la includes them (if any) - libnutconf_la_LIBADD = @NETLIBS@ libcommonclient.la + libnutconf_la_LIBADD = @NETLIBS@ +if ENABLE_SHARED_PRIVATE_LIBS + libnutconf_la_LIBADD += libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la +else !ENABLE_SHARED_PRIVATE_LIBS + libnutconf_la_LIBADD += libcommonclient.la +endif !ENABLE_SHARED_PRIVATE_LIBS libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp \ ../include/nutconf.hpp ../include/nutipc.hpp \ ../include/nutstream.hpp ../include/nutwriter.hpp diff --git a/common/common-nut_version.c b/common/common-nut_version.c index 461b7515df..92b1d93b03 100644 --- a/common/common-nut_version.c +++ b/common/common-nut_version.c @@ -355,7 +355,7 @@ const char *suggest_doc_links(const char *progname, const char *progconf) { * man page section for "System Management Programs". * If this ever changes (e.g. clients like `upsc` can be * a "User Program" just as well), we may need an extra - method argument here. + * method argument here. */ snprintfcat(buf, sizeof(buf), "Read The Fine Manual ('man %s %s') and/or ", diff --git a/common/common.c b/common/common.c index 5e6697a052..aec564876c 100644 --- a/common/common.c +++ b/common/common.c @@ -588,6 +588,16 @@ int syslog_is_disabled(void) return value; } +/* enable writing upslog_with_errno() and upslogx() type messages to + * the stdout instead of stderr, and end them with HTML
tag, + * to help troubleshoot NUT CGI programs specifically */ +void cgilogbit_set(void) +{ + xbit_set(&upslog_flags, UPSLOG_STDOUT); + xbit_set(&upslog_flags, UPSLOG_CGI_BR); + xbit_clear(&upslog_flags, UPSLOG_STDERR); +} + /* enable writing upslog_with_errno() and upslogx() type messages to the syslog */ void syslogbit_set(void) @@ -763,8 +773,8 @@ struct passwd *get_user_pwent(const char *name) return r; /* POSIX does not specify that "user not found" is an error, so - some implementations of getpwnam() do not set errno when this - happens. */ + * some implementations of getpwnam() do not set errno when this + * happens. */ if (errno == 0) fatalx(EXIT_FAILURE, "OS user %s not found", name); else @@ -1464,17 +1474,17 @@ int compareprocnames(pid_t pid, const char *procname, const char **prognames) goto finish; } - progbasenames = xcalloc(total_prognames, sizeof(char*)); + progbasenames = (char **)xcalloc(total_prognames, sizeof(char*)); if (!progbasenames) { ret = -2; goto finish; } - progbasenamelen = xcalloc(total_prognames, sizeof(size_t)); + progbasenamelen = (size_t *)xcalloc(total_prognames, sizeof(size_t)); if (!progbasenamelen) { ret = -2; goto finish; } - progbasenamedot = xcalloc(total_prognames, sizeof(size_t)); + progbasenamedot = (size_t *)xcalloc(total_prognames, sizeof(size_t)); if (!progbasenamedot) { ret = -2; goto finish; @@ -1482,7 +1492,7 @@ int compareprocnames(pid_t pid, const char *procname, const char **prognames) memset(all_progbasenames, 0, sizeof(all_progbasenames)); for (i = 0; i < total_prognames - 1; i++) { - progbasenames[i] = xcalloc(NUT_PATH_MAX + 1, sizeof(char)); + progbasenames[i] = (char *)xcalloc(NUT_PATH_MAX + 1, sizeof(char)); if (!progbasenames[i]) { ret = -2; @@ -1542,8 +1552,8 @@ int compareprocnames(pid_t pid, const char *procname, const char **prognames) size_t dot = progbasenamedot[i] ? progbasenamedot[i] : procbasenamedot; /* Optimize away procbasename comparisons beyond first */ - if (!strncasecmp(progbasenames[i], procbasename, dot - 1) && - ( (progbasenamedot[i] && !strcasecmp(progbasenames[i] + progbasenamedot[i], ".exe")) + if (!strncasecmp(progbasenames[i], procbasename, dot - 1) + && ( (progbasenamedot[i] && !strcasecmp(progbasenames[i] + progbasenamedot[i], ".exe")) || (i == 0 && procbasenamedot && !strcasecmp(procbasename + procbasenamedot, ".exe")) ) ) { ret = 5; @@ -1868,8 +1878,8 @@ char * getfullpath(char * relative_path) upsdebugx(6, "%s: prefix_in_buf:\t'%s'", __func__, NUT_STRARG(prefix_in_buf)); /* Did we find the prefix and is it followed by some slash? */ - if (prefix_in_buf && - ( *(prefix_in_buf + len_PREFIX) == '/' + if (prefix_in_buf + && ( *(prefix_in_buf + len_PREFIX) == '/' || *(prefix_in_buf + len_PREFIX) == '\\') ) { /* Make the path relative @@ -2253,9 +2263,11 @@ pid_t parsepidfile(const char *pidfn) * for the first time and no opponent PID file exists, * so the cut-off verbosity is higher. */ - if (nut_debug_level > 0 || - nut_sendsignal_debug_level >= NUT_SENDSIGNAL_DEBUG_LEVEL_FOPEN_PIDFILE) + if (nut_debug_level > 0 + || nut_sendsignal_debug_level >= NUT_SENDSIGNAL_DEBUG_LEVEL_FOPEN_PIDFILE + ) { upslog_with_errno(LOG_NOTICE, "fopen %s", pidfn); + } return -3; } @@ -2463,9 +2475,12 @@ int str_contains_token(const char *string, const char *token) * checking for uniqueness and going to add a newly seen token. * If such callback returns 0, abort the addition of token. */ -int str_add_unique_token(char *tgt, size_t tgtsize, const char *token, - int (*callback_always)(char *, size_t, const char *), - int (*callback_unique)(char *, size_t, const char *) +int str_add_unique_token( + char *tgt, + size_t tgtsize, + const char *token, + int (*callback_always)(char *, size_t, const char *), + int (*callback_unique)(char *, size_t, const char *) ) { size_t toklen = 0, tgtlen = 0; @@ -2719,6 +2734,31 @@ double difftimespec(struct timespec x, struct timespec y) } #endif /* HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC */ +/* returns the time elapsed since start in milliseconds */ +long elapsed_since_timeval(struct timeval *start) +{ + long rval; + struct timeval end; + + rval = gettimeofday(&end, NULL); + if (rval < 0) { + upslog_with_errno(LOG_ERR, "elapsed_since_timeval"); + } + if (start->tv_usec < end.tv_usec) { + suseconds_t nsec = (end.tv_usec - start->tv_usec) / 1000000 + 1; + end.tv_usec -= 1000000 * nsec; + end.tv_sec += nsec; + } + if (start->tv_usec - end.tv_usec > 1000000) { + suseconds_t nsec = (start->tv_usec - end.tv_usec) / 1000000; + end.tv_usec += 1000000 * nsec; + end.tv_sec -= nsec; + } + rval = (end.tv_sec - start->tv_sec) * 1000 + (end.tv_usec - start->tv_usec) / 1000; + + return rval; +} + /* Help avoid cryptic "upsnotify: notify about state 4 with libsystemd:" * (with only numeric codes) below */ const char *str_upsnotify_state(upsnotify_state_t state) { @@ -3278,8 +3318,8 @@ int upsnotify(upsnotify_state_t state, const char *fmt, ...) char *s = getenv("NUT_QUIET_INIT_UPSNOTIFY"); /* FIXME: Make an INVERTED server/conf.c::parse_boolean() reusable */ - if (s && *s && - ( (!strcasecmp(s, "false")) || (!strcasecmp(s, "off")) || (!strcasecmp(s, "no")) || (!strcasecmp(s, "0"))) + if (s && *s + && ( (!strcasecmp(s, "false")) || (!strcasecmp(s, "off")) || (!strcasecmp(s, "no")) || (!strcasecmp(s, "0")) ) ) { upsdebugx(1, "Caller WANTS to see all these messages: NUT_QUIET_INIT_UPSNOTIFY=%s", NUT_STRARG(s)); } else { @@ -3548,7 +3588,7 @@ int validate_formatting_string(const char *fmt_dynamic, const char *fmt_referenc */ size_t lenD = strlen(fmt_dynamic) + 1; size_t lenR = strlen(fmt_reference) + 1; - char *bufD = xcalloc(lenD, sizeof(char)), *bufR = xcalloc(lenR, sizeof(char)); + char *bufD = (char *)xcalloc(lenD, sizeof(char)), *bufR = (char *)xcalloc(lenR, sizeof(char)); size_t lenBufD; if (!bufD || !bufR) { @@ -3762,8 +3802,15 @@ char * mkstr_dynamic(const char *fmt_dynamic, const char *fmt_reference, ...) static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) { int ret, errno_orig = errno; +#ifdef HAVE_VA_COPY_VARIANT + /* Most our debug messages fit into this */ + size_t bufsize = 256; +#else + /* err on the safe(r) side, as re-runs can truncate + * the output when varargs are re-used */ size_t bufsize = LARGEBUF; - char *buf = xcalloc(bufsize, sizeof(char)); +#endif + char *buf = (char *)xcalloc(bufsize, sizeof(char)); /* Be pedantic about our limitations */ bufsize *= sizeof(char); @@ -3822,7 +3869,7 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) * Based on https://stackoverflow.com/a/72981237/4715872 */ if (bufsize < SIZE_MAX/2) { - size_t newbufsize = bufsize*2; + size_t newbufsize = bufsize < LARGEBUF ? LARGEBUF : bufsize*2; if (ret > 0) { /* Be generous, we snprintfcat() some * suffixes, prefix a timestamp, etc. */ @@ -3842,7 +3889,7 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) newbufsize); } bufsize = newbufsize; - buf = xrealloc(buf, bufsize); + buf = (char *)xrealloc(buf, bufsize); continue; } } else { @@ -3916,7 +3963,7 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) upslog_start = now; } - if (xbit_test(upslog_flags, UPSLOG_STDERR)) { + if (xbit_test(upslog_flags, UPSLOG_STDERR) || xbit_test(upslog_flags, UPSLOG_STDOUT)) { if (nut_debug_level > 0) { struct timeval now; @@ -3929,15 +3976,42 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) /* Print all in one shot, to better avoid * mixed lines in parallel threads */ - fprintf(stderr, "%4.0f.%06ld\t%s\n", - difftime(now.tv_sec, upslog_start.tv_sec), - (long)(now.tv_usec - upslog_start.tv_usec), - buf); + if (xbit_test(upslog_flags, UPSLOG_STDERR)) { +#ifdef WIN32 + fflush(stderr); +#endif /* WIN32 */ + fprintf(stderr, "%s%4.0f.%06ld\t%s%s\n", + xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : "",
+					difftime(now.tv_sec, upslog_start.tv_sec),
+					(long)(now.tv_usec - upslog_start.tv_usec),
+					buf,
+					xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : "" + ); + } + + if (xbit_test(upslog_flags, UPSLOG_STDOUT)) { +#ifdef WIN32 + fflush(stdout); +#endif /* WIN32 */ + fprintf(stdout, "%s%4.0f.%06ld\t%s%s\n", + xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : "",
+					difftime(now.tv_sec, upslog_start.tv_sec),
+					(long)(now.tv_usec - upslog_start.tv_usec),
+					buf,
+					xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : "" + ); + } } else { - fprintf(stderr, "%s\n", buf); + if (xbit_test(upslog_flags, UPSLOG_STDERR)) + fprintf(stderr, "%s\n", buf); + if (xbit_test(upslog_flags, UPSLOG_STDOUT)) + fprintf(stdout, "%s\n", buf); } #ifdef WIN32 - fflush(stderr); + if (xbit_test(upslog_flags, UPSLOG_STDERR)) + fflush(stderr); + if (xbit_test(upslog_flags, UPSLOG_STDOUT)) + fflush(stdout); #endif /* WIN32 */ } if (xbit_test(upslog_flags, UPSLOG_SYSLOG)) @@ -4205,7 +4279,7 @@ void setproctag(const char *tag) proctag = xstrdup(tag); proctag_for_upsdebug_buflen = strlen(tag) + 2; - proctag_for_upsdebug = xcalloc(proctag_for_upsdebug_buflen, sizeof(char)); + proctag_for_upsdebug = (char *)xcalloc(proctag_for_upsdebug_buflen, sizeof(char)); if (proctag_for_upsdebug) { snprintf(proctag_for_upsdebug, proctag_for_upsdebug_buflen, ":%s", tag); } @@ -4789,10 +4863,14 @@ static void nut_free_search_paths(void) { } if (search_paths != search_paths_builtin) { +#if HAVE_DECL_REALPATH size_t i; for (i = 0; search_paths[i] != NULL; i++) { + upsdebugx(7, "%s: freeing search_paths[%" PRIuSIZE "]: '%s'", + __func__, i, NUT_STRARG(search_paths[i])); free((char *)search_paths[i]); } +#endif /* else: curated selection of pointers to some of the built-in strings */ free(search_paths); search_paths = search_paths_builtin; } @@ -4814,14 +4892,21 @@ void nut_prepare_search_paths(void) { size_t count_builtin = 0, count_filtered = 0, i, j, index = 0; const char ** filtered_search_paths; DIR *dp; +#if HAVE_DECL_REALPATH + /* Per docs, buffer must be at least PATH_MAX bytes */ + char realpath_buf[NUT_PATH_MAX + 1] = {0}, *realpath_dirname = NULL; +#endif /* As a starting point, allow at least as many items as before */ /* TODO: somehow extend (xrealloc?) if we mix other paths later */ - for (i = 0; search_paths_builtin[i] != NULL; i++) {} + for (i = 0; search_paths_builtin[i] != NULL; i++) { + /* Different way of printing with minimal crash-ability on older systems */ + upsdebugx(7, "counting search_paths_builtin[%d] : %s", (int)i, NUT_STRARG(search_paths_builtin[i])); + } count_builtin = i + 1; /* +1 for the NULL */ /* Bytes inside should all be zeroed... */ - filtered_search_paths = xcalloc(count_builtin, sizeof(const char *)); + filtered_search_paths = (const char **)xcalloc(count_builtin, sizeof(const char *)); /* FIXME: here "count_builtin" means size of filtered_search_paths[] * and may later be more, if we would consider other data sources */ @@ -4829,22 +4914,35 @@ void nut_prepare_search_paths(void) { int dupe = 0; const char *dirname = search_paths_builtin[i]; + upsdebugx(7, "%s: checking search_paths_builtin[%" PRIuSIZE " of %" PRIuSIZE "] : %s", + __func__, i, count_builtin - 1, NUT_STRARG(dirname)); if ((dp = opendir(dirname)) == NULL) { upsdebugx(5, "%s: SKIP " "unreachable directory #%" PRIuSIZE " : %s", - __func__, index++, dirname); + __func__, index, NUT_STRARG(dirname)); + index++; continue; } index++; #if HAVE_DECL_REALPATH /* allocates the buffer we free() later */ - dirname = (const char *)realpath(dirname, NULL); + upsdebugx(7, "%s: call realpath()", __func__); + errno = 0; + realpath_dirname = realpath(dirname, realpath_buf); + if (errno || !realpath_dirname) + upsdebug_with_errno(7, "%s: realpath() failed and returned: %s", __func__, NUT_STRARG(realpath_dirname)); + else + upsdebugx(7, "%s: realpath() returned: %s", __func__, NUT_STRARG(realpath_dirname)); + if (realpath_dirname) + dirname = (const char *)realpath_dirname; #endif /* Revise for duplicates */ /* Note: (count_filtered == 0) means first existing dir seen, no hassle */ for (j = 0; j < count_filtered; j++) { + upsdebugx(7, "%s: check for duplicates filtered_search_paths[%" PRIuSIZE " of %" PRIuSIZE "] : %s", + __func__, j, count_filtered, NUT_STRARG(filtered_search_paths[j])); if (!strcmp(filtered_search_paths[j], dirname)) { #if HAVE_DECL_REALPATH if (strcmp(search_paths_builtin[i], dirname)) { @@ -4861,7 +4959,6 @@ void nut_prepare_search_paths(void) { dupe = 1; #if HAVE_DECL_REALPATH - free((char *)dirname); /* Have some valid value, for kicks (likely * to be ignored in the code path below) */ dirname = search_paths_builtin[i]; @@ -4874,9 +4971,10 @@ void nut_prepare_search_paths(void) { upsdebugx(5, "%s: ADD[#%" PRIuSIZE "] " "existing unique directory: %s", __func__, count_filtered, dirname); -#if !HAVE_DECL_REALPATH - /* Make a copy of table entry, else we have - * a dynamic result of realpath() made above. +#if HAVE_DECL_REALPATH + /* Make a copy of table entry, or the buffer + * with a result of realpath() made above, + * to eventually conststently free(). */ dirname = (const char *)xstrdup(dirname); #endif @@ -4979,7 +5077,7 @@ static char * get_libname_in_dir(const char* base_libname, size_t base_libname_l char current_test_path[NUT_PATH_MAX + 1]; upsdebugx(3, "%s('%s', %" PRIuSIZE ", '%s', %i): Entering method...", - __func__, base_libname, base_libname_length, dirname, index); + __func__, NUT_STRARG(base_libname), base_libname_length, NUT_STRARG(dirname), index); memset(current_test_path, 0, sizeof(current_test_path)); @@ -5112,7 +5210,7 @@ static char * get_libname_in_pathset(const char* base_libname, size_t base_libna /* First call to tokenization passes the string, others pass NULL */ pathset_tmp = xstrdup(pathset); upsdebugx(4, "%s: Looking for lib %s in a colon-separated path set", - __func__, base_libname); + __func__, NUT_STRARG(base_libname)); while (NULL != (onedir = strtok( (onedir ? NULL : pathset_tmp), ":" ))) { libname_path = get_libname_in_dir(base_libname, base_libname_length, onedir, (*counter)++); if (libname_path != NULL) @@ -5148,7 +5246,7 @@ char * get_libname(const char* base_libname) size_t base_libname_length = strlen(base_libname); struct stat st; - upsdebugx(3, "%s('%s'): Entering method...", __func__, base_libname); + upsdebugx(3, "%s('%s'): Entering method...", __func__, NUT_STRARG(base_libname)); /* First, check for an exact hit by absolute/relative path * if `base_libname` includes path separator character(s) */ @@ -5315,7 +5413,7 @@ int compile_regex(regex_t **compiled, const char *regex, const int cflags) return 0; } - preg = malloc(sizeof(*preg)); + preg = (regex_t *)malloc(sizeof(*preg)); if (!preg) { return -1; } @@ -5478,7 +5576,7 @@ const char *xinet_ntopSS(struct sockaddr_storage *s) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif - char *addrstr = xcalloc(INETADDRBUF_SIZE, sizeof(char*)); + char *addrstr = (char*)xcalloc(INETADDRBUF_SIZE, sizeof(char*)); const char *ret; if (!addrstr) @@ -5578,7 +5676,7 @@ const char *xinet_ntopAI(struct addrinfo *ai) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif - char *addrstr = xcalloc(INETADDRBUF_SIZE, sizeof(char*)); + char *addrstr = (char*)xcalloc(INETADDRBUF_SIZE, sizeof(char*)); const char *ret; if (!addrstr) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index ea2dd1659f..4345034f18 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -35,6 +35,7 @@ #include #include +#include #include @@ -270,23 +271,23 @@ NutParser::Token NutParser::parseToken() } else if (c == '[') { token = Token(Token::TOKEN_BRACKET_OPEN, c); popPos(); - return token; + return Token(std::move(token)); } else if (c == ']') { token = Token(Token::TOKEN_BRACKET_CLOSE, c); popPos(); - return token; + return Token(std::move(token)); } else if (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) { token = Token(Token::TOKEN_COLON, c); popPos(); - return token; + return Token(std::move(token)); } else if (c == '=') { token = Token(Token::TOKEN_EQUAL, c); popPos(); - return token; + return Token(std::move(token)); } else if (c == '\r' || c == '\n') { token = Token(Token::TOKEN_EOL, c); popPos(); - return token; + return Token(std::move(token)); } else if (c == '#') { token.type = Token::TOKEN_COMMENT; state = LEXPARSING_STATE_COMMENT; @@ -318,7 +319,7 @@ NutParser::Token NutParser::parseToken() token.str += '"'; } else { popPos(); - return token; + return Token(std::move(token)); } } else if (c == '\\') { if (escaped) { @@ -333,10 +334,10 @@ NutParser::Token NutParser::parseToken() /* WTF ? consider it as correct ? */ back(); popPos(); - return token; + return Token(std::move(token)); } else if (c == 0) /* EOF */ { popPos(); - return token; + return Token(std::move(token)); } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ } @@ -355,7 +356,7 @@ NutParser::Token NutParser::parseToken() } else { back(); popPos(); - return token; + return Token(std::move(token)); } } else if (c == '\\') { if (escaped) { @@ -367,10 +368,10 @@ NutParser::Token NutParser::parseToken() } else if (c == '\r' || c == '\n') /* EOL */{ back(); popPos(); - return token; + return Token(std::move(token)); } else if (c == 0) /* EOF */ { popPos(); - return token; + return Token(std::move(token)); }else if (isgraph(c)) { token.str += c; } else /* Bad character ?? */ { @@ -382,7 +383,7 @@ NutParser::Token NutParser::parseToken() case LEXPARSING_STATE_COMMENT: { if (c == '\r' || c == '\n') { - return token; + return Token(std::move(token)); } else { token.str += c; } @@ -416,7 +417,7 @@ NutParser::Token NutParser::parseToken() } } popPos(); - return token; + return Token(std::move(token)); } std::list NutParser::parseLine() @@ -1044,15 +1045,13 @@ void GenericConfiguration::removeSection(const std::string & section) std::string GenericConfiguration::getStr(const std::string & section, const std::string & entry, bool caseSensitive) const { - std::string str; - ConfigParamList params; if (!get(section, entry, params, caseSensitive)) - return str; + return std::string(); if (params.empty()) - return str; + return std::string(); return params.front(); } diff --git a/common/parseconf.c b/common/parseconf.c index cebf27f839..a9b7815990 100644 --- a/common/parseconf.c +++ b/common/parseconf.c @@ -132,13 +132,13 @@ static void add_arg_word(PCONF_CTX_t *ctx) ctx->maxargs = ctx->numargs; /* resize the lists */ - ctx->arglist = realloc(ctx->arglist, + ctx->arglist = (char **)realloc(ctx->arglist, sizeof(char *) * ctx->numargs); if (!ctx->arglist) pconf_fatal(ctx, "realloc arglist failed"); - ctx->argsize = realloc(ctx->argsize, + ctx->argsize = (size_t *)realloc(ctx->argsize, sizeof(size_t) * ctx->numargs); if (!ctx->argsize) @@ -159,7 +159,7 @@ static void add_arg_word(PCONF_CTX_t *ctx) newlen = wbuflen + 1; /* expand the string storage */ - ctx->arglist[argpos] = realloc(ctx->arglist[argpos], newlen); + ctx->arglist[argpos] = (char *)realloc(ctx->arglist[argpos], newlen); if (!ctx->arglist[argpos]) pconf_fatal(ctx, "realloc arglist member failed"); @@ -200,7 +200,7 @@ static void addchar(PCONF_CTX_t *ctx) if (wbuflen >= (ctx->wordbufsize - 1)) { ctx->wordbufsize += 8; - ctx->wordbuf = realloc(ctx->wordbuf, ctx->wordbufsize); + ctx->wordbuf = (char *)realloc(ctx->wordbuf, ctx->wordbufsize); if (!ctx->wordbuf) pconf_fatal(ctx, "realloc wordbuf failed"); @@ -415,7 +415,7 @@ int pconf_init(PCONF_CTX_t *ctx, void errhandler(const char *)) ctx->argsize = NULL; ctx->wordbufsize = 16; - ctx->wordbuf = calloc(1, ctx->wordbufsize); + ctx->wordbuf = (char *)calloc(1, ctx->wordbufsize); if (!ctx->wordbuf) pconf_fatal(ctx, "malloc wordbuf failed"); diff --git a/common/state.c b/common/state.c index 877e9a9bf1..f78ad7aea5 100644 --- a/common/state.c +++ b/common/state.c @@ -54,7 +54,7 @@ static void val_escape(st_tree_t *node) /* if the escaped value grew, deal with it */ if (node->safesize < (strlen(etmp) + 1)) { node->safesize = strlen(etmp) + 1; - node->safe = xrealloc(node->safe, node->safesize); + node->safe = (char *)xrealloc(node->safe, node->safesize); } snprintf(node->safe, node->safesize, "%s", etmp); @@ -310,7 +310,7 @@ int state_setinfo(st_tree_t **nptr, const char *var, const char *val) /* expand the buffer if the value grows */ if (node->rawsize < (strlen(val) + 1)) { node->rawsize = strlen(val) + 1; - node->raw = xrealloc(node->raw, node->rawsize); + node->raw = (char *)xrealloc(node->raw, node->rawsize); } /* store the literal value for later comparisons */ @@ -321,7 +321,7 @@ int state_setinfo(st_tree_t **nptr, const char *var, const char *val) return 1; /* changed */ } - *nptr = xcalloc(1, sizeof(**nptr)); + *nptr = (st_tree_t *)xcalloc(1, sizeof(**nptr)); (*nptr)->var = xstrdup(var); (*nptr)->raw = xstrdup(val); @@ -347,7 +347,7 @@ static int st_tree_enum_add(enum_t **list, const char *enc) return 0; /* duplicate */ } - item = xcalloc(1, sizeof(*item)); + item = (enum_t *)xcalloc(1, sizeof(*item)); item->val = xstrdup(enc); item->next = *list; @@ -392,7 +392,7 @@ static int st_tree_range_add(range_t **list, const int min, const int max) return 0; /* duplicate */ } - item = xcalloc(1, sizeof(*item)); + item = (range_t *)xcalloc(1, sizeof(*item)); item->min = min; item->max = max; item->next = *list; @@ -581,7 +581,7 @@ int state_addcmd(cmdlist_t **list, const char *cmd) return 0; /* duplicate */ } - item = xcalloc(1, sizeof(*item)); + item = (cmdlist_t *)xcalloc(1, sizeof(*item)); item->name = xstrdup(cmd); item->next = *list; diff --git a/common/strptime.c b/common/strptime.c index 8909aea6cf..90b6627019 100644 --- a/common/strptime.c +++ b/common/strptime.c @@ -316,8 +316,8 @@ again: switch (c = *fmt++) { sse *= 10; sse += *bp++ - '0'; rulim /= 10; - } while (((uint64_t)sse * 10 <= TIME_MAX) && - rulim && *bp >= '0' && *bp <= '9'); + } while (((uint64_t)sse * 10 <= TIME_MAX) + && rulim && *bp >= '0' && *bp <= '9'); if (sse < 0 || (uint64_t)sse > TIME_MAX) { bp = NULL; @@ -338,9 +338,9 @@ again: switch (c = *fmt++) { * point to calculate a real value, so just check the * range for now. */ - bp = conv_num(bp, &i, 0, 53); - LEGAL_ALT(ALT_O); - continue; + bp = conv_num(bp, &i, 0, 53); + LEGAL_ALT(ALT_O); + continue; case 'w': /* The day of week, beginning on sunday. */ bp = conv_num(bp, &tm->tm_wday, 0, 6); @@ -496,8 +496,8 @@ again: switch (c = *fmt++) { continue; } - if ((*bp >= 'A' && *bp <= 'I') || - (*bp >= 'L' && *bp <= 'Y') + if ((*bp >= 'A' && *bp <= 'I') + || (*bp >= 'L' && *bp <= 'Y') ) { #ifdef TM_GMTOFF /* Argh! No 'J'! */ diff --git a/common/wincompat.c b/common/wincompat.c index 8a6f2e1b3a..9045ba4624 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -483,8 +483,8 @@ void syslog(int priority, const char *fmt, ...) WriteFile (pipe,buf1,strlen(buf2)+sizeof(DWORD),&bytesWritten,NULL); /* testing result is useless. If we have an error and try to report it, - this will probably lead to a call to this function and an infinite - loop */ + * this will probably lead to a call to this function and an infinite + * loop */ CloseHandle(pipe); } @@ -758,9 +758,9 @@ int w32_serial_read (serial_handler_t * sh, void *ptr, size_t ulen, DWORD timeou } else if (sh->vtime_) { /* non-interruptible -- have to use kernel timeouts - also note that this is not strictly correct. - if vmin > ulen then things won't work right. - sh->overlapped_armed = -1; + * also note that this is not strictly correct. + * if vmin > ulen then things won't work right. + * // sh->overlapped_armed = -1; */ inq = ulen; } @@ -909,7 +909,7 @@ int w32_serial_write (serial_handler_t * sh, const void *ptr, size_t len) serial_handler_t * w32_serial_open (const char *name, int flags) { /* flags are currently ignored, it's here just to have the same - interface as POSIX open */ + * interface as POSIX open */ NUT_UNUSED_VARIABLE(flags); COMMTIMEOUTS to; @@ -942,7 +942,7 @@ serial_handler_t * w32_serial_open (const char *name, int flags) SetCommTimeouts (sh->handle, &to); /* Reset serial port to known state of 9600-8-1-no flow control - on open for better behavior under Win 95. + * on open for better behavior under Win 95. */ DCB state; GetCommState (sh->handle, &state); @@ -962,8 +962,7 @@ serial_handler_t * w32_serial_open (const char *name, int flags) state.XonChar = 0x11; state.XoffChar = 0x13; state.fOutxDsrFlow = FALSE; /* disable DSR flow control */ - state.fRtsControl = RTS_CONTROL_ENABLE; /* ignore lead control except - DTR */ + state.fRtsControl = RTS_CONTROL_ENABLE; /* ignore lead control except DTR */ state.fOutxCtsFlow = FALSE; /* disable output flow control */ state.fDtrControl = DTR_CONTROL_ENABLE; /* assert DTR */ state.fDsrSensitivity = FALSE; /* don't assert DSR */ @@ -1097,7 +1096,7 @@ int tcflush (serial_handler_t * sh, int queue) if ((queue == TCIFLUSH) | (queue == TCIOFLUSH)) /* Input flushing by polling until nothing turns up - (we stop after 1000 chars anyway) */ + * (we stop after 1000 chars anyway) */ for (max = 1000; max > 0; max--) { DWORD ev; @@ -1147,7 +1146,7 @@ TCSAFLUSH: flush output and discard input, then change attributes. /* -------------- Set baud rate ------------------ */ /* FIXME: WIN32 also has 14400, 56000, 128000, and 256000. - Unix also has 230400. */ + * Unix also has 230400. */ switch (t->c_ospeed) { @@ -1253,10 +1252,11 @@ TCSAFLUSH: flush output and discard input, then change attributes. state.ErrorChar = 0; /* -------------- Set software flow control ------------------ */ - /* Set fTXContinueOnXoff to FALSE. This prevents the triggering of a - premature XON when the remote device interprets a received character - as XON (same as IXANY on the remote side). Otherwise, a TRUE - value separates the TX and RX functions. */ + /* Set fTXContinueOnXoff to FALSE. This prevents the triggering + * of a premature XON when the remote device interprets a received + * character as XON (same as IXANY on the remote side). + * Otherwise, a TRUE value separates the TX and RX functions. + */ state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ @@ -1283,9 +1283,10 @@ TCSAFLUSH: flush output and discard input, then change attributes. state.fOutxDsrFlow = FALSE; /* Some old flavors of Unix automatically enabled hardware flow - control when software flow control was not enabled. Since newer - Unices tend to require explicit setting of hardware flow-control, - this is what we do. */ + * control when software flow control was not enabled. Since newer + * Unices tend to require explicit setting of hardware flow-control, + * this is what we do. + */ /* RTS/CTS flow control */ if (t->c_cflag & CRTSCTS) @@ -1300,9 +1301,9 @@ TCSAFLUSH: flush output and discard input, then change attributes. } /* - if (t->c_cflag & CRTSXOFF) - state.fRtsControl = RTS_CONTROL_HANDSHAKE; - */ + if (t->c_cflag & CRTSXOFF) + state.fRtsControl = RTS_CONTROL_HANDSHAKE; + */ /* -------------- DTR ------------------ */ /* Assert DTR on device open */ @@ -1318,8 +1319,8 @@ TCSAFLUSH: flush output and discard input, then change attributes. state.fDsrSensitivity = TRUE; /* yes */ /* -------------- Error handling ------------------ */ - /* Since read/write operations terminate upon error, we - will use ClearCommError() to resume. */ + /* Since read/write operations terminate upon error, + * we will use ClearCommError() to resume. */ state.fAbortOnError = TRUE; @@ -1335,42 +1336,43 @@ TCSAFLUSH: flush output and discard input, then change attributes. else { /* FIXME: Sometimes when CLRDTR is set, setting - state.fDtrControl = DTR_CONTROL_ENABLE will fail. This - is a problem since a program might want to change some - parameters while DTR is still down. */ + * state.fDtrControl = DTR_CONTROL_ENABLE will fail. + * This is a problem since a program might want to + * change some parameters while DTR is still down. + */ EscapeCommFunction (sh->handle, SETDTR); } /* - The following documentation on was taken from "Linux Serial Programming - HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) and TIME - (t->c_cc[VTIME] || vtime_) is to be used. - - In non-canonical input processing mode, input is not assembled into - lines and input processing (erase, kill, delete, etc.) does not - occur. Two parameters control the behavior of this mode: c_cc[VTIME] - sets the character timer, and c_cc[VMIN] sets the minimum number of - characters to receive before satisfying the read. - - If MIN > 0 and TIME = 0, MIN sets the number of characters to receive - before the read is satisfied. As TIME is zero, the timer is not used. - - If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will - be satisfied if a single character is read, or TIME is exceeded (t = - TIME *0.1 s). If TIME is exceeded, no character will be returned. - - If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The - read will be satisfied if MIN characters are received, or the time - between two characters exceeds TIME. The timer is restarted every time - a character is received and only becomes active after the first - character has been received. - - If MIN = 0 and TIME = 0, read will be satisfied immediately. The - number of characters currently available, or the number of characters - requested will be returned. According to Antonino (see contributions), - you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get - the same result. + * The following documentation on was taken from "Linux Serial + * Programming HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) + * and TIME (t->c_cc[VTIME] || vtime_) is to be used. + * + * In non-canonical input processing mode, input is not assembled into + * lines and input processing (erase, kill, delete, etc.) does not + * occur. Two parameters control the behavior of this mode: c_cc[VTIME] + * sets the character timer, and c_cc[VMIN] sets the minimum number of + * characters to receive before satisfying the read. + * + * If MIN > 0 and TIME = 0, MIN sets the number of characters to receive + * before the read is satisfied. As TIME is zero, the timer is not used. + * + * If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will + * be satisfied if a single character is read, or TIME is exceeded (t = + * TIME *0.1 s). If TIME is exceeded, no character will be returned. + * + * If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The + * read will be satisfied if MIN characters are received, or the time + * between two characters exceeds TIME. The timer is restarted every time + * a character is received and only becomes active after the first + * character has been received. + * + * If MIN = 0 and TIME = 0, read will be satisfied immediately. The + * number of characters currently available, or the number of characters + * requested will be returned. According to Antonino (see contributions), + * you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get + * the same result. */ if (t->c_lflag & ICANON) @@ -1398,15 +1400,15 @@ TCSAFLUSH: flush output and discard input, then change attributes. if ((sh->vmin_ > 0) && (sh->vtime_ == 0)) { /* Returns immediately with whatever is in buffer on a ReadFile(); - or blocks if nothing found. We will keep calling ReadFile(); until - vmin_ characters are read */ + * or blocks if nothing found. We will keep calling ReadFile(); + * until vmin_ characters are read */ to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; to.ReadTotalTimeoutConstant = MAXDWORD - 1; } else if ((sh->vmin_ == 0) && (sh->vtime_ > 0)) { /* set timeoout constant appropriately and we will only try to - read one character in ReadFile() */ + * read one character in ReadFile() */ to.ReadTotalTimeoutConstant = sh->vtime_; to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; } @@ -1418,7 +1420,7 @@ TCSAFLUSH: flush output and discard input, then change attributes. else if ((sh->vmin_ == 0) && (sh->vtime_ == 0)) { /* returns immediately with whatever is in buffer as per - Time-Outs docs in Win32 SDK API docs */ + * Time-Outs docs in Win32 SDK API docs */ to.ReadIntervalTimeout = MAXDWORD; } @@ -1567,24 +1569,24 @@ int tcgetattr (serial_handler_t * sh, struct termios *t) /* -------------- Hardware flow control ------------------ */ /* Some old flavors of Unix automatically enabled hardware flow - control when software flow control was not enabled. Since newer - Unices tend to require explicit setting of hardware flow-control, - this is what we do. */ + * control when software flow control was not enabled. Since newer + * Unices tend to require explicit setting of hardware flow-control, + * this is what we do. */ /* Input flow-control */ if ((state.fRtsControl == RTS_CONTROL_HANDSHAKE) && (state.fOutxCtsFlow == TRUE)) t->c_cflag |= CRTSCTS; /* - if (state.fRtsControl == RTS_CONTROL_HANDSHAKE) - t->c_cflag |= CRTSXOFF; - */ + if (state.fRtsControl == RTS_CONTROL_HANDSHAKE) + t->c_cflag |= CRTSXOFF; + */ /* -------------- CLOCAL --------------- */ /* DSR is only lead toggled only by CLOCAL. Check it to see if - CLOCAL was called. */ + * CLOCAL was called. */ /* FIXME: If tcsetattr() hasn't been called previously, this may - give a false CLOCAL. */ + * give a false CLOCAL. */ if (state.fDsrSensitivity == FALSE) t->c_cflag |= CLOCAL; diff --git a/conf/Makefile.am b/conf/Makefile.am index 235059cc66..0bd66744b7 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -37,20 +37,20 @@ SPELLCHECK_SRC = $(dist_sysconf_DATA) \ # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ diff --git a/conf/hosts.conf.sample b/conf/hosts.conf.sample index 37e561e78b..ef9fb8b525 100644 --- a/conf/hosts.conf.sample +++ b/conf/hosts.conf.sample @@ -9,8 +9,21 @@ # ----------------------------------------------------------------------- # # upsstats will use the list of MONITOR entries when displaying the -# default template (upsstats.html). The "FOREACHUPS" directive in the -# template will use this file to find systems running upsd. +# list template (default upsstats.html). The "FOREACHUPS" directive +# in the template will use this file to find systems running upsd. +# +# upsstats allows to use custom HTML template files for some of its +# outputs (JSON and "treemode" mark-ups are currently hard-coded in +# the binary), which you can specify in the query string part of the +# URI (in your `index.html` and/or added cells of `header.html`) as e.g. +# .../cgi-bin/upsstats.cgi?template_single=upsstats-custom-single.html&template_list=upsstats-custom-list.html +# Specific file names must be permitted below with `CUSTOM_TEMPLATE_LIST` +# or `CUSTOM_TEMPLATE_SINGLE` directive, as applicable; they must contain +# the `.htm` substring, and be located directly in the NUT configuration +# directory (same as default templates). If custom templates are used +# in the original request URI, they will be automatically suffixed to +# generated links (primarily HOSTLINK, but also just in case added to +# TREELINK and TREELINK_JSON). # # upsstats and upsimage also use this file to determine if a host may be # monitored. This keeps evil people from using your system to annoy @@ -30,3 +43,19 @@ # MONITOR myups@localhost "Local UPS" # MONITOR su2200@10.64.1.1 "Finance department" # MONITOR matrix@shs-server.example.edu "Sierra High School data room #1" + +# ----------------------------------------------------------------------- +# +# Allowed custom template file (adapted copy of upsstats.html) for listing +# your devices, which must be located in the same configuration directory +# and contain `.htm` in the file name. +# +# CUSTOM_TEMPLATE_LIST + +# ----------------------------------------------------------------------- +# +# Allowed custom template file (adapted copy of upsstats-single.html) for +# listing details about a single device, which must be located in the same +# configuration directory and contain `.htm` in the file name. +# +# CUSTOM_TEMPLATE_SINGLE diff --git a/conf/ups.conf.sample b/conf/ups.conf.sample index d9eabf1853..4d04554001 100644 --- a/conf/ups.conf.sample +++ b/conf/ups.conf.sample @@ -113,9 +113,10 @@ maxretry = 3 # The default is 75 seconds. # # debug_min: OPTIONAL. Specify a minimum debug level for all driver daemons -# (when specified at global level), or for this driver daemon -# (when specified in a driver section), e.g. for troubleshooting -# a deployment. This does not directly impact the foreground or +# and for the upsdrvctl tool (when specified at global level), +# or for this driver daemon (when specified in a driver section), +# e.g. for troubleshooting a deployment without changing init +# scripts. This does not directly impact the foreground or # background running mode. If both the global and driver level # `debug_min` are set, the driver-level setting takes precedence. # Command-line option `-D` can only increase this verbosity level. diff --git a/conf/upsd.conf.sample b/conf/upsd.conf.sample index 9497b1c63b..d2ed9a8f71 100644 --- a/conf/upsd.conf.sample +++ b/conf/upsd.conf.sample @@ -121,6 +121,11 @@ # LISTEN address and each client count as one connection. If the server # runs out of connections, it will no longer accept new incoming client # connections. Only set this if you know exactly what you're doing. +# Note that on some platforms there may be a smaller amount of file descriptors +# or handles that can be polled in one operation, the server would then poll +# several smaller groups until it handles all the connections it tracks. +# With a large amount of connections this may however impact the delays between +# processing loops, and time before an incoming message is seen and processed. # ======================================================================= # CERTFILE diff --git a/conf/upsstats.html.sample.in b/conf/upsstats.html.sample.in index 01b87e3d7b..9d9c007d9f 100644 --- a/conf/upsstats.html.sample.in +++ b/conf/upsstats.html.sample.in @@ -41,7 +41,6 @@ th, td{padding:0.5ex;} .t2{background:#0f0;} -@REFRESH@ diff --git a/configure.ac b/configure.ac index 3265d7936e..f289775115 100644 --- a/configure.ac +++ b/configure.ac @@ -317,7 +317,7 @@ NUT_ARG_WITH_EXPAND_DEFAULT_HELP_SINGLEQUOTE([confdir-examples], [DIRPATH], [Com dnl --------------------------------------------------------------------- dnl GNU and BSD make are okay with the syntax, but Sun make/dmake are not: -AC_MSG_CHECKING([whether this make implementation supports export VAR=VAL syntax]) +AC_MSG_CHECKING([whether this make implementation supports 'export VAR=VAL' syntax]) dnl # using printf formatting for some funniner shells out there nut_am_output="`printf 'export VAR=VAL\ntest:\n\t@echo \"VAR=%s%sVAR%s\"\n' '\$' '(' ')' | ${MAKE-make} -f - test`" nut_am_result="$?" @@ -330,6 +330,24 @@ AS_IF([test x"${nut_am_result}" = x0 -a x"${nut_am_output}" = x"VAR=VAL"], [ ]) AC_SUBST(NUT_AM_MAKE_CAN_EXPORT) +dnl --------------------------------------------------------------------- +dnl Some versions of BSD make (e.g. in NetBSD 11) may require this syntax +dnl in lieu of the more standard "+" prefix, but at least GNU make exploded +dnl with it, so we can not use it everywhere: +AC_MSG_CHECKING([whether this make implementation supports a .MAKE special source (pseudo-goal for sub-makes)]) +dnl # using printf formatting for some funniner shells out there +nut_am_output="`printf 'sub: .MAKE\n\t@printf \\\"test:\\\\n\\\\t@echo %s\\\\n\\\" | $(MAKE) -f - test\n' '\\\\\\\"Hello world\\\\\\\"' | ${MAKE-make} -f - sub`" +nut_am_result="$?" +AS_IF([test x"${nut_am_result}" = x0 -a x"${nut_am_output}" = x"Hello world"], [ + dotMAKE=".MAKE" + AC_MSG_RESULT(yes) +], [ + dotMAKE="" + AC_MSG_RESULT(no: got '${nut_am_output}') +]) +AC_SUBST(dotMAKE) + +dnl --------------------------------------------------------------------- dnl Some systems have older autotools without direct macro support for PKG_CONF* NUT_CHECK_PKGCONFIG @@ -393,8 +411,8 @@ test "${prefix}" = "NONE" && prefix="${ac_default_prefix}" test "${exec_prefix}" = "NONE" && exec_prefix='${prefix}' AS_CASE([x"${nut_with_confdir}"], - [yes], [AC_MSG_ERROR([--with-confdir should specify a path name or expansible expression])], - [/*|?:\*|?:/*|*/*|*'\'*], [ + [xyes], [AC_MSG_ERROR([--with-confdir should specify a path name or expansible expression])], + [x/*|x?":\\"*|x?:/*|x*/*|x*'\'*], [ AC_MSG_NOTICE([A non-trivial --with-confdir path was specified (${nut_with_confdir}); any --with-confdir-suffix (${nut_with_confdir_suffix}) or --sysconfdir (${sysconfdir}) values are disregarded]) ], [ RESULT_COMMENT="" @@ -1300,9 +1318,13 @@ AC_CHECK_HEADER([poll.h], [Define to 1 if you have .])]) SEMLIBS="" +nut_have_semaphore_h=no +nut_have_semaphore_unnamed=no +nut_have_semaphore_named=no AC_CHECK_HEADER([semaphore.h], [AC_DEFINE([HAVE_SEMAPHORE_H], [1], [Define to 1 if you have .]) + nut_have_semaphore_h=yes AC_LANG_PUSH([C]) myLIBS="${LIBS}" @@ -1339,6 +1361,7 @@ sem_destroy(&semaphore); [AC_DEFINE([HAVE_SEMAPHORE_UNNAMED], [1], [Define to 1 if you have with usable sem_t, sem_init() and sem_destroy() for unnamed semaphores.]) AC_MSG_RESULT([ok]) + nut_have_semaphore_unnamed=yes ], [AC_MSG_RESULT([no])] ) @@ -1363,6 +1386,7 @@ if (semaphore != SEM_FAILED) [AC_DEFINE([HAVE_SEMAPHORE_NAMED], [1], [Define to 1 if you have with usable sem_t, sem_open() and sem_close() for named semaphores.]) AC_MSG_RESULT([ok]) + nut_have_semaphore_named=yes ], [AC_MSG_RESULT([no])] ) @@ -1371,8 +1395,28 @@ if (semaphore != SEM_FAILED) AC_LANG_POP([C]) ] ) -AM_CONDITIONAL(HAVE_SEMAPHORE_LIBS, test -n "${SEMLIBS}") +AM_CONDITIONAL(HAVE_SEMAPHORE_LIBS, [test -n "${SEMLIBS}"]) +AS_IF([test -n "${SEMLIBS}" -o x"${nut_have_semaphore_h}" = xyes -o x"${nut_have_semaphore_unnamed}" = xyes -o x"${nut_have_semaphore_named}" = xyes], + [nut_have_semaphore_ability=yes], + [nut_have_semaphore_ability=no]) + +dnl ---------------------------------------------------------------------- +dnl Check for --with-threading request + +NUT_ARG_WITH([threading], + [If it is possible to parallelize some tools (e.g. nut-scanner), do so?], + [auto]) + +AS_CASE(["${nut_with_threading}"], + [""|yes], [AS_IF([test x"${nut_have_semaphore_ability}" = xyes], [], [AC_MSG_ERROR([pthread support was required but libraries not detected])])], + [auto],[AS_IF([test x"${nut_have_semaphore_ability}" = xyes], [nut_with_threading=yes], [nut_with_threading=no])], + [no], [], + [AC_MSG_ERROR([Unsupported value for --with-threading option: "${nut_with_threading}"])] +) +NUT_REPORT_FEATURE([Enable support for parallelization of some tools], [${nut_with_threading}], [${SEMLIBS}], + [WITH_THREADING], [Define to enable build with threading support]) +dnl ---------------------------------------------------------------------- AC_CHECK_FUNCS(cfsetispeed tcsendbreak) AC_CHECK_FUNCS(seteuid setsid getpassphrase) AC_CHECK_FUNCS(on_exit setlogmask) @@ -1618,6 +1662,24 @@ AS_IF([test x"${ac_cv_func_strdup}" = xyes], [AC_MSG_WARN([Required C library routine strdup not found; try adding -D_POSIX_C_SOURCE=200112L])] ) +AC_CACHE_CHECK([for %zu as PRIuSIZE], + [ac_cv_printfmt_zu], + [AX_RUN_OR_LINK_IFELSE( + [AC_LANG_PROGRAM([$CODE_STRINGINCL +#include +], + [[size_t n = 123; +char buf[64]; +snprintf(buf, sizeof(buf), "%zu", n); +return !strcmp(buf, "123"); +]])], + [ac_cv_printfmt_zu=yes], [ac_cv_printfmt_zu=no] + )]) +AS_IF([test x"${ac_cv_printfmt_zu}" = xyes], + [AC_DEFINE([HAVE_PRINTF_ZU], 1, [defined if standard library has, and C standard allows, the printf("%zu", size_t) support])], + [AC_MSG_WARN([Desired C library support for printf("%zu", size_t) not found; try adding -D_POSIX_C_SOURCE=200112L])] + ) + AC_CACHE_CHECK([for va_copy(dest,src)], [ac_cv_have_va_copy], [ @@ -2316,6 +2378,7 @@ AC_ARG_WITH(drivers, if test -z "${with_powerman}"; then with_powerman="yes"; fi if test -z "${with_modbus}"; then with_modbus="yes"; fi if test -z "${with_ipmi}"; then with_ipmi="yes"; fi + if test -z "${with_upower}"; then with_upower="yes"; fi dnl Platform-dependent snowflakes that are required or auto: if test -z "${with_gpio}"; then @@ -2353,6 +2416,7 @@ AC_ARG_WITH(drivers, if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi + if test -z "${with_upower}"; then with_upower="${withval}"; fi if test -z "${with_gpio}"; then with_gpio="${withval}"; fi if test -z "${with_linux_i2c}"; then with_linux_i2c="${withval}"; fi if test -z "${with_macosx_ups}"; then with_macosx_ups="${withval}"; fi @@ -2369,7 +2433,8 @@ AC_ARG_WITH(drivers, SERIAL_DRIVERLIST USB_LIBUSB_DRIVERLIST SERIAL_USB_DRIVERLIST SNMP_DRIVERLIST NEONXML_DRIVERLIST MACOSX_DRIVERLIST MODBUS_DRIVERLIST LINUX_I2C_DRIVERLIST - POWERMAN_DRIVERLIST IPMI_DRIVERLIST GPIO_DRIVERLIST" + POWERMAN_DRIVERLIST IPMI_DRIVERLIST GPIO_DRIVERLIST + UPOWER_DRIVERLIST" dnl Gets ONE Makefile assignment value get_drivers_makefile_value() ( @@ -2520,6 +2585,11 @@ AC_ARG_WITH(drivers, [AC_MSG_NOTICE([Requiring --with-gpio=yes for driver "$DRV"]) with_gpio=yes] )], + [UPOWER_DRIVERLIST], [ + AS_IF([test -z "${with_upower}"], + [AC_MSG_NOTICE([Requiring --with-upower=yes for driver "$DRV"]) + with_upower=yes] + )], [AC_MSG_WARN([Unhandled DRVLIST_NAME=$DRVLIST_NAME])] ) @@ -2553,7 +2623,7 @@ dnl check for --with-all (or --without-all, or --with-all=auto) flag AC_MSG_CHECKING(for --with-all) AC_ARG_WITH(all, - AS_HELP_STRING([--with-all], [enable serial, usb, snmp, neon, libxml2, ipmi, powerman, modbus, gpio (currently on Linux released after ~2018), linux_i2c (on Linux), macosx-ups (on MacOS), cgi, dev, avahi, nut-scanner, nutconf, dev-libnutconf, pynut, dmf, snmp_dmf]), + AS_HELP_STRING([--with-all], [enable serial, usb, snmp, neon, libxml2, ipmi, powerman, modbus, gpio (currently on Linux released after ~2018), linux_i2c (on Linux), upower, macosx-ups (on MacOS), cgi, dev, avahi, nut-scanner, nutconf, dev-libnutconf, pynut, dmf, snmp_dmf]), dnl ### Not forced: lua, dmf_lua, snmp_dmf_lua [ if test -n "${withval}"; then @@ -2601,6 +2671,7 @@ dnl if test -z "${with_snmp_dmf_lua}"; then with_snmp_dmf_lua="${withval}"; fi if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi + if test -z "${with_upower}"; then with_upower="${withval}"; fi if test -z "${with_dmf}"; then with_dmf="${withval}"; fi dnl Platform-dependent snowflakes that are required or auto: @@ -2694,6 +2765,7 @@ dnl Note that production drivers must conform to docs/nut-names.txt NUT_ARG_WITH([unmapped-data-points], [represent USB-HID and SNMP data points discovered during subdriver generation but not mapped to nut-names yet (no, yes, yes-if-not-DMF)], [no]) +dnl Note the final decision is made far below, after DMF option processing. dnl The NUT legacy option was --with-doc; however to simplify configuration dnl in some common packaging frameworks, we also allow --with-docs as @@ -2740,8 +2812,14 @@ DEFAULT_MAN_DIR_AS_BASE='m4nut_DEFAULT_MAN_DIR_AS_BASE' case "${target_os}" in solaris*|sunos*|SunOS*|illumos*) - dnl Note: this regards target OS standard layout + dnl Note: this regards target OS standard layout as documented in + dnl https://docs.oracle.com/cd/E23824_01/html/821-1451/gladp.html dnl but may not fit certain packaging projects + dnl FIXME https://github.com/networkupstools/nut/issue/3314 : + dnl If we have no tools or wish to build man pages, and would + dnl just deliver what we have in dist tarball (or otherwise), we + dnl must keep the original names and cross-links of files we copy + dnl (no section substitutions then!) DEFAULT_MAN_SECTION_CMD_SYS="1m" DEFAULT_MAN_DIR_AS_BASE="no" ;; @@ -2874,6 +2952,8 @@ dnl Platform-dependent drivers, currently their detection code is directly dnl spelled out in configure.ac NUT_ARG_WITH([macosx_ups], [build and install Mac OS X Power Sources meta-driver], [auto]) NUT_ARG_WITH([linux_i2c], [build and install i2c drivers], [auto]) +NUT_ARG_WITH([upower], [build and install UPower driver and nut-scanner support (requires GLib/GIO)], [auto]) +NUT_CHECK_LIBGLIB dnl A Python GUI client application for the sysadmin desktop dnl (not necessarily on the NUT server itself): @@ -3023,7 +3103,6 @@ NUT_REPORT_FEATURE([enable Avahi support], [${nut_with_avahi}], [], [WITH_AVAHI], [Define to enable Avahi support]) dnl ---------------------------------------------------------------------- - dnl checks related to --with-powerman dnl ${nut_with_powerman}: any value except "yes" or "no" is treated as "auto". @@ -3141,8 +3220,14 @@ if test "${nut_with_gpio}" != "no"; then fi dnl NOTE: m4 scriptlet also defines WITH_LIBGPIO_VERSION like 0x00020000 in config.h -NUT_REPORT_DRIVER([build GPIO driver (library v${GPIO_VERSION})], [${nut_with_gpio}], [${nut_gpio_lib}], +AS_IF([test x"${GPIO_VERSION}" = xnone], [ + REPORT_GPIO_VERSION="library version not detected" +],[ + REPORT_GPIO_VERSION="library v${GPIO_VERSION}" +]) +NUT_REPORT_DRIVER([build GPIO driver (${REPORT_GPIO_VERSION})], [${nut_with_gpio}], [${nut_gpio_lib}], [WITH_GPIO], [Define to enable GPIO support]) +unset REPORT_GPIO_VERSION dnl ---------------------------------------------------------------------- dnl The Mac OS X meta-driver looks at IOKit Power Sources keys managed by @@ -3165,6 +3250,31 @@ NUT_REPORT_DRIVER([build Mac OS X meta-driver], [${nut_with_macosx_ups}], [${nut_macosx_ups_lib}], [WITH_MACOSX], [Define to enable Mac OS X meta-driver]) +dnl ---------------------------------------------------------------------- +dnl checks related to --with-upower +dnl Check if we have detected libGLib / libGIO above (Required for the +dnl nut-upower driver and/or nut-scanner UPower support) +dnl NOTE: Do not confuse libglib{2} (GNOME) with glibc (part of compiler) +dnl ---------------------------------------------------------------------- + +AC_MSG_CHECKING([whether to build nut-upower driver and nut-scanner support]) +AS_IF([test "${nut_have_libglib}${nut_have_libgio}" = "yesyes"], [ + AS_CASE(["${nut_with_upower}"], + [yes|auto], [nut_with_upower=yes] + ) +], [ + AS_CASE(["${nut_with_upower}"], + [yes], [AC_MSG_ERROR([GLib/GIO not found but requested via --with-upower])], + [auto],[AC_MSG_WARN([GLib/GIO not found. The 'nut-upower' driver will not be built.])] + ) + nut_with_upower=no +]) + +AC_MSG_RESULT(${nut_with_upower}) +NUT_REPORT_DRIVER([build UPower driver and nut-scanner support], + [${nut_with_upower}], [], + [WITH_UPOWER], [Define to build UPower driver and nut-scanner support]) + dnl ---------------------------------------------------------------------- dnl checks related to --with_linux_i2c dnl Check for i2c header on Linux, used for ASEM UPS driver @@ -3398,7 +3508,7 @@ if test x"${nut_with_nut_monitor}" != xno ; then PYTHON2_TEST_MODULES="re,glob,codecs,gtk,gtk.glade,gobject,ConfigParser" PYTHON3_TEST_MODULES_QT5="re,glob,codecs,PyQt5.uic,configparser" PYTHON3_TEST_MODULES_QT6="re,glob,codecs,PyQt6.uic,configparser" - if test -n "${PYTHON2_VERSION_INFO_REPORT}" ; then + if test -n "${PYTHON2_VERSION_INFO_REPORT}" -a -n "${PYTHON2}" ; then AC_MSG_CHECKING([if we have Python2 prerequisites for NUT-Monitor desktop application]) if ${PYTHON2} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then @@ -3452,7 +3562,7 @@ if test x"${nut_with_nut_monitor}" != xno ; then fi fi - if test -n "${PYTHON3_VERSION_INFO_REPORT}" ; then + if test -n "${PYTHON3_VERSION_INFO_REPORT}" -a -n "${PYTHON3}" ; then AC_MSG_CHECKING([if we have Python3 Qt5 prerequisites for NUT-Monitor desktop application]) if ${PYTHON3} -c "import ${PYTHON3_TEST_MODULES_QT5}" 1>&5 2>&5 \ ; then @@ -3468,7 +3578,7 @@ if test x"${nut_with_nut_monitor}" != xno ; then fi fi - if test -n "${PYTHON3_VERSION_INFO_REPORT}" ; then + if test -n "${PYTHON3_VERSION_INFO_REPORT}" -a -n "${PYTHON3}" ; then AC_MSG_CHECKING([if we have Python3 Qt6 prerequisites for NUT-Monitor desktop application]) if ${PYTHON3} -c "import ${PYTHON3_TEST_MODULES_QT6}" 1>&5 2>&5 \ ; then @@ -3486,7 +3596,7 @@ if test x"${nut_with_nut_monitor}" != xno ; then dnl Fall back to default interpreter if test -z "${nut_with_nut_monitor_py2gtk2}${nut_with_nut_monitor_py3qt5}${nut_with_nut_monitor_py3qt6}" \ - && test -n "${PYTHON_VERSION_INFO_REPORT}" \ + && test -n "${PYTHON_VERSION_INFO_REPORT}" -a -n "${PYTHON}" \ && test x"${PYTHON_VERSION_INFO_REPORT}" != x"${PYTHON3_VERSION_INFO_REPORT}" \ && test x"${PYTHON_VERSION_INFO_REPORT}" != x"${PYTHON2_VERSION_INFO_REPORT}" \ ; then @@ -4049,6 +4159,11 @@ dnl not fail if we have no tools to generate it (so add to SKIP list). ( cd "$DOCTESTDIR" && ${A2X} --format manpage --destination-dir=. --xsltproc-opts="--nonet" "${abs_srcdir}"/docs/man/snmp-ups.txt && test -s snmp-ups.8 ) && can_build_doc_man=yes rm -f "${DOCTESTDIR}"/snmp-ups.8 fi + if test x"${can_build_doc_man}" != xyes && test x"${have_disted_doc_man}" = xyes && test x"${nut_doc_build_target_flag}" != xno ; then + dnl https://github.com/networkupstools/nut/issue/3314 + AC_MSG_NOTICE([Seems we can not build man pages, but have some pre-built ones...]) + dnl want_disted_doc_man=yes + fi can_install_doc_man=no if test "${want_disted_doc_man}" = yes && ( test "${have_disted_doc_man}" = yes || test "${have_disted_doc_man}" = yes-placeholder ) ; then AC_MSG_NOTICE([Requested, and can, install pre-built distributed copies of ${nut_doc_build_target_base} documentation]) @@ -4081,6 +4196,9 @@ dnl not fail if we have no tools to generate it (so add to SKIP list). if test "${have_disted_doc_man}" = yes || test "${have_disted_doc_man}" = yes-placeholder ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, but can install pre-built distributed copies]) DOC_INSTALL_DISTED_MANS="yes" + dnl Avoid rebuilding existing build products due to their timestamp dependencies; + dnl ignore "touch" errors due to e.g. read-only sources (distcheck, ISO image, etc.): + touch -r "${abs_srcdir}"/docs/man/Makefile.am "${abs_srcdir}"/docs/man/*.{1,2,3,4,5,6,7,8,9}* "${abs_srcdir}"/docs/man/*.{txt,xml,html,pdf} || true can_install_doc_man=yes else AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, and unable to install pre-built distributed copies because they are absent; will reflect on this below]) @@ -4403,10 +4521,10 @@ case "${nut_with_docs_changelog_start}" in dnl # For the FTY NUT fork, the interesting list is differences from common master GITLOG_START_POINT=master ], [ - GITLOG_START_POINT=v"`echo \"${NUT_SOURCE_GITREV_NUMERIC}\" | sed -e 's/^\(@<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\)@<:@^0-9@:>@*.*$/\1/'`" \ - && test x"${GITLOG_START_POINT}" != xv \ - || GITLOG_START_POINT="master" - ]) + GITLOG_START_POINT=v"`echo \"${NUT_SOURCE_GITREV_NUMERIC}\" | sed -e 's/^\(@<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\)@<:@^0-9@:>@*.*$/\1/'`" \ + && test x"${GITLOG_START_POINT}" != xv \ + || GITLOG_START_POINT="master" + ]) ]) ;; *) dnl # Else assume this is a git hash/tag/branch... @@ -7283,10 +7401,13 @@ AS_CASE([${target_os}], AC_MSG_NOTICE([FWIW, assuming ABS_TOP_SRCDIR="$ABS_TOP_SRCDIR" and ABS_TOP_BUILDDIR="$ABS_TOP_BUILDDIR"]) ]) -dnl Use these at best for tests (e.g. nutconf), not production code: +dnl Use these at best for tests (e.g. nutconf, NIT), not production code: AC_DEFINE_UNQUOTED([ABS_TOP_SRCDIR], ["${ABS_TOP_SRCDIR}"], [NUT source directory when the build was configured]) AC_DEFINE_UNQUOTED([ABS_TOP_BUILDDIR], ["${ABS_TOP_BUILDDIR}"], [NUT build directory when the build was configured]) +AC_SUBST(ABS_TOP_SRCDIR) +AC_SUBST(ABS_TOP_BUILDDIR) + dnl --------------------------------------------------------------------- AC_MSG_CHECKING([whether to install External API integration script: Enphase Monitor]) nut_with_extapi_enphase="no" @@ -7789,4 +7910,7 @@ AS_IF([test x"${theMAKE}" = x], [theMAKE="make"]) AC_MSG_NOTICE([==========================================================]) AC_MSG_NOTICE([Configuration complete: Run '$theMAKE' to build ${NUT_SOURCE_VERSION_REPORT} now.]) AC_MSG_NOTICE([You may use parallelism if supported by your hardware and 'make' implementation, e.g. '$theMAKE -j 8']) +AS_IF([test x"${dotMAKE}" = x.MAKE], [ +AC_MSG_NOTICE([WARNING: do not use (parallel) GNU make with this build configuration!]) +]) AC_MSG_NOTICE([==========================================================]) diff --git a/data/Makefile.am b/data/Makefile.am index b4e82af77e..7f79e1c9a4 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -18,13 +18,13 @@ check-local: # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -cmdvartab-spellchecked: cmdvartab Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +cmdvartab-spellchecked: cmdvartab Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="cmdvartab" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp diff --git a/data/driver.list.in b/data/driver.list.in index 95a09b2324..52888e6d16 100644 --- a/data/driver.list.in +++ b/data/driver.list.in @@ -741,6 +741,8 @@ "Liebert" "ups" "3" "PowerSure PSA 500" "USB" "usbhid-ups" "Liebert" "ups" "3" "PowerSure PSA500MT3-230U" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/601 "Liebert" "ups" "3" "PowerSure PSI 1440" "USB" "usbhid-ups" # http://www.emersonnetworkpower.com/en-US/Products/ACPower/Pages/LiebertPowerSurePSILineInteractiveUPS10003000VA.aspx +"Liebert" "ups" "3" "PSI5-800RT120" "USB" "usbhid-ups" # https://www.vertiv.com/en-us/products-catalog/critical-power/uninterruptible-power-supplies-ups/psi5-800rt120/ +"Liebert" "ups" "3" "PSI5-750MT120 (with IS-UNITY-DP SNMP card)" "" "snmp-ups" # https://github.com/networkupstools/nut/pull/3299 "LNXI" "pdu" "1" "Icebox" "10 outlets" "powerman-pdu (experimental)" @@ -1568,6 +1570,7 @@ "Tripp Lite" "ups" "3" "SU3000XLCD" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=744&txtModelID=5342 "Tripp Lite" "ups" "3" "SUINT1000RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3983 "Tripp Lite" "ups" "3" "SUINT1500RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2720 +"Tripp Lite" "ups" "3" "SUINT1500RTXL2UA" "Serial" "tripplitesu" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2720 "Tripp Lite" "ups" "3" "SUINT2200RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3970 "Tripp Lite" "ups" "3" "SUINT3000RTXL2U" "USB (protocol 4005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4523 diff --git a/data/htmlcgi/Makefile.am b/data/htmlcgi/Makefile.am index 072b8f1c43..29649c404a 100644 --- a/data/htmlcgi/Makefile.am +++ b/data/htmlcgi/Makefile.am @@ -17,20 +17,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/docs/Makefile.am b/docs/Makefile.am index b0021d5b7d..2ab7afe443 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -31,7 +31,7 @@ EXTRA_DIST = # generated once (can take a looong while), settled into place, and only then # we revisit them for html/pdf rendering (another long while) without randomly # confusing the system with new timestamps and needless regenerations later on. -all: +all: @dotMAKE@ @echo " DOC-FOLLOW-UP Basic 'make $@' in `pwd` is done, following up with 'make doc' to ensure complex document types" +@$(MAKE) $(AM_MAKEFLAGS) doc @@ -219,7 +219,7 @@ CHECK_LOCAL_TARGETS = @DOC_CHECK_LIST@ if WITH_SPELLCHECK CHECK_LOCAL_TARGETS += spellcheck endif WITH_SPELLCHECK -check-local: $(CHECK_LOCAL_TARGETS) +check-local: $(CHECK_LOCAL_TARGETS) @dotMAKE@ +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) check # Make sure sources are there for out-of-tree builds: @@ -227,7 +227,7 @@ all-local all-am-local \ $(DOC_BUILD_CHANGELOG_TEXT) $(DOC_BUILD_CHANGELOG_ADOC) \ @DOC_BUILD_LIST@ $(ASCIIDOC_PDF) $(ASCIIDOC_HTML_SINGLE) $(ASCIIDOC_HTML_CHUNKED): $(abs_top_builddir)/docs/.prep-src-docs -all-local: +all-local: @dotMAKE@ +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) all-optional # This list is defined by configure script choices and options: @@ -372,7 +372,7 @@ ChangeLog.html-contentchecked: exit 1 check-html-single: .check-html-single -.check-html-single: $(ASCIIDOC_HTML_SINGLE) Makefile +.check-html-single: $(ASCIIDOC_HTML_SINGLE) Makefile @dotMAKE@ +@FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(ASCIIDOC_HTML_SINGLE) ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ @@ -409,11 +409,11 @@ check-html-chunked: .check-html-chunked # NOTE; we rig it up with a DOCS_NO_MAN option to simplify parallel work # from top-level Makefile, while allowing legacy "cd docs && make" to # still do the right thing by default :) -check-man check-man-man all-man man-man all-html html-man: +check-man check-man-man all-man man-man all-html html-man: @dotMAKE@ +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile $@ -man: +man: @dotMAKE@ +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile all @@ -435,7 +435,7 @@ MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no # Work around some documents that have originally included # the asciidoc markup (use double-hash to avoid conversion). # The $< is okay here, it is used in a suffix rule below -.adoc.adoc-parsed: +.adoc.adoc-parsed: @dotMAKE@ +@if [ ! -s '$<' ] ; then \ echo " DOC-ASCIIDOC-GITHUB-LINKS STRANGE: input $< does not exist or is empty" >&2 ; \ $(MAKE) $(AM_MAKEFLAGS) '$<' ; \ @@ -479,7 +479,7 @@ $(top_builddir)/ChangeLog.adoc-parsed: $(top_builddir)/ChangeLog.adoc CLEANFILES += .ChangeLog.adoc-parsed.latest dummy: -$(top_builddir)/ChangeLog: dummy +$(top_builddir)/ChangeLog: dummy @dotMAKE@ @+echo " DOC-CHANGELOG-GENERATE-WRAPPER $@ : call parent Makefile to decide if (re-)generation is needed" \ && cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) $(@F) @@ -582,7 +582,7 @@ solaris-usb.html solaris-usb.chunked solaris-usb.pdf: solaris-usb.txt asciidoc.c # to look at is cause to run a recipe always). We define recipes outside # the suffix-based handling and require *them* for default target builds. ChangeLog.html ChangeLog.chunked ChangeLog.pdf: ChangeLog.txt .ChangeLog.adoc-parsed.latest asciidoc.conf -$(top_builddir)/docs/ChangeLog.html $(top_builddir)/docs/ChangeLog.chunked $(top_builddir)/docs/ChangeLog.pdf: ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf +$(top_builddir)/docs/ChangeLog.html $(top_builddir)/docs/ChangeLog.chunked $(top_builddir)/docs/ChangeLog.pdf: ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf @dotMAKE@ @+if [ -s '$(@F)' ] && [ x"`find '$(@F)' -newer '$(top_builddir)/ChangeLog.adoc-parsed'`" != x ] ; then \ echo " DOC-CHANGELOG-RENDER-WRAPPER SKIP: `pwd`/$(@F) already exists and is newer than ChangeLog.adoc-parsed" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ @@ -767,9 +767,9 @@ GENERATE_HTML_SINGLE = ( \ ) *.html: common.xsl xhtml.xsl -.txt-prepped.html: +.txt-prepped.html: @dotMAKE@ +@$(GENERATE_HTML_SINGLE) -.adoc-prepped.html: +.adoc-prepped.html: @dotMAKE@ +@$(GENERATE_HTML_SINGLE) # Note: extra age check here because *.chunked is a directory and not all @@ -966,22 +966,22 @@ SPELLCHECK_AUTO_ONE = ( \ || { RES=$$? ; touch '$@'.failed; exit $$RES; } \ ) -.txt.txt-spellchecked-auto: +.txt.txt-spellchecked-auto: @dotMAKE@ +@$(SPELLCHECK_AUTO_ONE) -.adoc.adoc-spellchecked-auto: +.adoc.adoc-spellchecked-auto: @dotMAKE@ +@$(SPELLCHECK_AUTO_ONE) -.in.in-spellchecked-auto: +.in.in-spellchecked-auto: @dotMAKE@ +@$(SPELLCHECK_AUTO_ONE) -.sample.sample-spellchecked-auto: +.sample.sample-spellchecked-auto: @dotMAKE@ +@$(SPELLCHECK_AUTO_ONE) -.conf.conf-spellchecked-auto: +.conf.conf-spellchecked-auto: @dotMAKE@ +@$(SPELLCHECK_AUTO_ONE) -spellcheck: +spellcheck: @dotMAKE@ @if test "$(SPELLCHECK_ENV_DEBUG)" = detailed ; then \ echo "ASPELL DEBUG : information about the setup follows:"; \ LANG=$(ASPELL_ENV_LANG); LC_ALL=$(ASPELL_ENV_LANG); export LANG; export LC_ALL; \ @@ -1070,7 +1070,7 @@ DISTCLEANFILES += $(NUT_SPELL_DICT).bak-pre-sorting $(NUT_SPELL_DICT).bak-pre-in # that their dictionary was updated and may need a Git recommit - either # if it did change, or if caller's SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes. SPELLCHECK_REPORT_MAYBE_UPDATED_DICT = no -spellcheck-interactive: +spellcheck-interactive: @dotMAKE@ @rm -f $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive || true @cp -pf $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive +@FAILED="" ; for docsrc in $(SPELLCHECK_SRC); do \ diff --git a/docs/acknowledgements.txt b/docs/acknowledgements.txt index 22c7bd2512..7be1be399e 100644 --- a/docs/acknowledgements.txt +++ b/docs/acknowledgements.txt @@ -161,6 +161,7 @@ document - Tank provided documentation on the Belkin/Delta protocol - Potrans provided a Fenton PowerPal 600 (P series) for development of the safenet driver. +- Tim Niemueller wrote nut-upower driver for UPower devices and scanner support. Older entries (before 2005) --------------------------- diff --git a/docs/config-prereqs.txt b/docs/config-prereqs.txt index 595520a364..0eb788b27c 100644 --- a/docs/config-prereqs.txt +++ b/docs/config-prereqs.txt @@ -65,7 +65,7 @@ environment, and build some tests: ------ :; mkdir -p nut && cd nut && \ - git clone https://github.com/networkupstools/nut/ -b fightwarn . + git clone https://github.com/networkupstools/nut/ -b master . :; ./autogen.sh && \ ./configure --with-doc=all --with-all --with-cgi && \ make all && make check && make spellcheck @@ -259,6 +259,7 @@ metadata about recently published package revisions: libssl-dev libnss3-dev \ augeas-tools libaugeas-dev augeas-lenses \ libusb-dev libusb-1.0-0-dev \ + libglib2.0-dev \ libi2c-dev \ libmodbus-dev \ libsnmp-dev \ @@ -324,16 +325,21 @@ for the `xmllint` tool: :; apt-get install python-pycparser || apt-get install python3-pycparser ------ -CentOS 6 and 7 -~~~~~~~~~~~~~~ +CentOS 6 and 7, Fedora 43 +~~~~~~~~~~~~~~~~~~~~~~~~~ CentOS is another popular baseline among Linux distributions, being a free derivative of the RedHat Linux, upon which many other distros are based as well. These systems typically use the RPM package manager, using directly `rpm` command, or `yum` or `dnf` front-ends depending on their generation. +In fact, most of the instructions directly apply to much newer distributions +like Fedora 43. + For CI farm container setup, prepared root filesystem archives from http://download.proxmox.com/images/system/ worked sufficiently well. +For Fedora, https://images.linuxcontainers.org/images/fedora/43/amd64/default +nightly image was used. Prepare CentOS repository mirrors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -399,6 +405,7 @@ enable it: :; yum install \ openssh-server openssh-clients +# On CentOS 6/7: :; chkconfig sshd on :; service sshd start @@ -411,8 +418,8 @@ NOTE: Below we request to install generic `python` per system defaults. You may request specifically `python2` or `python3` (or both): current NUT should be compatible with both (2.7+ at least). -NOTE: On CentOS, `libusb` means 0.1.x and `libusbx` means 1.x.x API version -(latter is not available for CentOS 6). +NOTE: On CentOS, `libusb` means 0.1.x (not available on modern Fedora), +and `libusbx` means 1.x.x API version (latter is not available for CentOS 6). NOTE: On CentOS, it seems that development against libi2c/smbus is not supported. Neither the suitable devel packages were found, nor i2c-based @@ -446,6 +453,8 @@ drivers in distro packaging of NUT. Resolution and doc PRs are welcome. # You can find a list of what is (pre-)installed with: # :; rpm -qa | grep -Ei 'perl|python' # Note that CentOS 6 includes python-2.6.x and does not serve newer versions +# For Fedora 43, further packages can be installed to test more: +# :; yum install python3-qt5 python3-setuptools # For spell-checking, highly recommended if you would propose pull requests: :; yum install \ @@ -456,6 +465,10 @@ drivers in distro packaging of NUT. Resolution and doc PRs are welcome. :; yum install \ asciidoc source-highlight python-pygments dblatex +# For PDF generation, you may need explicitly (at least on Fedora 43): +:; yum install \ + texlive 'tex(upquote.sty)' + # For CGI graph generation - massive packages (X11): :; yum install \ gd-devel @@ -465,19 +478,30 @@ drivers in distro packaging of NUT. Resolution and doc PRs are welcome. systemd-devel # NOTE: "libusbx" is the CentOS way of naming "libusb-1.0" (not in CentOS 6) -# vs. the older "libusb" as the package with "libusb-0.1" +# vs. the older "libusb" as the package with "libusb-0.1" (not in recent Fedora) +:; yum install \ + libusb-devel + +:; yum install \ + libusbx-devel + :; yum install \ cppunit-devel \ openssl-devel nss-devel \ augeas augeas-devel \ - libusb-devel libusbx-devel \ + glib2-devel \ i2c-tools \ libmodbus-devel \ net-snmp-devel \ - powerman-devel \ freeipmi-devel \ avahi-devel \ neon-devel + +# Not in recent Fedora releases: +:; yum install \ + powerman-devel + +# Not in CentOS, some present in Fedora: #?# is python-augeas needed? exists at least... #?# no (lib)i2c-devel ... #?# no (lib)ipmimonitoring-devel ... would "freeipmi-ipmidetectd" @@ -485,6 +509,11 @@ drivers in distro packaging of NUT. Resolution and doc PRs are welcome. #?# no (lib)gpio(d)-devel - starts with CentOS 8 (or extra repositories #?# for later minor releases of CentOS 7) +# In Fedora: +:; yum install \ + libi2c-devel \ + libgpiod-devel + # Some NUT code related to lua may be currently limited to lua-5.1 # or possibly 5.2; the former is default in CentOS 7 releases... :; yum install \ @@ -492,6 +521,14 @@ drivers in distro packaging of NUT. Resolution and doc PRs are welcome. :; yum install \ bash dash ksh + +# If available: +:; yum install \ + bash-completion + +# In Fedora: +:; yum install \ + busybox ------ NOTE: `busybox` is not packaged for CentOS 7 release; a static binary can @@ -509,8 +546,15 @@ other described environments by adding a symlink `/usr/lib/ccache`: ====== For Jenkins agents, also need to install JDK 17 or newer, which is not available for CentOS 6 nor 7 directly (in distribution packaging). -Alternative packaging, such as Temurin from the Adoptium project, is possible -(checked for at least CentOS 7), see + +In Fedora e.g.: +------ +:; yum install \ + java-21-openjdk-headless +------ + +Alternative packaging for older distros, such as Temurin from the Adoptium +project, is possible (checked for at least CentOS 7), see link:https://adoptium.net/installation/linux/#_centosrhelfedora_instructions[their instructions] for specific details. This may require updated library package versions as dependencies from the OS distribution, so you may also have to make @@ -578,6 +622,7 @@ Install tools and prerequisites for NUT: openssl nss \ augeas \ libusb \ + glib2 \ neon \ net-snmp \ freeipmi \ @@ -749,6 +794,7 @@ For NUT dependencies and build tools: :; slackpkg-install \ openssl openssl-solibs mozilla-nss \ libusb \ + glib2 \ net-snmp \ neon @@ -887,6 +933,8 @@ below. cppunit \ nss \ augeas \ + libusb \ + glib \ libmodbus \ neon \ net-snmp \ @@ -1068,6 +1116,7 @@ Finally, as `root` add the packages: openssl nss \ augeas \ libusb1 \ + glib2 \ net-snmp \ avahi @@ -1149,8 +1198,8 @@ build(s)), and use it to install the `pycparser` module, e.g.: :; pip3.6 install pycparser ------ -NetBSD 9.2 -~~~~~~~~~~ +NetBSD 9.2, 11.0 (Beta) +~~~~~~~~~~~~~~~~~~~~~~~ Instructions below assume that `pkgin` tool (pkg-src component to "install binary packages") is present on the system. Text below @@ -1202,6 +1251,11 @@ using the older tooling: :; pkg_add pkgin ---- +If you are using a test version that identifies like `11.0_BETA`, the +`PKG_PATH` definition above may include that but the package repository +might not serve the URL spelled as such. Trim it down to `11.0` manually +then. + For more details, see https://www.pkgsrc.org/#index1h1 and https://www.librebyte.net/en/cli-en/pkgin-a-netbsd-package-manager/ (the latter also provides a nice cheat-sheet about `pkgin` operations). @@ -1209,7 +1263,7 @@ https://www.librebyte.net/en/cli-en/pkgin-a-netbsd-package-manager/ [NOTE] ====== -On NetBSD 9.2 the `openpimi` and `net-snmp` packages complain that +On NetBSD 9.2 and 11 the `openpimi` and `net-snmp` packages complain that they require either OS ABI 9.0, or that `CHECK_OSABI=no` is set in a `pkg_install.conf`. Such file was not found in the test system, but can be created in `/etc/` and is honoured by `pkgin`: @@ -1220,6 +1274,10 @@ but can be created in `/etc/` and is honoured by `pkgin`: ---- ====== +Some packages include the software version in the name (so several +variants may be installed side by side), so instructions below vary +slightly depending on the OS distribution version: + ------ :; pkgin install \ git perl curl \ @@ -1227,12 +1285,26 @@ but can be created in `/etc/` and is honoured by `pkgin`: bmake gmake autoconf automake libltdl libtool \ cppcheck \ pkgconf \ - gcc7 gcc14 clang + clang + +# NOTE: ccache is installed and links configured for it below + +# NetBSD 9.2: +:; pkgin install \ + gcc7 gcc14 + +# NetBSD 11: +:; pkgin install \ + gcc15 # See comments below, python version and package naming depends on distro +# NetBSD 9.2: :; pkgin install \ python27 python39 python312 python313 +# NetBSD 11 (to cover the max testing scope with both python generations): +:; pkgin install python27 python314 + :; ( cd /usr/pkg/bin && ( ln -fs python2.7 python2 ; ln -fs python3.13 python3 ) ) # You can find a list of what is (pre-)installed with: # :; pkgin list | grep -Ei 'perl|python' @@ -1245,8 +1317,10 @@ but can be created in `/etc/` and is honoured by `pkgin`: # For Python2: # :; pkgin install py27-gtk2 # For Python3: +# * NetBSD 9.2: # :; pkgin install py312-qt5 py313-qt5 -# FIXME: Consider qt6 since 2025 +# * NetBSD 11: +# :; pkgin install py314-qt6 # For spell-checking, highly recommended if you would propose pull requests: :; pkgin install \ @@ -1270,6 +1344,7 @@ but can be created in `/etc/` and is honoured by `pkgin`: openssl nss \ augeas \ libusb libusb1 \ + glib2 \ neon \ net-snmp \ avahi @@ -1299,21 +1374,22 @@ It still seems to not work for NUT's expectations of FreeIPMI Recommended: For compatibility with common setups on other operating systems, can add dash-number suffixed symlinks to compiler tools (e.g. `gcc-7` beside the `gcc` installed by package) near the original -binaries and into `/usr/lib/ccache`: +binaries and into `/usr/lib/ccache`; use the numbers according to +what you do have installed: ------ :; ( cd /usr/pkg/bin && for TOOL in cpp gcc g++ ; do \ for VER in "7" "14" ; do \ - ln -fs "../gcc$VER/bin/$TOOL" "${TOOL}-${VER}" ; \ + ln -fs "../gcc${VER}/bin/${TOOL}" "${TOOL}-${VER}" ; \ done ; \ done ) # Note that the one delivered binary is `clang-13` (in originally described -# installation; `clang-18` after an update in 2025 which auto-removed the -# older version) and many (unnumbered) symlinks to it. For NUT CI style of +# NetBSD 9.x installation; `clang-18` after an update in 2025 which auto-removed +# the older version) and many (unnumbered) symlinks to it. For NUT CI style of # support for builds with many compilers, complete the known numbers: :; ( cd /usr/pkg/bin && for TOOL in clang-cpp clang++ ; do \ for VER in "-18" ; do \ - ln -s clang-18 "$TOOL$VER" ; \ + ln -s clang"${VER}" "${TOOL}${VER}" ; \ done ; \ done ) @@ -1321,12 +1397,12 @@ binaries and into `/usr/lib/ccache`: :; ( mkdir -p /usr/lib/ccache && cd /usr/lib/ccache && \ for TOOL in cpp gcc g++ clang ; do \ for VER in "" "-7" "-14" ; do \ - ln -s ../../pkg/bin/ccache "$TOOL$VER" ; \ + ln -s ../../pkg/bin/ccache "${TOOL}${VER}" ; \ done ; \ done ; \ for TOOL in clang clang++ clang-cpp ; do \ for VER in "" "-18" ; do \ - ln -s ../../pkg/bin/ccache "$TOOL$VER" ; \ + ln -s ../../pkg/bin/ccache "${TOOL}${VER}" ; \ done ; \ done ; \ ) @@ -1416,6 +1492,7 @@ Typical tooling would include: library/augeas python/augeas \ libusb-1 libusbugen system/library/usb/libusb \ system/header/header-usb driver/usb/ugen \ + glib2 \ libmodbus \ library/neon \ system/management/snmp/net-snmp \ @@ -1563,6 +1640,7 @@ site for setup details. developer/build/libtool library/libtool/libltdl \ build-essential ccache git developer/pkg-config \ runtime/perl \ + glib \ asciidoc \ libgd @@ -1780,7 +1858,7 @@ Currently known dependencies for basic build include: # Required: :; brew install ccache bash libtool binutils autoconf automake git m4 \ pkg-config aspell asciidoc docbook-xsl cppunit gd \ - libusb neon net-snmp \ + libusb glib neon net-snmp \ nss openssl \ libmodbus freeipmi powerman @@ -1992,7 +2070,8 @@ export PATH # This also pulls *-devel of several other projects: :; pacman -S --needed \ - mingw-w64-x86_64-neon libneon-devel + mingw-w64-x86_64-neon libneon-devel \ + mingw-w64-x86_64-glib2 # For DMF XML capability, also add libxml: :; pacman -S --needed \ diff --git a/docs/configure.txt b/docs/configure.txt index f17b9b54a0..ef8f1983b4 100644 --- a/docs/configure.txt +++ b/docs/configure.txt @@ -221,6 +221,20 @@ This allows to monitor numerous Power Supply Units (PSU) found on servers. Note that you need to install freeipmi (0.8.5 or higher, for nut-scanner; and 1.0.1 or higher, for nut-ipmipsu) development package or files. +UPower/D-Bus drivers +~~~~~~~~~~~~~~~~~~~~ + + --with-upower (default: auto-detect) + +Build and install the `nut-upower` driver. + +This allows to monitor UPS and battery devices managed by the UPower daemon +via D-Bus. This introduces a new category of drivers that talk to operating +system services to obtain power state information. + +Note that you need to install `glib-2.0` and `gio-2.0` development packages +or files. + I2C bus drivers ~~~~~~~~~~~~~~~ @@ -329,6 +343,16 @@ Many of the features depend on third-party libraries that are loosely linked at run-time using libltdl, and due to that, the build, delivery and use of the tool does not depend on *all* of them being available in the final deployment. + --with-threading (default: auto) + +Currently limited to linkman:nut-scanner[8] tool: require/allow build with +pthreads and/or semaphore support to parallelize the network and local port +scans, and scans of different media types. + +Some older systems' implementation of threading may be broken, so while we +can detect support, builds using it can fail in practice -- so this toggle +allows to keep building sequential-only code. + NUT Configuration tool ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/developers.txt b/docs/developers.txt index ed43d00a4a..d617ae18d7 100644 --- a/docs/developers.txt +++ b/docs/developers.txt @@ -337,7 +337,8 @@ locations can be wiped by a careless `git clean -fdX`. You are advised to explore configuring your IDE to store project configurations outside the source codebase location, or to track such subdirectories as `nbproject` or `nb-cache` or `.idea` as a separate Git repository (not necessarily a -submodule of NUT nor really diligently tracked) to avoid such surprises. +submodule of NUT nor really diligently tracked) to avoid such surprises, +e.g. `(cd nbproject && git init .)` can help. IDE notes on Windows ~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/download.txt b/docs/download.txt index a1357f85de..74e1cb8155 100644 --- a/docs/download.txt +++ b/docs/download.txt @@ -79,9 +79,13 @@ workspace to try subsequent iterations), although the latter are now also available for development iterations. See the live Wiki article on -https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests -for latest suggestions for building, testing and installing the latest -NUT code base. +link:https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests[Building +NUT for in-place upgrades or non-disruptive tests] +for the most up-to-date suggestions for building, testing and installing +the latest (or experimental) revisions of the NUT code base, and +link:https://github.com/networkupstools/nut/wiki/Finding-recent-development-iteration-artifacts[Finding +recent development iteration artifacts] about fetching the results of +the hard work done by the NUT CI farm. Code repository ^^^^^^^^^^^^^^^ diff --git a/docs/images/nut-squared.svg b/docs/images/nut-squared.svg new file mode 100644 index 0000000000..84c1dcd2c9 --- /dev/null +++ b/docs/images/nut-squared.svg @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/docs/maintainer-guide.txt b/docs/maintainer-guide.txt index e059fbfe95..2fbbe4a3e3 100644 --- a/docs/maintainer-guide.txt +++ b/docs/maintainer-guide.txt @@ -164,9 +164,26 @@ symbol names and API versions, similar to what `GNUC` or `SUNW` libraries do. * bump the release identification (consider committing as one commit later on): ** see `docs/nut-versioning.adoc` for details about NUT SEMVER spec and practice +** revise `.github/workflows/08-PyNUTClient.yml` for fallback `TAG_NAME` naming +** revise `appveyor.yml` for branch naming +** revise `scripts/Windows/build-mingw-nut.sh` for fallback value of `VER_OPT` +** revise `scripts/obs/debian.changelog` (at least a dummy entry) +** revise `scripts/obs/nut.dsc` and `scripts/obs/nut.spec` for their `Version` + fields ** update the fallback `NUT_DEFAULT_VERSION` in `tools/gitlog2version.sh` to - (ex: `2.8.0`), and provide the `VERSION_FORCED` - and `VERSION_FORCED_SEMVER` files (to same effect but more explicitly and + (ex: `2.8.0`) +*** DOUBLE-CHECK that the `NUT_DEFAULT_VERSION` in `tools/gitlog2version.sh` + is an `X.Y.Z` triplet, without the fourth `.1` suffix, for the release! +*** Note that since NUT v2.8.3 this script dictates the version propagated by + the `configure` script, so direct changes of `AC_INIT` there are no longer + needed +** commit with a relevant release message, e.g.: ++ +---- +:; git commit -sm 'Update versions for release of NUT v2.8.0' +---- +** provide the `VERSION_FORCED` and `VERSION_FORCED_SEMVER` files (to same + effect as fallback in `tools/gitlog2version.sh` but more explicitly and visibly) in the local workspace to be added to the `dist` archive tarball file (DO NOT add them to git to avoid confusion later, or revert any such addition after the release -- still has a chance to confuse e.g. branches @@ -178,6 +195,8 @@ symbol names and API versions, similar to what `GNUC` or `SUNW` libraries do. :; git tag v2.8.3-rc7 :; NUT_VERSION_QUERY="UPDATE_FILE_GIT_RELEASE" ./tools/gitlog2version.sh + +# Output sample wrapped for readability: SEMVER=2.8.3; TRUNK='upstream/master'; BASE='735451f1f21556f2a7b8443053e8962c2184239f'; DESC='v2.8.2-2881+gbdade6241' => TAG='v2.8.2' + SUFFIX='-2881+gbdade6241+v2.8.3+rc7' => VER5='2.8.2.2878.3' => DESC5='2.8.2.2878.3-2881+gbdade6241+v2.8.3+rc7' @@ -212,19 +231,6 @@ VERSION_FORCED_SEMVER:NUT_VERSION_FORCED_SEMVER='2.8.3' # if file names in your top_srcdir are removed: :; ln .relver/* . ---- -*** DOUBLE-CHECK that the `NUT_DEFAULT_VERSION` in `tools/gitlog2version.sh` - is an `X.Y.Z` triplet, without the fourth `.1` suffix, for the release! -*** Note that since NUT v2.8.3 this script dictates the version propagated by - the `configure` script, so direct changes of `AC_INIT` there are no longer - needed -** revise `.github/workflows/PyNUTClient.yml` for fallback `TAG_NAME` naming -** revise `appveyor.yml` for branch naming -** revise `scripts/Windows/build-mingw-nut.sh` for fallback value of `VER_OPT` -** commit with a relevant release message, e.g.: -+ ----- -:; git commit -sm 'Update versions for release of NUT v2.8.0' ----- * last-minute update against possible master-branch changes (and be sure to apply the release-version changes described above to your local copy of diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index 86370afad0..5b1f74c678 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -113,7 +113,7 @@ BUILT_SOURCES = $(abs_top_builddir)/docs/man/.prep-src-docs all-optional # been provided by automake, since we want to do nothing in certain cases. # Ideally it would refuse "make all" in certain cases, but we can't override # the automake-generated rules in each make implementation we care for. -all-optional: $(abs_top_builddir)/docs/man/.prep-src-docs +all-optional: $(abs_top_builddir)/docs/man/.prep-src-docs @dotMAKE@ +@case "$(ALL_TGT)" in \ ""|" "|" "|" ") echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile: No format of man page rendering is enabled" ; exit 0 ;; \ *all-*) \ @@ -1483,6 +1483,38 @@ else !DOC_INSTALL_SELECTED_MANS_PROGS_BUILT LINKMAN_PAGES_DRIVERS += $(SRC_GPIO_PAGES) endif !DOC_INSTALL_SELECTED_MANS_PROGS_BUILT +# (--with-upower) +SRC_UPOWER_PAGES = nut-upower.txt +INST_MAN_UPOWER_PAGES = nut-upower.$(MAN_SECTION_CMD_SYS) +DIST_ALL_MAN_PAGES += $(INST_MAN_UPOWER_PAGES) + +if ! SOME_DRIVERS +if WITH_MANS +MAN_UPOWER_PAGES = $(INST_MAN_UPOWER_PAGES) +endif WITH_MANS + +if WITH_UPOWER +mansys_DATA += $(MAN_UPOWER_PAGES) +endif WITH_UPOWER +endif ! SOME_DRIVERS + +INST_HTML_UPOWER_MANS = \ + nut-upower.html +DIST_ALL_HTML_PAGES += $(INST_HTML_UPOWER_MANS) + +if ! SOME_DRIVERS +HTML_UPOWER_MANS = $(INST_HTML_UPOWER_MANS) +endif ! SOME_DRIVERS + +# FIXME? Refine for HTML etc.? +if DOC_INSTALL_SELECTED_MANS_PROGS_BUILT +if WITH_UPOWER +LINKMAN_PAGES_DRIVERS += $(SRC_UPOWER_PAGES) +endif WITH_UPOWER +else !DOC_INSTALL_SELECTED_MANS_PROGS_BUILT +LINKMAN_PAGES_DRIVERS += $(SRC_UPOWER_PAGES) +endif !DOC_INSTALL_SELECTED_MANS_PROGS_BUILT + # Summarize which pages we ultimately install: MAN_MANS = if WITH_MANS @@ -1507,7 +1539,8 @@ MAN_MANS += \ $(MAN_MACOSX_PAGES) \ $(MAN_MODBUS_PAGES) \ $(MAN_LINUX_I2C_PAGES) \ - $(MAN_GPIO_PAGES) + $(MAN_GPIO_PAGES) \ + $(MAN_UPOWER_PAGES) endif WITH_MANS SRC_DRIVERS_PAGES = \ @@ -1522,7 +1555,8 @@ SRC_DRIVERS_PAGES = \ $(SRC_MACOSX_PAGES) \ $(SRC_MODBUS_PAGES) \ $(SRC_LINUX_I2C_PAGES) \ - $(SRC_GPIO_PAGES) + $(SRC_GPIO_PAGES) \ + $(SRC_UPOWER_PAGES) if SOME_DRIVERS # (Legacy note) The list above probably came up empty in this case, so make sure @@ -1599,7 +1633,8 @@ HTML_MANS = \ $(HTML_MACOSX_MANS) \ $(HTML_MODBUS_MANS) \ $(HTML_LINUX_I2C_MANS) \ - $(HTML_GPIO_MANS) + $(HTML_GPIO_MANS) \ + $(HTML_UPOWER_MANS) # htmlmandir is set by autoconf/automake htmlman_DATA = @@ -2039,16 +2074,16 @@ endif !HAVE_ASCIIDOC # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *.txt-spellchecked: Makefile.am $(abs_top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.txt.txt-spellchecked: +.txt.txt-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SRC_ALL_PAGES)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # When building out-of-tree, be sure to have all asciidoc resources diff --git a/docs/man/hosts.conf.txt b/docs/man/hosts.conf.txt index 940329b871..9f57e657d4 100644 --- a/docs/man/hosts.conf.txt +++ b/docs/man/hosts.conf.txt @@ -40,6 +40,26 @@ The description must be one element, so if it has spaces, then it must be wrapped with quotes as shown above. The default hostname is "localhost". +*CUSTOM_TEMPLATE_LIST* 'filename':: +*CUSTOM_TEMPLATE_SINGLE* 'filename':: + +linkman:upsstats[8] allows to use custom HTML template files for some of +its outputs (JSON and "treemode" mark-ups are currently hard-coded in +the binary), which you can specify in the query string part of the +URI (in your `index.html` and/or added cells of `header.html`) as e.g. +------ +.../cgi-bin/upsstats.cgi?template_single=custom-s.htm&template_list=custom-l.htm +------ ++ +Specific file names for a specific role must be permitted with these +directives (can be repeated). File names must contain the `.htm` sub-string +and must be located directly in the NUT configuration directory (same as +default templates). If custom templates are used in the original request +URI, they will be automatically suffixed to generated links (primarily +`HOSTLINK`, but also just in case added to `TREELINK` and `TREELINK_JSON`, +see linkman:upsstats.html[5] for more details). + + SEE ALSO -------- diff --git a/docs/man/nut-scanner.txt b/docs/man/nut-scanner.txt index 8366e2bf23..9a28b51099 100644 --- a/docs/man/nut-scanner.txt +++ b/docs/man/nut-scanner.txt @@ -29,11 +29,12 @@ INSTALLATION *nut-scanner* is only built if libltdl (part of libtool development suite) is available. -Available scanning options (USB, SNMP, IPMI, ...) will vary according +Available scanning options (USB, SNMP, IPMI, UPower, ...) will vary according to the available compile-time and run-time dependencies. For example, if Net-SNMP is installed, thus providing libsnmp libraries (`*.so` or `*.dll`) and header files during compilation, and at least the library files on the -monitoring system, then SNMP discovery will be available. +monitoring system, then SNMP discovery will be available. Similarly, UPower +discovery requires GDBus/libgio libraries. OPTIONS ------- @@ -106,6 +107,9 @@ No IP address options are required or used. Scan NUT compatible power supplies available via IPMI on the current host, or over the network if IP address ranges are specified. +*-J* | *--upower_scan*:: +Scan UPower devices. Requires GDBus/libgio libraries to be available. + *-E* | *--eaton_serial* 'serial ports':: Scan Eaton devices (XCP and SHUT) available via serial bus on the current host. This option must be requested explicitly, even for a complete scan. @@ -363,6 +367,20 @@ on Windows): :; nut-scanner --eaton_serial 1-2 ---- +To scan for UPower devices: + +---- +:; nut-scanner -J + +[nutdev-upower1] + driver = "upower" + port = "/org/freedesktop/UPower/devices/ups_hiddev0" + vendor = "APC" + product = "Back-UPS ES 700G" + serial = "5B1234567890" + bus = "upower" +---- + SEE ALSO -------- diff --git a/docs/man/nut-upower.txt b/docs/man/nut-upower.txt new file mode 100644 index 0000000000..172a6fdfeb --- /dev/null +++ b/docs/man/nut-upower.txt @@ -0,0 +1,71 @@ +NUT-UPOWER(8) +============= + +NAME +---- +nut-upower - Driver for UPower devices via D-Bus + +SYNOPSIS +-------- +*nut-upower* -h + +*nut-upower* -a 'UPS_NAME' ['OPTIONS'] + +NOTE: This man page only documents the specific features of the +*nut-upower* driver. For information about the core driver, see +linkman:nutupsdrv[8]. + +DESCRIPTION +----------- +This driver allows the monitoring of power devices (UPS, batteries) that are +managed by the UPower daemon via the D-Bus system bus. + +It maps UPower properties (state, percentage, voltage, etc.) to standard NUT +variables, allowing NUT clients to monitor devices that are natively supported +by the OS desktop environment but not directly by other NUT drivers. + +EXTRA ARGUMENTS +--------------- +This driver supports the following optional settings in linkman:ups.conf[5]: + +*port*:: +The UPower Object Path of the device to monitor. + +If set to `auto` (the default), the driver will scan for the first UPower device +whose object path contains the string "ups_". + +If set to a specific path (e.g., `/org/freedesktop/UPower/devices/ups_hiddev0`), +the driver will attempt to monitor that specific device. + +*lowbatt*:: +The battery percentage threshold below which the `LB` (Low Battery) status +flag is set. The default value is 20.0. + +INSTALLATION +------------ +To use this driver, add a section to your *ups.conf*: + +---- +[myups] + driver = nut-upower + port = auto + lowbatt = 20 + desc = "Laptop Battery or generic UPS via UPower" +---- + +REQUIREMENTS +------------ +This driver requires the `upower` daemon to be running and accessible via the +D-Bus system bus. It also requires GLib 2.0 and GIO libraries. + +AUTHOR +------ +Tim Niemueller + +SEE ALSO +-------- +linkman:ups.conf[5], linkman:nutupsdrv[8], linkman:upsc[8] + +Internet Resources: +~~~~~~~~~~~~~~~~~~~ +The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ diff --git a/docs/man/nut.exe.txt b/docs/man/nut.exe.txt index ed4e233bc3..a9717a6976 100644 --- a/docs/man/nut.exe.txt +++ b/docs/man/nut.exe.txt @@ -99,6 +99,12 @@ Install as a Windows service called "Network UPS Tools". Does not start it. *-N*:: Run once in non-service mode (for troubleshooting). ++ +Since NUT v2.8.5, using `nut.exe -N` for testing and pressing 'Ctrl+C' should +cause the started daemons to be killed off. Previously they would linger and +e.g. preclude subsequent experiments with the service wrapper. Console close +events are ignored, so there is a way to indefinitely keep the daemons started +by the test-mode wrapper running (kill later if needed via Task Manager). *start*:: Install as a Windows service called "Network UPS Tools" (if not yet done), diff --git a/docs/man/nut.txt b/docs/man/nut.txt index e420389382..fa6a5926c1 100644 --- a/docs/man/nut.txt +++ b/docs/man/nut.txt @@ -370,7 +370,7 @@ to secure access to those files and their copies as well. include::index.txt[] -:!included-skip-title: +:included-skip-title!: /////////////// :leveloffset: 0 diff --git a/docs/man/tripplitesu.txt b/docs/man/tripplitesu.txt index a279a25827..ae2ec8f4d5 100644 --- a/docs/man/tripplitesu.txt +++ b/docs/man/tripplitesu.txt @@ -33,6 +33,15 @@ Set the low battery warning threshold in percent at which shutdown is initiated by linkman:upsmon[8]. By default, the UPS may not report low battery until there are only a few seconds left. Common values are around 25--30. +*command_delay*='milliseconds':: +Set a delay in milliseconds to be applied before each command sent to the UPS. +The default value is 0 (disabled). If experiencing intermittent communication +timeouts when multiple commands are sent in rapid succession, set this to +1000 (1 second) or adjust as needed. + +This delay helps prevent "read timeout" errors when the hardware buffer is +not ready to accept new commands immediately after completing the previous one. + AUTHOR ------ diff --git a/docs/man/ups.conf.txt b/docs/man/ups.conf.txt index d083b091af..9211df7121 100644 --- a/docs/man/ups.conf.txt +++ b/docs/man/ups.conf.txt @@ -183,8 +183,9 @@ or with device filesystems re-generated by an OS for every reboot. *debug_min* 'INTEGER':: -Optional. Specify a minimum debug level for all driver daemons, e.g. for -troubleshooting a deployment, without impacting foreground or background +Optional. Specify a minimum debug level for all driver daemons and +for the linkman:upsdrvctl[8] tool, e.g. for troubleshooting a deployment +without changing init scripts, without impacting foreground or background running mode directly. Command-line option `-D` can only increase this verbosity level. diff --git a/docs/man/upsd.conf.txt b/docs/man/upsd.conf.txt index a79355f656..f6d538e7c6 100644 --- a/docs/man/upsd.conf.txt +++ b/docs/man/upsd.conf.txt @@ -150,6 +150,12 @@ This defaults to maximum number allowed on your system. Each UPS, each `LISTEN` address and each client count as one connection. If the server runs out of connections, it will no longer accept new incoming client connections. Only set this if you know exactly what you're doing. ++ +Note that on some platforms there may be a smaller amount of file descriptors +or handles that can be polled in one operation, the server would then poll +several smaller groups until it handles all the connections it tracks. +With a large amount of connections this may however impact the delays between +processing loops, and time before an incoming message is seen and processed. *CERTFILE 'certificate file'*:: diff --git a/docs/man/upsdrvctl.txt b/docs/man/upsdrvctl.txt index cdd31deb77..dee0488f47 100644 --- a/docs/man/upsdrvctl.txt +++ b/docs/man/upsdrvctl.txt @@ -81,6 +81,11 @@ global section. *-D*:: Raise the debug level. Use this multiple times for additional details. +Alternatively the value can be set via +debug_min+ in global section of +linkman:ups.conf[5]. Note the global setting applies to both the tool +and a started driver; but another line in a driver's individual section +can override that with a larger or smaller value (including a `debug_min=0` +to disable tracing the driver by default). + Note that this does not preclude the `upsdrvctl` tool from exiting after its job is done (however an explicit *-F* option does). diff --git a/docs/man/upsstats.cgi.txt b/docs/man/upsstats.cgi.txt index b83fca8c13..b30a37a03e 100644 --- a/docs/man/upsstats.cgi.txt +++ b/docs/man/upsstats.cgi.txt @@ -48,9 +48,24 @@ The web page that is displayed is actually a template containing commands to `upsstats` which are replaced by status information. The default file used for the overview of devices is `upsstats.html`. +An alternate template may be provided by `&template_list=...` CGI +query option; relevant file must be allowed via `CUSTOM_TEMPLATE_LIST` +option in linkman:hosts.conf[5]. When monitoring a single UPS, the file displayed is `upsstats-single.html`. +An alternate template may be provided by `&template_single=...` CGI +query option; relevant file must be allowed via `CUSTOM_TEMPLATE_SINGLE` +option in linkman:hosts.conf[5]. + +Alternate templates must be structured similarly to default ones, +located in the same directory, and contain `.htm` in the file name. +You can specify in the query string part of the URI (for example, +in your local `index.html` and/or added cells of `header.html`) as e.g. + +------ +.../cgi-bin/upsstats.cgi?template_single=custom-s.html&template_list=custom-l.html +------ The format of these files, including the possible commands, is documented in linkman:upsstats.html[5]. @@ -83,7 +98,7 @@ parameter is also provided: In both modes, each UPS object includes: * *host*: The UPS identifier (e.g., "myups@localhost") -* *desc*: The host description from ``hosts.conf`` +* *desc*: The host description from `hosts.conf` * *status_raw*: The raw status string (e.g., "OL") * *status_parsed*: An array of human-readable status strings (e.g., ["Online"]) diff --git a/docs/man/upsstats.html.txt b/docs/man/upsstats.html.txt index a4376fcac9..e41aa4a948 100644 --- a/docs/man/upsstats.html.txt +++ b/docs/man/upsstats.html.txt @@ -244,9 +244,14 @@ Insert the META header magic for refreshing the page if that variable has been set by the browser. This needs to be in the HEAD section of the page. +*@STATUS separator@*:: *@STATUS@*:: Expand the abbreviations in the ups.status variable -- OL becomes -"On line", OB becomes "On battery", and so on. +"On line", OB becomes "On battery", and so on. Reported values are +separated by the specified optional separator (`
` if not specified), +which starts at the next character after the "STATUS" (e.g. +a `@STATUS @` directive might be used to avoid any separation, or +`@STATUS @` to separate by spaces. *@STATUSCOLOR@*:: Insert red, green, or yellow color triplets depending on the severity of diff --git a/docs/nut-versioning.adoc b/docs/nut-versioning.adoc index 28c85fc544..e632ecd6f6 100644 --- a/docs/nut-versioning.adoc +++ b/docs/nut-versioning.adoc @@ -463,8 +463,11 @@ Return sorted (via expansion) list of original semver strings (till end of args), in their original spelling (with leading zeroes, if present, not stripped away). -`semver-compare.sh [OPTS] {test|[} "SEMVER1" {-gt|-ge|-lt|-le|-eq|=|==|-ne|!=|<>|<|<=|>|>=} "SEMVER2"`:: -Shell-style syntax to compare two semver strings (via expanded variants). +`semver-compare.sh [OPTS] {test|[|[[} "SEMVER1" {-gt|>|-ge|>=|-lt|<|-le|<=|-eq|=|==|-ne|!=|<>} "SEMVER2" {]|]]}`:: +Relaxed shell-style syntax to compare two semver strings (via their expanded +variants). Introduced so this script can be just prefixed into existing +(alphanumeric-based) shell comparisons, or newly added with a human-readable +command-line interface. + Note that `--min-components` can play a role here (e.g. is `1.2.3` equal to `1.2.3.0.0`? You can specify whether and how many zeroes can be added diff --git a/docs/nut.dict b/docs/nut.dict index b9c8995c45..947121dd84 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3677 utf-8 +personal_ws-1.1 en 3705 utf-8 AAC AAS ABI @@ -241,6 +241,7 @@ Cygwin DATACABLE DATAPATH DBCF +DBUS DCE DCF DCO @@ -331,6 +332,7 @@ EE EEPROM EFI EG +EINVAL EL ELCD EMI @@ -345,6 +347,7 @@ EOLed EPEL EPERM EPFCLCD +EPIPE EPO EPS ESC @@ -352,6 +355,7 @@ ESS ESV ESXi ETIME +ETIMEDOUT EUROCASE EVeRr EXtreme @@ -431,11 +435,14 @@ FullLoad Fuß GC GCCVER +GDBus GES GETADDRINFO GETPID GID +GIO GITREV +GLib GND GNUMakefile GNUmakefile @@ -814,6 +821,7 @@ NONBLOCK NONUT NOP NOPARENT +NOSIGPIPE NOTALARM NOTBOOST NOTBYPASS @@ -855,6 +863,7 @@ Netman NetworkUPSTools Neus Niels +Niemueller Niklas Niro NixOS @@ -955,6 +964,7 @@ PPDnnn PPP PR PR'ed +PRIuSIZE PROGRA PROGS PROTVER @@ -1237,6 +1247,7 @@ SX SXI SXL SYMLINKDIR +SYSMAXCONN SafeNet Salicru Salvia @@ -1317,6 +1328,7 @@ SyntaxWarning Sysgration SyslogIdentifier SystemIO +SystemRoot Systeme Syu Szady @@ -1433,6 +1445,7 @@ UUU UUUU UX Ubuntu +Ugreen Ulf Ulfat Uncomment @@ -1471,6 +1484,7 @@ Valderen Vdc Velloso VendorID +Vertiv Viewpower Viewsonic Viktor @@ -1937,6 +1951,7 @@ datasheet datasize datastale dblatex +dbus dcd dcn ddk @@ -2158,6 +2173,7 @@ formatstring fosshost fp freebsd +freedesktop freeipmi freetype frob @@ -2210,6 +2226,7 @@ getval getvar gh gif +gio gitcache github gitignore @@ -2460,6 +2477,8 @@ libexecdir libexpat libfreeipmi libgd +libgio +libglib libgpgme libgpiod libhid @@ -2485,6 +2504,7 @@ libnutscan libpcre libpng libpowerman +libpthread libre libregex libs @@ -2850,6 +2870,7 @@ pF pacman pacstrap parallelizable +parallelize parallelized param parsability @@ -3010,6 +3031,7 @@ rc rcctl readline readonly +realpath realpower realups rebase @@ -3154,6 +3176,7 @@ setproctag setq setuid setupCommands +setuptools setvar setvar's sfr @@ -3245,6 +3268,7 @@ startup statepath stayoff stderr +stdint stdlib stdout stdupsv @@ -3351,6 +3375,8 @@ testime testtime testuser testvar +tex +texlive textproc tgcware tgt @@ -3453,6 +3479,7 @@ unstash updateinfo upexia upower +upquote upsBypassCurrent upsBypassPower upsBypassVoltage @@ -3671,6 +3698,7 @@ znapzendzetup zpool zroot zsh +zu zw zwfa zzz diff --git a/docs/packager-guide.txt b/docs/packager-guide.txt index cf44a1a46d..d45062b005 100644 --- a/docs/packager-guide.txt +++ b/docs/packager-guide.txt @@ -324,6 +324,14 @@ nut-gpio - Size: - Deps: +[[pkg-nut-upower]] +nut-upower +^^^^^^^^^^ +- Desc: (may be platform-dependent); maybe better `nut-dbus`? +- Files: +- Size: +- Deps: + [[pkg-nut-linux-i2c]] nut-linux-i2c ^^^^^^^^^^^^^ diff --git a/drivers/Makefile.am b/drivers/Makefile.am index 5089405b3e..e0a5478634 100644 --- a/drivers/Makefile.am +++ b/drivers/Makefile.am @@ -15,7 +15,7 @@ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonversion.la \ $(top_builddir)/common/libparseconf.la \ $(top_builddir)/common/libnutdmfsnmp.la \ -$(top_builddir)/clients/libupsclient.la: dummy +$(top_builddir)/clients/libupsclient.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Builds from root dir arrange stuff decently. Make sure parallel builds @@ -30,7 +30,7 @@ $(top_builddir)/common/libcommonversion.la: $(top_builddir)/include/nut_version. if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h @@ -175,6 +175,7 @@ LINUX_I2C_DRIVERLIST = asem pijuice hwmon_ina219 POWERMAN_DRIVERLIST = powerman-pdu IPMI_DRIVERLIST = nut-ipmipsu GPIO_DRIVERLIST = generic_gpio_libgpiod +UPOWER_DRIVERLIST = nut-upower # distribute all drivers, even ones that are not built by default EXTRA_PROGRAMS = $(SERIAL_DRIVERLIST) $(USB_DRIVERLIST) $(SERIAL_USB_DRIVERLIST) @@ -182,6 +183,7 @@ EXTRA_PROGRAMS += $(SNMP_DRIVERLIST) $(NEONXML_DRIVERLIST) $(MACOSX_DRIVERLIST) EXTRA_PROGRAMS += $(LINUX_I2C_DRIVERLIST) EXTRA_PROGRAMS += $(NUTSW_DRIVERLIST) EXTRA_PROGRAMS += $(GPIO_DRIVERLIST) +EXTRA_PROGRAMS += $(UPOWER_DRIVERLIST) # construct the list of drivers to build if SOME_DRIVERS @@ -372,6 +374,16 @@ mge_shut_SOURCES = usbhid-ups.c libshut.c libhid.c hidparser.c mge-hid.c mge_shut_CFLAGS = $(AM_CFLAGS) -DSHUT_MODE=1 mge_shut_LDADD = $(LDADD_DRIVERS_SERIAL) -lm +# UPower +if WITH_UPOWER +# Only build nut-upower if the set of libGLib/libGIO was found + driverexec_PROGRAMS += $(UPOWER_DRIVERLIST) + + nut_upower_SOURCES = nut-upower.c + nut_upower_LDADD = $(LDADD_DRIVERS) $(LIBGLIB_LIBS) $(LIBGIO_LIBS) + nut_upower_CFLAGS = $(AM_CFLAGS) $(LIBGLIB_CFLAGS) $(LIBGIO_CFLAGS) +endif WITH_UPOWER + # SNMP # Please keep the MIB table below sorted roughly alphabetically (incidentally # by vendor too) to ease maintenance and codebase fork resynchronisations @@ -390,6 +402,7 @@ snmp_ups_SOURCES = snmp-ups.c snmp-ups-helpers.c \ mge-mib.c \ netvision-mib.c \ raritan-pdu-mib.c raritan-px2-mib.c \ + vertiv-mib.c \ xppc-mib.c snmp_ups_CFLAGS = $(AM_CFLAGS) snmp_ups_CFLAGS += $(LIBNETSNMP_CFLAGS) @@ -563,7 +576,7 @@ dist_noinst_HEADERS = \ nutdrv_qx_voltronic-axpert.h nutdrv_qx_voltronic-qs.h nutdrv_qx_voltronic-qs-hex.h \ nutdrv_qx_zinto.h \ upsdrvquery.h \ - xppc-mib.h huawei-mib.h eaton-ats16-nmc-mib.h eaton-ats16-nm2-mib.h apc-ats-mib.h raritan-px2-mib.h eaton-ats30-mib.h \ + xppc-mib.h huawei-mib.h eaton-ats16-nmc-mib.h eaton-ats16-nm2-mib.h apc-ats-mib.h raritan-px2-mib.h vertiv-mib.h eaton-ats30-mib.h \ apc-pdu-mib.h apc-epdu-mib.h ecoflow-hid.h ever-hid.h eaton-pdu-genesis2-mib.h eaton-pdu-marlin-mib.h eaton-pdu-marlin-helpers.h \ eaton-pdu-pulizzi-mib.h eaton-pdu-revelation-mib.h emerson-avocent-pdu-mib.h eaton-ups-pwnm2-mib.h eaton-ups-pxg-mib.h legrand-hid.h \ hpe-pdu-mib.h hpe-pdu3-cis-mib.h powervar-hid.h delta_ups-hid.h generic_modbus.h salicru-hid.h adelsystem_cbi.h eaton-pdu-nlogic-mib.h ydn23.h diff --git a/drivers/adelsystem_cbi.c b/drivers/adelsystem_cbi.c index f7f3e904fd..c1254e5858 100644 --- a/drivers/adelsystem_cbi.c +++ b/drivers/adelsystem_cbi.c @@ -34,7 +34,7 @@ #endif #define DRIVER_NAME "NUT ADELSYSTEM DC-UPS CB/CBI driver (libmodbus link type: " NUT_MODBUS_LINKTYPE_STR ")" -#define DRIVER_VERSION "0.07" +#define DRIVER_VERSION "0.08" /* variables */ static modbus_t *mbctx = NULL; /* modbus memory context */ @@ -83,10 +83,6 @@ int register_write(modbus_t *mb, int addr, regtype_t type, void *data); /* instant command triggered by upsd */ int upscmd(const char *cmdname, const char *extra); -/* count the time elapsed since start */ -long time_elapsed(struct timeval *start); - - /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, @@ -790,31 +786,6 @@ int register_write(modbus_t *mb, int addr, regtype_t type, void *data) return rval; } -/* returns the time elapsed since start in milliseconds */ -long time_elapsed(struct timeval *start) -{ - long rval; - struct timeval end; - - rval = gettimeofday(&end, NULL); - if (rval < 0) { - upslog_with_errno(LOG_ERR, "time_elapsed"); - } - if (start->tv_usec < end.tv_usec) { - suseconds_t nsec = (end.tv_usec - start->tv_usec) / 1000000 + 1; - end.tv_usec -= 1000000 * nsec; - end.tv_sec += nsec; - } - if (start->tv_usec - end.tv_usec > 1000000) { - suseconds_t nsec = (start->tv_usec - end.tv_usec) / 1000000; - end.tv_usec += 1000000 * nsec; - end.tv_sec -= nsec; - } - rval = (end.tv_sec - start->tv_sec) * 1000 + (end.tv_usec - start->tv_usec) / 1000; - - return rval; -} - /* instant command triggered by upsd */ int upscmd(const char *cmdname, const char *extra) { @@ -861,7 +832,7 @@ int upscmd(const char *cmdname, const char *extra) } /* wait for an increasing time interval before sending shutdown command */ - while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt)); + while ((etime = elapsed_since_timeval(&start)) < ( FSD_REPEAT_INTRV / cnt)); upsdebugx(2, "ERROR: load.off failed, wait for %lims, retries left: %d", etime, cnt - 1); cnt--; } @@ -1336,7 +1307,7 @@ modbus_t *modbus_new(const char *port) upslogx(LOG_ERR, "modbus_new_rtu: Unable to open serial port context"); } } else if ((sp = strchr(port, ':')) != NULL) { - char *tcp_port = xmalloc(sizeof(sp)); + char *tcp_port = (char*)xmalloc(sizeof(sp)); strncpy(tcp_port, sp + 1, sizeof(sp)); *sp = '\0'; mb = modbus_new_tcp(port, (int)strtoul(tcp_port, NULL, 10)); diff --git a/drivers/adelsystem_cbi.h b/drivers/adelsystem_cbi.h index 5551414d03..275c44b3b0 100644 --- a/drivers/adelsystem_cbi.h +++ b/drivers/adelsystem_cbi.h @@ -257,14 +257,14 @@ typedef struct alrm_ar alrm_ar_t; static inline alrm_ar_t *alloc_alrm_ar(int as, size_t extra) { - alrm_ar_t *ret = xcalloc(1, sizeof(alrm_t) + extra); + alrm_ar_t *ret = (alrm_ar_t*)xcalloc(1, sizeof(alrm_t) + extra); if (ret) { - memcpy(ret, - &(alrm_ar_t const) { - .alrm_c = as - }, - sizeof(alrm_ar_t) - ); + memcpy(ret, + &(alrm_ar_t const) { + .alrm_c = as + }, + sizeof(alrm_ar_t) + ); } return ret; } diff --git a/drivers/al175.c b/drivers/al175.c index 5ea80e5689..77f8e8e2ea 100644 --- a/drivers/al175.c +++ b/drivers/al175.c @@ -118,7 +118,7 @@ static raw_data_t raw_xmalloc(size_t size) { raw_data_t data; - data.buf = xmalloc(size); + data.buf = (byte_t *)xmalloc(size); data.buf_size = size; data.begin = data.buf; @@ -253,14 +253,14 @@ static void reverse_bits(byte_t *buf, size_t count) while (count!=0) { x = *buf; - x = (byte_t)( (x & 0x80) >> 7 ) | - (byte_t)( (x & 0x40) >> 5 ) | - (byte_t)( (x & 0x20) >> 3 ) | - (byte_t)( (x & 0x10) >> 1 ) | - (byte_t)( (x & 0x08) << 1 ) | - (byte_t)( (x & 0x04) << 3 ) | - (byte_t)( (x & 0x02) << 5 ) | - (byte_t)( (x & 0x01) << 7 ); + x = (byte_t)( (x & 0x80) >> 7 ) + | (byte_t)( (x & 0x40) >> 5 ) + | (byte_t)( (x & 0x20) >> 3 ) + | (byte_t)( (x & 0x10) >> 1 ) + | (byte_t)( (x & 0x08) << 1 ) + | (byte_t)( (x & 0x04) << 3 ) + | (byte_t)( (x & 0x02) << 5 ) + | (byte_t)( (x & 0x01) << 7 ); *buf = x; ++buf; @@ -327,7 +327,7 @@ static void comli_prepare(raw_data_t *dest, const comli_head_t *h, const void *b /* it's caller responsibility to allocate enough space. - else it is a bug in the program */ + * else it is a bug in the program */ if ( (out+11+count+2) > (dest->buf + dest->buf_size) ) fatalx(EXIT_FAILURE, "too small dest in comli_prepare\n"); @@ -1003,9 +1003,11 @@ static int al175_read(byte_t *dst, size_t addr, size_t count) if (err==-1) return -1; - if ((rx_data.end - rx_data.begin) < 0 || - (size_t)(rx_data.end - rx_data.begin) != count) + if ((rx_data.end - rx_data.begin) < 0 + || (size_t)(rx_data.end - rx_data.begin) != count + ) { return -1; + } if ( (io.addr != addr) || (io.len != count) ) { upsdebugx(3, "%s: io_head mismatch\t(%" PRIxSIZE ",%" PRIxSIZE " != %" PRIxSIZE ",%" PRIxSIZE ")", @@ -1276,7 +1278,7 @@ void upsdrv_shutdown(void) /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); @@ -1284,7 +1286,7 @@ void upsdrv_shutdown(void) set_exit_flag(EF_EXIT_FAILURE); /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ diff --git a/drivers/apc-hid.c b/drivers/apc-hid.c index 6f1826d725..da34dba7eb 100644 --- a/drivers/apc-hid.c +++ b/drivers/apc-hid.c @@ -42,7 +42,7 @@ static char * tweak_max_report[] = { /* Back-UPS ES 700 does NOT overflow. */ /* Back-UPS ES 725 does NOT overflow. */ /* Back-UPS ES 525 overflows on ReportID 0x0c - (UPS.PowerSummary.RemainingCapacity). */ + * (UPS.PowerSummary.RemainingCapacity). */ "Back-UPS ES 525", /* Back-UPS CS 650 overflows on ReportID 0x46 */ "Back-UPS CS", @@ -330,144 +330,144 @@ static usage_tables_t apc_utab[] = { /* HID2NUT lookup table */ static hid_info_t apc_hid2nut[] = { - /* Battery page */ - { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, - { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, - { "battery.runtime", 0, 0, "UPS.Battery.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, - { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, - { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "battery.voltage", 0, 0, "UPS.Battery.Voltage", NULL, "%.1f", 0, NULL }, - { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.1f", 0, NULL }, - { "battery.voltage.nominal", 0, 0, "UPS.Battery.ConfigVoltage", NULL, "%.1f", 0, NULL }, - { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.1f", 0, NULL }, /* Back-UPS 500 */ - { "battery.temperature", 0, 0, "UPS.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, - { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, - { "battery.mfr.date", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.ManufacturerDate", NULL, "%s", HU_FLAG_SEMI_STATIC, date_conversion }, - { "battery.mfr.date", 0, 0, "UPS.PowerSummary.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Back-UPS 500, Back-UPS ES/CyberFort 500 */ - { "battery.date", 0, 0, "UPS.Battery.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Observed values: 0x0 on Back-UPS ES 650, 0x92501 on Back-UPS BF500 whose manufacture date was 2005/01/20 - this makes little sense but at least it's a valid date. */ - - /* UPS page */ - { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.1f", 0, NULL }, - { "ups.load", 0, 0, "UPS.PowerConverter.PercentLoad", NULL, "%.0f", 0, NULL }, - /* USB HID PDC defaults */ - { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - /* used by APC SmartUPS RM */ - { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.timer.start", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.shutdown", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - /* used by APC BackUPS ES */ - { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, - { "ups.timer.start", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.shutdown", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.timer.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - { "ups.test.result", 0, 0, "UPS.Battery.Test", NULL, "%s", 0, test_read_info }, - { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, - { "ups.mfr.date", 0, 0, "UPS.ManufacturerDate", NULL, "%s", 0, date_conversion }, - { "ups.mfr.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", 0, date_conversion }, /* Back-UPS 500 */ - { "ups.realpower.nominal", 0, 0, "UPS.PowerConverter.ConfigActivePower", NULL, "%.0f", 0, NULL }, - { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL }, - - /* the below one need to be discussed as we might need to complete - * the ups.test sub collection - * { "ups.test.panel", 0, 0, "UPS.APCPanelTest", NULL, "%.0f", 0, NULL }, */ - - /* Special case: ups.status & ups.alarm */ - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, - - { "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, /* Back-UPS 500 */ - { "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, /* Back-UPS 500 */ - { "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, /* Back-UPS 500 */ - { "BOOL", 0, 0, "UPS.PowerSummary.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, /* Back-UPS 500 */ - { "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, - { "BOOL", 0, 0, "UPS.PowerSummary.APCStatusFlag", NULL, NULL, HU_FLAG_QUICK_POLL, apcstatusflag_info }, /* APC Back-UPS LS 500 */ - - /* we map 2 times "input.transfer.reason" to be able to clear - * both vrange (voltage) and frange (frequency) */ - { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_vrange_info }, - { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_frange_info }, - - /* Input page */ - { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, - { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL }, - { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - /* used by APC BackUPS RS */ - { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, - { "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.APCSensitivity", NULL, "%s", HU_FLAG_SEMI_STATIC, apc_sensitivity_info }, - - /* Output page */ - { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, - { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.1f", 0, NULL }, - { "output.current", 0, 0, "UPS.Output.Current", NULL, "%.2f", 0, NULL }, - { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, - - /* Environmental page */ - { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe1.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, - { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe1.Humidity", NULL, "%.1f", 0, NULL }, + /* Battery page */ + { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, + { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, + { "battery.runtime", 0, 0, "UPS.Battery.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, + { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, + { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "battery.voltage", 0, 0, "UPS.Battery.Voltage", NULL, "%.1f", 0, NULL }, + { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.1f", 0, NULL }, + { "battery.voltage.nominal", 0, 0, "UPS.Battery.ConfigVoltage", NULL, "%.1f", 0, NULL }, + { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.1f", 0, NULL }, /* Back-UPS 500 */ + { "battery.temperature", 0, 0, "UPS.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, + { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, + { "battery.mfr.date", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.ManufacturerDate", NULL, "%s", HU_FLAG_SEMI_STATIC, date_conversion }, + { "battery.mfr.date", 0, 0, "UPS.PowerSummary.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Back-UPS 500, Back-UPS ES/CyberFort 500 */ + { "battery.date", 0, 0, "UPS.Battery.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Observed values: 0x0 on Back-UPS ES 650, 0x92501 on Back-UPS BF500 whose manufacture date was 2005/01/20 - this makes little sense but at least it's a valid date. */ + + /* UPS page */ + { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.1f", 0, NULL }, + { "ups.load", 0, 0, "UPS.PowerConverter.PercentLoad", NULL, "%.0f", 0, NULL }, + /* USB HID PDC defaults */ + { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + /* used by APC SmartUPS RM */ + { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.timer.start", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.shutdown", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + /* used by APC BackUPS ES */ + { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, + { "ups.timer.start", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.shutdown", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.timer.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, + { "ups.test.result", 0, 0, "UPS.Battery.Test", NULL, "%s", 0, test_read_info }, + { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, + { "ups.mfr.date", 0, 0, "UPS.ManufacturerDate", NULL, "%s", 0, date_conversion }, + { "ups.mfr.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", 0, date_conversion }, /* Back-UPS 500 */ + { "ups.realpower.nominal", 0, 0, "UPS.PowerConverter.ConfigActivePower", NULL, "%.0f", 0, NULL }, + { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL }, + + /* the below one need to be discussed as we might need to complete + * the ups.test sub collection + * { "ups.test.panel", 0, 0, "UPS.APCPanelTest", NULL, "%.0f", 0, NULL }, */ + + /* Special case: ups.status & ups.alarm */ + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, + + { "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, /* Back-UPS 500 */ + { "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, /* Back-UPS 500 */ + { "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, /* Back-UPS 500 */ + { "BOOL", 0, 0, "UPS.PowerSummary.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, /* Back-UPS 500 */ + { "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, + { "BOOL", 0, 0, "UPS.PowerSummary.APCStatusFlag", NULL, NULL, HU_FLAG_QUICK_POLL, apcstatusflag_info }, /* APC Back-UPS LS 500 */ + + /* we map 2 times "input.transfer.reason" to be able to clear + * both vrange (voltage) and frange (frequency) */ + { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_vrange_info }, + { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_frange_info }, + + /* Input page */ + { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, + { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL }, + { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + /* used by APC BackUPS RS */ + { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, + { "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.APCSensitivity", NULL, "%s", HU_FLAG_SEMI_STATIC, apc_sensitivity_info }, + + /* Output page */ + { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, + { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.1f", 0, NULL }, + { "output.current", 0, 0, "UPS.Output.Current", NULL, "%.2f", 0, NULL }, + { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, + + /* Environmental page */ + { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe1.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, + { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe1.Humidity", NULL, "%.1f", 0, NULL }, /* - { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe2.Temperature", NULL, "%.1f", 0, kelvin_celsius_conversion }, - { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe2.Humidity", NULL, "%.1f", 0, NULL }, + { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe2.Temperature", NULL, "%.1f", 0, kelvin_celsius_conversion }, + { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe2.Humidity", NULL, "%.1f", 0, NULL }, */ - /* instant commands. */ - /* test.* split into subset while waiting for extradata support - * ie: test.battery.start quick - */ - { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, - { "test.battery.start.quick", 0, 0, "UPS.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ - { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, - { "test.battery.start.deep", 0, 0, "UPS.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ - { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, - { "test.battery.stop", 0, 0, "UPS.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ - { "test.panel.start", 0, 0, "UPS.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, - { "test.panel.stop", 0, 0, "UPS.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, - { "test.panel.start", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ - { "test.panel.stop", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ - - /* USB HID PDC defaults */ - { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, - { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, - { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, - { "shutdown.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, - /* used by APC SmartUPS RM */ - { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, - { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, - { "shutdown.stop", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, - { "shutdown.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, - /* used by APC BackUPS ES */ - { "load.off.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, - { "load.on.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, - { "shutdown.stop", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, - { "shutdown.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, - /* used by APC BackUPS CS */ - { "shutdown.return", 0, 0, "UPS.Output.APCDelayBeforeReboot", NULL, "1", HU_TYPE_CMD, NULL }, - - { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, - { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, - { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, - { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, - { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, - - /* end of structure. */ - { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } + /* instant commands. */ + /* test.* split into subset while waiting for extradata support + * ie: test.battery.start quick + */ + { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, + { "test.battery.start.quick", 0, 0, "UPS.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ + { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, + { "test.battery.start.deep", 0, 0, "UPS.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ + { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, + { "test.battery.stop", 0, 0, "UPS.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ + { "test.panel.start", 0, 0, "UPS.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, + { "test.panel.stop", 0, 0, "UPS.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, + { "test.panel.start", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ + { "test.panel.stop", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ + + /* USB HID PDC defaults */ + { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, + { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, + { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, + { "shutdown.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, + /* used by APC SmartUPS RM */ + { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, + { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, + { "shutdown.stop", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, + { "shutdown.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, + /* used by APC BackUPS ES */ + { "load.off.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, + { "load.on.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, + { "shutdown.stop", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, + { "shutdown.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, + /* used by APC BackUPS CS */ + { "shutdown.return", 0, 0, "UPS.Output.APCDelayBeforeReboot", NULL, "1", HU_TYPE_CMD, NULL }, + + { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, + { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, + { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, + { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, + { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, + + /* end of structure. */ + { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *apc_format_model(HIDDevice_t *hd) { @@ -535,11 +535,11 @@ static int apc_claim(HIDDevice_t *hd) { * the report IDs may be different. */ static int apc_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) { - HIDData_t *pData; - int res = 0; + HIDData_t *pData; + int res = 0; - int vendorID = pDev->VendorID; - int productID = pDev->ProductID; + int vendorID = pDev->VendorID; + int productID = pDev->ProductID; if (vendorID != APC_VENDORID || productID != 0x0002) { return 0; } @@ -570,34 +570,34 @@ static int apc_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) { */ if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x33, USAGE_POW_HIGH_VOLTAGE_TRANSFER))) { - long hvt_logmin = pData->LogMin; - long hvt_logmax = pData->LogMax; + long hvt_logmin = pData->LogMin; + long hvt_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: highVoltageTransfer LogMin: %ld LogMax: %ld", hvt_logmin, hvt_logmax); if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x31, USAGE_POW_VOLTAGE))) { - long voltage_logmin = pData->LogMin; - long voltage_logmax = pData->LogMax; + long voltage_logmin = pData->LogMin; + long voltage_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: voltage LogMin: %ld LogMax: %ld", - voltage_logmin, voltage_logmax); + voltage_logmin, voltage_logmax); if (hvt_logmax > voltage_logmax) { pData->LogMin = 0; /* a reasonable lower limit for voltage */ pData->LogMax = hvt_logmax * 2; /* it may be smoking at this point */ upsdebugx(3, "Fixing Report Descriptor. Set voltage LogMin = %ld, LogMax = %ld", - pData->LogMin , pData->LogMax); + pData->LogMin , pData->LogMax); res = 1; } } if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x30, USAGE_POW_CONFIG_VOLTAGE))) { - long cvoltage_logmin = pData->LogMin; - long cvoltage_logmax = pData->LogMax; + long cvoltage_logmin = pData->LogMin; + long cvoltage_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: configVoltage LogMin: %ld LogMax: %ld", cvoltage_logmin, cvoltage_logmax); if (hvt_logmax > cvoltage_logmax) { pData->LogMax = 255; upsdebugx(3, "Fixing Report Descriptor. Set configVoltage LogMin = %ld, LogMax = %ld", - pData->LogMin , pData->LogMax); + pData->LogMin , pData->LogMax); res = 1; } } diff --git a/drivers/apc_modbus.c b/drivers/apc_modbus.c index 2dfc5f14f0..178aa65e7a 100644 --- a/drivers/apc_modbus.c +++ b/drivers/apc_modbus.c @@ -44,7 +44,7 @@ #endif #define DRIVER_NAME "NUT APC Modbus driver " DRIVER_NAME_NUT_MODBUS_HAS_USB_WITH_STR " USB support (libmodbus link type: " NUT_MODBUS_LINKTYPE_STR ")" -#define DRIVER_VERSION "0.17" +#define DRIVER_VERSION "0.18" #if defined NUT_MODBUS_HAS_USB @@ -834,46 +834,46 @@ typedef struct { /* Values that only need to be updated once on startup */ static apc_modbus_register_t apc_modbus_register_map_inventory[] = { - { "ups.firmware", 516, 8, APC_VT_STRING, 0, NULL, "%s", 0, NULL }, - { "ups.model", 532, 16, APC_VT_STRING, 0, NULL, "%s", 0, NULL }, /* also device.model, filled automatically */ - { "ups.serial", 564, 8, APC_VT_STRING, 0, NULL, "%s", 0, NULL }, /* also device.serial, filled automatically */ - { "ups.power.nominal", 588, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.0f", 0, &power_nominal }, - { "ups.realpower.nominal", 589, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.0f", 0, &realpower_nominal }, - { "ups.mfr.date", 591, 1, APC_VT_UINT, 0, &_apc_modbus_date_conversion, NULL, 0, NULL }, - { "battery.date", 595, 1, APC_VT_UINT, APC_VF_RW, &_apc_modbus_date_conversion, NULL, 0, NULL }, - { "ups.id", 596, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, - { "outlet.group.0.name", 604, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, - { "outlet.group.1.name", 612, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, - { "outlet.group.2.name", 620, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, - { "outlet.group.3.name", 628, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, - { NULL, 0, 0, 0, 0, NULL, NULL, 0.0f, NULL } + { "ups.firmware", 516, 8, APC_VT_STRING, APC_VF_NONE, NULL, "%s", 0, NULL }, + { "ups.model", 532, 16, APC_VT_STRING, APC_VF_NONE, NULL, "%s", 0, NULL }, /* also device.model, filled automatically */ + { "ups.serial", 564, 8, APC_VT_STRING, APC_VF_NONE, NULL, "%s", 0, NULL }, /* also device.serial, filled automatically */ + { "ups.power.nominal", 588, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.0f", 0, &power_nominal }, + { "ups.realpower.nominal", 589, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.0f", 0, &realpower_nominal }, + { "ups.mfr.date", 591, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_date_conversion, NULL, 0, NULL }, + { "battery.date", 595, 1, APC_VT_UINT, APC_VF_RW, &_apc_modbus_date_conversion, NULL, 0, NULL }, + { "ups.id", 596, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, + { "outlet.group.0.name", 604, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, + { "outlet.group.1.name", 612, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, + { "outlet.group.2.name", 620, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, + { "outlet.group.3.name", 628, 8, APC_VT_STRING, APC_VF_RW, NULL, "%s", 0, NULL }, + { NULL, 0, 0, APC_VT_INT, APC_VF_NONE, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_status[] = { - { "input.transfer.reason", 2, 1, APC_VT_UINT, 0, &_apc_modbus_status_change_cause_conversion, NULL, 0, NULL }, - { "ups.test.result", 23, 1, APC_VT_UINT, 0, &_apc_modbus_battery_test_status_conversion, NULL, 0, NULL }, - { NULL, 0, 0, 0, 0, NULL, NULL, 0.0f, NULL } + { "input.transfer.reason", 2, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_status_change_cause_conversion, NULL, 0, NULL }, + { "ups.test.result", 23, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_battery_test_status_conversion, NULL, 0, NULL }, + { NULL, 0, 0, APC_VT_INT, APC_VF_NONE, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_dynamic[] = { - { "battery.runtime", 128, 2, APC_VT_UINT, 0, NULL, "%" PRIu64, 0, NULL }, - { "battery.charge", 130, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 9, NULL }, - { "battery.voltage", 131, 1, APC_VT_INT, 0, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, - { "battery.date.maintenance", 133, 1, APC_VT_UINT, 0, &_apc_modbus_date_conversion, NULL, 0, NULL }, - { "battery.temperature", 135, 1, APC_VT_INT, 0, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, - { "ups.load", 136, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 8, NULL }, - { "ups.realpower", 136, 1, APC_VT_UINT, 0, &_apc_modbus_power_conversion, "%.2f", 8, &realpower_nominal }, - { "ups.power", 138, 1, APC_VT_UINT, 0, &_apc_modbus_power_conversion, "%.2f", 8, &power_nominal }, - { "output.current", 140, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, - { "output.voltage", 142, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 6, NULL }, - { "output.frequency", 144, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, - { "experimental.output.energy", 145, 2, APC_VT_UINT, 0, NULL, "%" PRIu64, 0, NULL }, - { "input.voltage", 151, 1, APC_VT_UINT, 0, &_apc_modbus_voltage_conversion, "%.2f", 6, NULL }, - { "ups.efficiency", 154, 1, APC_VT_INT, 0, &_apc_modbus_efficiency_conversion, "%.1f", 7, NULL }, - { "ups.timer.shutdown", 155, 1, APC_VT_INT, 0, NULL, "%" PRIi64, 0, NULL }, - { "ups.timer.start", 156, 1, APC_VT_INT, 0, NULL, "%" PRIi64, 0, NULL }, - { "ups.timer.reboot", 157, 2, APC_VT_INT, 0, NULL, "%" PRIi64, 0, NULL }, - { NULL, 0, 0, 0, 0, NULL, NULL, 0.0f, NULL } + { "battery.runtime", 128, 2, APC_VT_UINT, APC_VF_NONE, NULL, "%" PRIu64, 0, NULL }, + { "battery.charge", 130, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 9, NULL }, + { "battery.voltage", 131, 1, APC_VT_INT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, + { "battery.date.maintenance", 133, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_date_conversion, NULL, 0, NULL }, + { "battery.temperature", 135, 1, APC_VT_INT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, + { "ups.load", 136, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 8, NULL }, + { "ups.realpower", 136, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_power_conversion, "%.2f", 8, &realpower_nominal }, + { "ups.power", 138, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_power_conversion, "%.2f", 8, &power_nominal }, + { "output.current", 140, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, + { "output.voltage", 142, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 6, NULL }, + { "output.frequency", 144, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, + { "experimental.output.energy", 145, 2, APC_VT_UINT, APC_VF_NONE, NULL, "%" PRIu64, 0, NULL }, + { "input.voltage", 151, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_voltage_conversion, "%.2f", 6, NULL }, + { "ups.efficiency", 154, 1, APC_VT_INT, APC_VF_NONE, &_apc_modbus_efficiency_conversion, "%.1f", 7, NULL }, + { "ups.timer.shutdown", 155, 1, APC_VT_INT, APC_VF_NONE, NULL, "%" PRIi64, 0, NULL }, + { "ups.timer.start", 156, 1, APC_VT_INT, APC_VF_NONE, NULL, "%" PRIi64, 0, NULL }, + { "ups.timer.reboot", 157, 2, APC_VT_INT, APC_VF_NONE, NULL, "%" PRIi64, 0, NULL }, + { NULL, 0, 0, APC_VT_INT, APC_VF_NONE, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_static[] = { @@ -894,7 +894,7 @@ static apc_modbus_register_t apc_modbus_register_map_static[] = { { "outlet.group.3.delay.shutdown", 1044, 1, APC_VT_INT, APC_VF_RW, NULL, "%" PRIi64, 0, NULL }, { "outlet.group.3.delay.start", 1045, 1, APC_VT_INT, APC_VF_RW, NULL, "%" PRIi64, 0, NULL }, { "outlet.group.3.delay.reboot", 1046, 2, APC_VT_INT, APC_VF_RW, NULL, "%" PRIi64, 0, NULL }, - { NULL, 0, 0, 0, 0, NULL, NULL, 0.0f, NULL } + { NULL, 0, 0, APC_VT_INT, APC_VF_NONE, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t* apc_modbus_register_maps[] = { diff --git a/drivers/apcsmart-old.c b/drivers/apcsmart-old.c index 740a41e90c..dcae58d357 100644 --- a/drivers/apcsmart-old.c +++ b/drivers/apcsmart-old.c @@ -316,8 +316,8 @@ static void do_capabilities(void) upsdebugx(1, "APC - About to get capabilities string"); /* If we can do caps, then we need the Firmware revision which has - the locale descriptor as the last character (ugh) - */ + * the locale descriptor as the last character (ugh) + */ ptr = dstate_getinfo("ups.firmware"); if (ptr) upsloc = ptr[strlen(ptr) - 1]; @@ -340,8 +340,8 @@ static void do_capabilities(void) /* Early Smart-UPS, not as smart as later ones */ /* This should never happen since we only call - this if the REQ_CAPABILITIES command is supported - */ + * this if the REQ_CAPABILITIES command is supported + */ upslogx(LOG_ERR, "ERROR: APC cannot do capabilities but said it could!"); return; } @@ -494,8 +494,8 @@ static void oldapcsetup(void) update_status(); /* If we have come down this path then we dont do capabilities and - other shiny features - */ + * other shiny features + */ } static void protocol_verify(unsigned char cmd) @@ -645,9 +645,9 @@ static void getbaseinfo(void) upsdebugx(1, "APC - Attempting to find command set"); /* Initially we ask the UPS what commands it takes - If this fails we are going to need an alternate - strategy - we can deal with that if it happens - */ + * If this fails we are going to need an alternate + * strategy - we can deal with that if it happens + */ ret = ser_send_char(upsfd, APC_CMDSET); @@ -667,12 +667,12 @@ static void getbaseinfo(void) upsdebugx(1, "APC - Parsing out command set"); /* We have the version.alert.cmdchars string - NB the alert chars are normally in IGNCHARS - so will have been pretty much edited out. - You will need to change the ser_get_line above if - you want to check those out too.... - */ - alrts = strchr(temp, '.'); + * NB the alert chars are normally in IGNCHARS + * so will have been pretty much edited out. + * You will need to change the ser_get_line above if + * you want to check those out too.... + */ + alrts = strchr(temp, '.'); if (alrts == NULL) { fatalx(EXIT_FAILURE, "Unable to split APC version string"); } @@ -1016,11 +1016,12 @@ static void upsdrv_shutdown_simple(long status) static void upsdrv_shutdown_advanced(long status) { const char *strval; - const char deforder[] = {48 + SDIDX_S, - 48 + SDIDX_AT3N, - 48 + SDIDX_K, - 48 + SDIDX_Z, - 0}; + const char deforder[] = { + 48 + SDIDX_S, + 48 + SDIDX_AT3N, + 48 + SDIDX_K, + 48 + SDIDX_Z, + 0}; size_t i; long n; diff --git a/drivers/apcsmart-old.h b/drivers/apcsmart-old.h index 752c6a1273..723f33642f 100644 --- a/drivers/apcsmart-old.h +++ b/drivers/apcsmart-old.h @@ -191,13 +191,12 @@ static apc_vartab_t apc_vartab[] = { { "battery.alarm.threshold", 0, 'k' }, /* todo: - - I = alarm enable (hex field) - split into alarm.n.enable - J = alarm status (hex field) - split into alarm.n.status - - 0x15 = output voltage selection (APC_F_VOLT) - 0x5C = load power (APC_POLL|APC_F_PERCENT) - + * + * I = alarm enable (hex field) - split into alarm.n.enable + * J = alarm status (hex field) - split into alarm.n.status + * + * 0x15 = output voltage selection (APC_F_VOLT) + * 0x5C = load power (APC_POLL|APC_F_PERCENT) */ {NULL, 0, 0}, diff --git a/drivers/apcsmart.c b/drivers/apcsmart.c index e0471f3f8a..7cf11bd5d3 100644 --- a/drivers/apcsmart.c +++ b/drivers/apcsmart.c @@ -4,7 +4,7 @@ * Copyright (C) 1999 Russell Kroll * (C) 2000 Nigel Metheringham * (C) 2011+ Michal Soltys - * (C) 2024 Jim Klimov + * (C) 2024-2026 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ #include "apcsmart_tabs.h" #define DRIVER_NAME "APC Smart protocol driver" -#define DRIVER_VERSION "3.37" +#define DRIVER_VERSION "3.38" #ifdef WIN32 # ifndef ECANCELED @@ -95,10 +95,13 @@ static apc_vartab_t *vt_lookup_char(char cmdchar) { int i; - for (i = 0; apc_vartab[i].name != NULL; i++) - if ((apc_vartab[i].flags & APC_PRESENT) && - apc_vartab[i].cmd == cmdchar) + for (i = 0; apc_vartab[i].name != NULL; i++) { + if ((apc_vartab[i].flags & APC_PRESENT) + && apc_vartab[i].cmd == cmdchar + ) { return &apc_vartab[i]; + } + } return NULL; } @@ -705,7 +708,7 @@ static void apc_dstate_delinfo(apc_vartab_t *vt, int skip) return; } - if ( !(name = xmalloc(sizeof(char) * vt->nlen0)) ) { + if ( !(name = (char *)xmalloc(sizeof(char) * vt->nlen0)) ) { upslogx(LOG_ERR, "apc_dstate_delinfo() failed to allocate buffer"); return; } @@ -737,12 +740,12 @@ static void apc_dstate_setinfo(apc_vartab_t *vt, const char *upsval) return; } - if ( !(name = xmalloc(sizeof(char) * vt->nlen0)) ) { + if ( !(name = (char *)xmalloc(sizeof(char) * vt->nlen0)) ) { upslogx(LOG_ERR, "apc_dstate_setinfo() failed to allocate buffer"); return; } - if ( !(temp = xmalloc(sizeof(char) * (upsvallen + 2))) ) { + if ( !(temp = (char *)xmalloc(sizeof(char) * (upsvallen + 2))) ) { /* +2 seems like an overkill, but helps hush compiler warnings */ upslogx(LOG_ERR, "apc_dstate_setinfo() failed to allocate buffer"); free(name); @@ -1583,7 +1586,7 @@ static int sdcmd_AT(const void *str) { ssize_t ret; size_t cnt, padto, i; - const char *awd = str; + const char *awd = (const char *)str; char temp[APC_SBUF], *ptr; memset(temp, '\0', sizeof(temp)); @@ -2080,9 +2083,11 @@ static int instcmd(const char *cmd, const char *ext) } if (!(ct->flags & APC_PRESENT)) { - upslogx(LOG_INSTCMD_INVALID, "%s: command [%s %s] recognized, but" - " not supported by your UPS model", __func__, cmd, - ext ? ext : "\b"); + upslogx(LOG_INSTCMD_INVALID, + "%s: command [%s %s] recognized, but" + " not supported by your UPS model", + __func__, cmd, + ext ? ext : "\b"); return STAT_INSTCMD_INVALID; } @@ -2161,11 +2166,6 @@ void upsdrv_tweak_prognames(void) void upsdrv_help(void) { - printf( - "\nFor detailed information, please refer to:\n" - " - apcsmart(8)\n" - " - https://www.networkupstools.org/docs/man/apcsmart.html\n" - ); } void upsdrv_initups(void) diff --git a/drivers/apcsmart_tabs.c b/drivers/apcsmart_tabs.c index 0955e01dd5..06dd1d774f 100644 --- a/drivers/apcsmart_tabs.c +++ b/drivers/apcsmart_tabs.c @@ -73,13 +73,13 @@ apc_vartab_t apc_vartab[] = { { NULL, 0, 0, NULL, 0, 0 } /* todo: - - I = alarm enable (hex field) - split into alarm.n.enable - J = alarm status (hex field) - split into alarm.n.status - - 0x15 = output voltage selection (APC_F_VOLT) - 0x5C = load power (APC_POLL|APC_F_PERCENT) - + * + * I = alarm enable (hex field) - split into alarm.n.enable + * J = alarm status (hex field) - split into alarm.n.status + * + * 0x15 = output voltage selection (APC_F_VOLT) + * 0x5C = load power (APC_POLL|APC_F_PERCENT) + * */ }; diff --git a/drivers/arduino-hid.c b/drivers/arduino-hid.c index 4aa47c685d..8b556ebe63 100644 --- a/drivers/arduino-hid.c +++ b/drivers/arduino-hid.c @@ -36,7 +36,7 @@ #include "main.h" /* for getval() */ #include "usb-common.h" -#define ARDUINO_HID_VERSION "Arduino HID 0.21" +#define ARDUINO_HID_VERSION "Arduino HID 0.22" /* FIXME: experimental flag to be put in upsdrv_info */ /* Arduino */ @@ -103,16 +103,20 @@ static hid_info_t arduino_hid2nut[] = { { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "battery.runtime.low", 0, 0, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* Parse `*Capacity` values assuming `UPS.PowerSummary.CapacityMode` is set to 2, which means the `*Capacity` - units are percent. The Arduino HID Powerdevice library is capable of doing other modes, if the Sketch wants - to use them, but it appears most drivers just assume percent. - */ + * units are percent. The Arduino HID Powerdevice library is capable of doing other modes, if the Sketch wants + * to use them, but it appears most drivers just assume percent. + */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL}, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL}, + { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, + { "input.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Voltage", NULL, "%.1f", 0, NULL }, + { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", 0, NULL }, + /* USB HID PresentStatus Flags - TODO: Parse these into battery.charger.status - */ + * TODO: Parse these into battery.charger.status + */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info}, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info}, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info}, diff --git a/drivers/asem.c b/drivers/asem.c index 6b530db70f..ac0170cb9b 100644 --- a/drivers/asem.c +++ b/drivers/asem.c @@ -381,7 +381,7 @@ void upsdrv_shutdown(void) /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); @@ -389,7 +389,7 @@ void upsdrv_shutdown(void) set_exit_flag(EF_EXIT_FAILURE); /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ diff --git a/drivers/bcmxcp.c b/drivers/bcmxcp.c index efb108f3dd..dd00e00b88 100644 --- a/drivers/bcmxcp.c +++ b/drivers/bcmxcp.c @@ -1077,7 +1077,7 @@ void init_ext_vars(void) send_write_command(AUTHOR, 4); - sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ + sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_SET_CONF_COMMAND; cbuf[1] = PW_CONF_REQ; @@ -1087,67 +1087,79 @@ void init_ext_vars(void) length = command_write_sequence(cbuf, 4, answer); if (length <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); - if (length < 4) /* UPS doesn't have configurable vars */ + if (length < 4) /* UPS doesn't have configurable vars */ return; + for (index=3; index < length; index++) { switch(answer[index]) { - case PW_CONF_LOW_DEV_LIMIT: dstate_setinfo("input.transfer.boost.high", "%d", 0); - dstate_setflags("input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("input.transfer.boost.high", 3); - break; - - case PW_CONF_HIGH_DEV_LIMIT: dstate_setinfo("input.transfer.trim.low", "%d", 0); - dstate_setflags("input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("input.transfer.trim.low", 3); - break; - - case PW_CONF_LOW_BATT: dstate_setinfo("battery.runtime.low", "%d", 0); - dstate_setflags("battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("battery.runtime.low", 2); - break; - - case PW_CONF_BEEPER: dstate_addcmd("beeper.disable"); - dstate_addcmd("beeper.enable"); - dstate_addcmd("beeper.mute"); - break; - - case PW_CONF_RETURN_DELAY: dstate_setinfo("input.transfer.delay", "%d", 0); - dstate_setflags("input.transfer.delay", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("input.transfer.delay", 5); - break; - - case PW_CONF_RETURN_CAP: dstate_setinfo("battery.charge.restart", "%d", 0); - dstate_setflags("battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("battery.charge.restart", 3); - break; - - case PW_CONF_MAX_TEMP: dstate_setinfo("ambient.temperature.high", "%d", 0); - dstate_setflags("ambient.temperature.high", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("ambient.temperature.high", 3); - break; - - case PW_CONF_NOMINAL_OUT_VOLTAGE: dstate_setinfo("output.voltage.nominal", "%d", 0); - dstate_setflags("output.voltage.nominal", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("output.voltage.nominal", 3); - break; - - case PW_CONF_SLEEP_TH_LOAD: dstate_setinfo("battery.energysave.load", "%d", 0); - dstate_setflags("battery.energysave.load", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("battery.energysave.load", 3); - break; - - case PW_CONF_SLEEP_DELAY: dstate_setinfo("battery.energysave.delay", "%d", 0); - dstate_setflags("battery.energysave.delay", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("battery.energysave.delay", 3); - break; - - case PW_CONF_BATT_STRINGS: dstate_setinfo("battery.packs", "%d", 0); - dstate_setflags("battery.packs", ST_FLAG_RW | ST_FLAG_STRING); - dstate_setaux("battery.packs", 1); - break; + case PW_CONF_LOW_DEV_LIMIT: + dstate_setinfo("input.transfer.boost.high", "%d", 0); + dstate_setflags("input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("input.transfer.boost.high", 3); + break; + + case PW_CONF_HIGH_DEV_LIMIT: + dstate_setinfo("input.transfer.trim.low", "%d", 0); + dstate_setflags("input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("input.transfer.trim.low", 3); + break; + + case PW_CONF_LOW_BATT: + dstate_setinfo("battery.runtime.low", "%d", 0); + dstate_setflags("battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("battery.runtime.low", 2); + break; + + case PW_CONF_BEEPER: + dstate_addcmd("beeper.disable"); + dstate_addcmd("beeper.enable"); + dstate_addcmd("beeper.mute"); + break; + + case PW_CONF_RETURN_DELAY: + dstate_setinfo("input.transfer.delay", "%d", 0); + dstate_setflags("input.transfer.delay", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("input.transfer.delay", 5); + break; + + case PW_CONF_RETURN_CAP: + dstate_setinfo("battery.charge.restart", "%d", 0); + dstate_setflags("battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("battery.charge.restart", 3); + break; + + case PW_CONF_MAX_TEMP: + dstate_setinfo("ambient.temperature.high", "%d", 0); + dstate_setflags("ambient.temperature.high", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("ambient.temperature.high", 3); + break; + + case PW_CONF_NOMINAL_OUT_VOLTAGE: + dstate_setinfo("output.voltage.nominal", "%d", 0); + dstate_setflags("output.voltage.nominal", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("output.voltage.nominal", 3); + break; + + case PW_CONF_SLEEP_TH_LOAD: + dstate_setinfo("battery.energysave.load", "%d", 0); + dstate_setflags("battery.energysave.load", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("battery.energysave.load", 3); + break; + + case PW_CONF_SLEEP_DELAY: + dstate_setinfo("battery.energysave.delay", "%d", 0); + dstate_setflags("battery.energysave.delay", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("battery.energysave.delay", 3); + break; + + case PW_CONF_BATT_STRINGS: + dstate_setinfo("battery.packs", "%d", 0); + dstate_setflags("battery.packs", ST_FLAG_RW | ST_FLAG_STRING); + dstate_setaux("battery.packs", 1); + break; default: - break; + break; } } } @@ -1419,7 +1431,7 @@ void upsdrv_initinfo(void) /* No overflow checks, len value is byte-sized here */ buf = len * 11; - pTmp = xmalloc(buf+1); + pTmp = (char *)xmalloc(buf+1); pTmp[0] = 0; /* If there is one or more CPU number, get it */ @@ -1471,7 +1483,7 @@ void upsdrv_initinfo(void) len = answer[iIndex++]; /* Extract and reformat the model string */ - pTmp = xmalloc(len+15); + pTmp = (char *)xmalloc(len+15); snprintf(pTmp, len + 1, "%s", answer + iIndex); pTmp[len+1] = 0; iIndex += len; @@ -1583,7 +1595,8 @@ void upsdrv_initinfo(void) if (bcmxcp_command_map[PW_INIT_SYS_TEST].command_byte > 0) { init_system_test_capabilities(); } - /* Get information about configurable external variables*/ + + /* Get information about configurable external variables*/ init_ext_vars(); upsh.instcmd = instcmd; @@ -1615,8 +1628,10 @@ void upsdrv_updateinfo(void) /* Loop thru meter map, get all data UPS is willing to offer */ for (iIndex = 0; iIndex < BCMXCP_METER_MAP_MAX; iIndex++) { if (bcmxcp_meter_map[iIndex].format != 0 && bcmxcp_meter_map[iIndex].nut_entity != NULL) { - decode_meter_map_entry(answer + bcmxcp_meter_map[iIndex].meter_block_index, - bcmxcp_meter_map[iIndex].format, sValue); + decode_meter_map_entry( + answer + bcmxcp_meter_map[iIndex].meter_block_index, + bcmxcp_meter_map[iIndex].format, + sValue); /* Set result */ dstate_setinfo(bcmxcp_meter_map[iIndex].nut_entity, "%s", sValue); @@ -1913,20 +1928,20 @@ float calculate_ups_load(const unsigned char *answer) bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].format != 0) /* Max output VA */ { decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].meter_block_index, - bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].format, sValue); + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].format, sValue); output = atof(sValue); decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].meter_block_index, - bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].format, sValue); + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].format, sValue); max_output = atof(sValue); } else if (bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].format != 0 && /* Output A */ - bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format != 0) /* Max output A */ + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format != 0) /* Max output A */ { decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].meter_block_index, - bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].format, sValue); + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].format, sValue); output = atof(sValue); decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].meter_block_index, - bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format, sValue); + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format, sValue); max_output = atof(sValue); } if (max_output > 0.0) @@ -2040,10 +2055,10 @@ static int instcmd(const char *cmdname, const char *extra) return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Testing battery now"); /* Get test info from UPS ? - Should we wait for 50 sec and get the - answer from the test. - Or return, as we may lose line power - and need to do a shutdown.*/ + * Should we wait for 50 sec and get the + * answer from the test. + * Or return, as we may lose line power + * and need to do a shutdown.*/ } if (!strcasecmp(cmdname, "test.system.start")) { @@ -2073,7 +2088,7 @@ static int instcmd(const char *cmdname, const char *extra) return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Testing panel now"); } - if (!strcasecmp(cmdname, "beeper.disable") || !strcasecmp(cmdname, "beeper.enable") || !strcasecmp(cmdname, "beeper.mute")) { + if (!strcasecmp(cmdname, "beeper.disable") || !strcasecmp(cmdname, "beeper.enable") || !strcasecmp(cmdname, "beeper.mute")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ @@ -2387,7 +2402,7 @@ int setvar (const char *varname, const char *val) } - if (!strcasecmp(varname, "output.voltage.nominal")) { + if (!strcasecmp(varname, "output.voltage.nominal")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ diff --git a/drivers/bcmxcp_usb.c b/drivers/bcmxcp_usb.c index aed7f22842..8ab3c32d38 100644 --- a/drivers/bcmxcp_usb.c +++ b/drivers/bcmxcp_usb.c @@ -53,7 +53,7 @@ static int (*usb_set_descriptor)(usb_dev_handle *udev, unsigned char type, static int usb_set_powerware(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, size_t size) { assert (size < INT_MAX); - return usb_control_msg(udev, USB_ENDPOINT_OUT, USB_REQ_SET_DESCRIPTOR, (type << 8) + index, 0, buf, (int)size, 1000); + return usb_control_msg(udev, USB_ENDPOINT_OUT, USB_REQ_SET_DESCRIPTOR, (type << 8) + index, 0, (usb_ctrl_charbuf)buf, (int)size, 1000); } static void *powerware_ups(USBDevice_t *device) { @@ -69,7 +69,7 @@ static int usb_set_phoenixtec(usb_dev_handle *udev, unsigned char type, unsigned NUT_UNUSED_VARIABLE(index); NUT_UNUSED_VARIABLE(type); assert (size < INT_MAX); - return usb_control_msg(udev, 0x42, 0x0d, (0x00 << 8) + 0x0, 0, buf, (int)size, 1000); + return usb_control_msg(udev, 0x42, 0x0d, (0x00 << 8) + 0x0, 0, (usb_ctrl_charbuf)buf, (int)size, 1000); } static void *phoenixtec_ups(USBDevice_t *device) { @@ -233,7 +233,7 @@ ssize_t get_answer(unsigned char *data, unsigned char command) if ( my_buf[0] != PW_COMMAND_START_BYTE ) { upsdebugx(2, "get_answer: wrong header 0xab vs. %02x", my_buf[0]); /* Sometime we read something wrong. bad cables? bad ports? */ - my_buf = memchr(my_buf, PW_COMMAND_START_BYTE, bytes_read); + my_buf = (unsigned char*)memchr(my_buf, PW_COMMAND_START_BYTE, bytes_read); if (!my_buf) return -1; } @@ -302,7 +302,7 @@ ssize_t get_answer(unsigned char *data, unsigned char command) tail = (ssize_t)bytes_read; tail -= (ssize_t)(length + PW_HEADER_SIZE); if (tail > 0) - my_buf = memmove(&buf[0], my_buf + length + PW_HEADER_SIZE, (size_t)tail); + my_buf = (unsigned char*)memmove(&buf[0], my_buf + length + PW_HEADER_SIZE, (size_t)tail); else if (tail == 0) my_buf = &buf[0]; else { /* if (tail < 0) */ diff --git a/drivers/belkinunv.c b/drivers/belkinunv.c index a8a0519304..5c4b0d3d05 100644 --- a/drivers/belkinunv.c +++ b/drivers/belkinunv.c @@ -235,7 +235,7 @@ static void belkin_nut_open_tty(void) ser_set_speed(upsfd, device_path, B2400); /* must clear DTR and set RTS for 1 second for UPS to go to - "smart" mode */ + * "smart" mode */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); sleep(1); @@ -463,8 +463,8 @@ static TYPE_FD_SER belkin_std_open_tty(const char *device) { } /* set communications parameters: 2400 baud, 8 bits, 1 stop bit, no - parity, enable reading, hang up when done, ignore modem control - lines. */ + * parity, enable reading, hang up when done, ignore modem control + * lines. */ memset(&tios, 0, sizeof(tios)); tios.c_cflag = B2400 | CS8 | CREAD | HUPCL | CLOCAL; tios.c_cc[VMIN] = 1; @@ -476,16 +476,16 @@ static TYPE_FD_SER belkin_std_open_tty(const char *device) { } /* signal the UPS to enter "smart" mode. This is done by setting RTS - and dropping DTR for at least 0.25 seconds. RTS and DTR refer to - two specific pins in the 9-pin serial connector. Note: this must - be done for at least 0.25 seconds for the UPS to react. Ignore - any errors, as this probably means we are not on a "real" serial - port. */ + * and dropping DTR for at least 0.25 seconds. RTS and DTR refer to + * two specific pins in the 9-pin serial connector. Note: this must + * be done for at least 0.25 seconds for the UPS to react. Ignore + * any errors, as this probably means we are not on a "real" serial + * port. */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); /* flush both directions of serial port: throw away all data in - transit */ + * transit */ r = ser_flush_io(fd); if (r == -1) { close(fd); @@ -507,11 +507,11 @@ static TYPE_FD_SER belkin_std_open_tty(const char *device) { #endif /* WIN32 */ /* sleep at least 0.25 seconds for the UPS to wake up. Belkin's own - software sleeps 1 second, so that's what we do, too. */ + * software sleeps 1 second, so that's what we do, too. */ usleep(1000000); /* flush incoming data again, and read any remaining garbage - bytes. There should not be any. */ + * bytes. There should not be any. */ r = tcflush(fd, TCIFLUSH); if (r == -1) { close(fd); @@ -836,7 +836,7 @@ static int belkin_wait(void) } /* wait until the UPS is online and the battery level - is >= level */ + * is >= level */ bs = belkin_std_read_int(fd, REG_BATSTATUS); /* battery status */ if (bs==-1) { failcount++; @@ -1050,9 +1050,9 @@ void upsdrv_updateinfo(void) if (us & US_ACFAILURE) { status_set("ACFAIL"); /* AC failure, self-invented */ /* Note: this is not the same as "on battery", because this - flag makes sense even during a test, or when the load is - off. It simply reflects the status of utility power. A - "critical" situation should be OB && BL && ACFAIL. */ + * flag makes sense even during a test, or when the load is + * off. It simply reflects the status of utility power. A + * "critical" situation should be OB && BL && ACFAIL. */ } if (us & US_OVERLOAD) { status_set("OVER"); /* overload */ @@ -1175,20 +1175,20 @@ void upsdrv_shutdown(void) * general handling of other `sdcommands` here */ /* Note: this UPS cannot (apparently) be put into "soft - shutdown" mode; thus the -k option should not normally be - used; instead, a workaround using the "-x wait" option - should be used; see belkinunv(8) for details. - - In case somebody uses the -k option, the best we can do - here is a timed shutdown; this will wake up the attached - load after 10 minutes, come rain come shine. If AC power - does not return, this will probably lead to a few - shutdown/reboot cycles, until the batteries finally die and - possibly cause a system crash. - - Don't use this! Use the solution involving the "-x wait" - option instead, as suggested on the belkinunv(8) man - page. + * shutdown" mode; thus the -k option should not normally be + * used; instead, a workaround using the "-x wait" option + * should be used; see belkinunv(8) for details. + * + * In case somebody uses the -k option, the best we can do + * here is a timed shutdown; this will wake up the attached + * load after 10 minutes, come rain come shine. If AC power + * does not return, this will probably lead to a few + * shutdown/reboot cycles, until the batteries finally die and + * possibly cause a system crash. + * + * Don't use this! Use the solution involving the "-x wait" + * option instead, as suggested on the belkinunv(8) man + * page. */ upslogx(LOG_WARNING, @@ -1209,10 +1209,11 @@ int instcmd(const char *cmdname, const char *extra) upsdebug_INSTCMD_STARTING(cmdname, extra); /* We use test.failure.start to initiate a "deep battery test". - This does not really simulate a 'power failure', because we - won't start shutdown procedures during a test. - - We use test.battery.start to initiate a "10-second battery test". */ + * This does not really simulate a 'power failure', because we + * won't start shutdown procedures during a test. + * + * We use test.battery.start to initiate a "10-second battery test". + */ if (!strcasecmp(cmdname, "beeper.off")) { /* compatibility mode for old command */ @@ -1277,11 +1278,11 @@ int instcmd(const char *cmdname, const char *extra) if (!strcasecmp(cmdname, "shutdown.reboot")) { upslog_INSTCMD_POWERSTATE_CHANGE(cmdname, extra); /* restarttimer is in minutes, shutdowntimer is in - seconds. Still, restarttimer=1 is not safe, - because it might be decremented before - shutdowntimer is set, which would cause the UPS to - stay off. So we need restarttimer=2, which means, - the UPS will stay off between 60 and 120 seconds */ + * seconds. Still, restarttimer=1 is not safe, + * because it might be decremented before + * shutdowntimer is set, which would cause the UPS to + * stay off. So we need restarttimer=2, which means, + * the UPS will stay off between 60 and 120 seconds */ r = belkin_nut_write_int(REG_RESTARTTIMER, 2); /* 2 minutes */ r |= belkin_nut_write_int(REG_SHUTDOWNTIMER, 1); /* 1 second */ if (r == -1) upslogx(LOG_WARNING, "Command '%s' failed", cmdname); @@ -1387,9 +1388,9 @@ void upsdrv_makevartable(void) void upsdrv_initups(void) { /* If '-x wait' or '-x wait=' option given, branch into - standalone behavior. */ + * standalone behavior. */ if (getval("wait") || dstate_getinfo("driver.flag.wait")) { - exit(belkin_wait()); + exit(belkin_wait()); } belkin_nut_open_tty(); diff --git a/drivers/bestfcom.c b/drivers/bestfcom.c index 5608cca0b1..231b427c47 100644 --- a/drivers/bestfcom.c +++ b/drivers/bestfcom.c @@ -456,7 +456,7 @@ static void ups_sync(void) char buf[256]; /* A bit better sanity might be good here. As is, we expect the - human to observe the time being totally not a time. */ + * human to observe the time being totally not a time. */ if (execute("time\r", buf, sizeof(buf)) > 0) { upsdebugx(1, "UPS Time: %s", buf); @@ -606,7 +606,7 @@ static void upsdrv_init_nofc(void) upsdebugx(2, "id response: %s", rstring); /* Better way to identify this unit is using "d 15\r", which results in - "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ + * "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ if (strstr(rstring, "Unit ID \"C1K")){ fc.model = MDxxxx; snprintf(fc.name, sizeof(fc.name), "%s", "Micro Ferrups"); diff --git a/drivers/bestfortress.c b/drivers/bestfortress.c index 174009a9f6..713e99e672 100644 --- a/drivers/bestfortress.c +++ b/drivers/bestfortress.c @@ -93,21 +93,21 @@ void upsdrv_initinfo(void) dstate_setinfo("output.voltamps", "0"); /* tunable via front panel: (european voltage level) - parameter factory default range - INFO_LOWXFER 196 V p7=nnn 160-210 - INFO_HIGHXFER 254 V p8=nnn 215-274 - INFO_LOBATTIME 2 min p2=n 1-5 - - comm mode p6=0 dumb DONT USE (will lose access to parameter setting!) - p6=1 B1200 - p6=2 B2400 - P6=3 B4800 - p6=4 B9600 - maybe cycle through speeds to autodetect? - - echo off e0 - echo on e1 - */ + * parameter factory default range + * INFO_LOWXFER 196 V p7=nnn 160-210 + * INFO_HIGHXFER 254 V p8=nnn 215-274 + * INFO_LOBATTIME 2 min p2=n 1-5 + * + * comm mode p6=0 dumb DONT USE (will lose access to parameter setting!) + * p6=1 B1200 + * p6=2 B2400 + * P6=3 B4800 + * p6=4 B9600 + * maybe cycle through speeds to autodetect? + * + * echo off e0 + * echo on e1 + */ dstate_setinfo("input.transfer.low", "%s", ""); dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("input.transfer.low", 3); @@ -264,8 +264,9 @@ static ssize_t upsrecv(char *buf,size_t bufsize,char ec,const char *ic) { ssize_t nread; - nread = ser_get_line(upsfd, buf, bufsize - 1, ec, ic, - SER_WAIT_SEC, SER_WAIT_USEC); + nread = ser_get_line( + upsfd, buf, bufsize - 1, ec, ic, + SER_WAIT_SEC, SER_WAIT_USEC); /* \todo is buf null terminated? */ upsdebugx(4, "%s: read %" PRIiSIZE " <%s>", __func__, nread, buf); @@ -302,7 +303,7 @@ void upsdrv_updateinfo(void) do { if ((recv = upsrecv (temp+2, sizeof temp - 2, ENDCHAR, IGNCHARS)) <= 0) { upsdebugx(1, "%s: upsrecv failed, " - "retrying without counting", __func__); + "retrying without counting", __func__); upsflushin (0, 0, "\r "); upssend ("f\r"); while (ser_get_char(upsfd, &ch, 0, UPSDELAY) > 0 && ch != '\n'); /* response starts with \r\n */ @@ -310,37 +311,37 @@ void upsdrv_updateinfo(void) } while (temp[2] == 0); upsdebugx(3, "%s: received %" PRIiSIZE " bytes (try %i)", - __func__, recv, retry); + __func__, recv, retry); /* syslog (LOG_DAEMON | LOG_NOTICE,"ups: got %d chars '%s'\n", recv, temp + 2); */ /* status example: - 000000000001000000000000012201210000001200014500000280600000990025000000000301BE - 000000000001000000000000012401230000001200014800000280600000990025000000000301B7 - |Vi||Vo| |Io||Psou| |Vb||f| |tr||Ti| CS - 000000000001000000000000023802370000000200004700000267500000990030000000000301BD - 1 1 2 2 3 3 4 4 5 5 6 6 7 7 78 - 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 90 + * 000000000001000000000000012201210000001200014500000280600000990025000000000301BE + * 000000000001000000000000012401230000001200014800000280600000990025000000000301B7 + * |Vi||Vo| |Io||Psou| |Vb||f| |tr||Ti| CS + * 000000000001000000000000023802370000000200004700000267500000990030000000000301BD + * 1 1 2 2 3 3 4 4 5 5 6 6 7 7 78 + * 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 90 */ /* last bytes are a checksum: - interpret response as hex string, sum of all bytes must be zero + * interpret response as hex string, sum of all bytes must be zero */ checksum_ok = ( (checksum (temp+2) & 0xff) == 0 ); /* setinfo (INFO_, ""); */ if (!checksum_ok) { upsdebug_hex(5, "upsdrv_updateinfo: " - "checksum failure buffer hex", - temp, (size_t)recv); + "checksum failure buffer hex", + temp, (size_t)recv); upsdebug_ascii(5, "upsdrv_updateinfo: " - "checksum failure buffer ascii", - temp, (size_t)recv); + "checksum failure buffer ascii", + temp, (size_t)recv); } /* I can't figure out why this is missing the first two chars. - But the first two chars are not used, so just set them to zero - when missing. */ + * But the first two chars are not used, so just set them to zero + * when missing. */ len = strlen(temp+2); temp[0] = '0'; temp[1] = '0'; @@ -352,7 +353,7 @@ void upsdrv_updateinfo(void) if (checksum_ok) break; upsdebugx(1, "%s: failed to read status try %d", - __func__, retry); + __func__, retry); sleep(SER_WAIT_SEC); } @@ -389,9 +390,9 @@ void upsdrv_updateinfo(void) low_batt = fromhex(p[21]) & 8 || fromhex(p[20]) & 1; is_off = p[11] == '0'; trimming = p[33] == '1'; - boosting = 0; /* FIXME, don't know which bit gets set - (brownouts are very rare here and I can't - simulate one) */ + boosting = 0; /* FIXME, don't know which bit gets set + * (brownouts are very rare here and + * I can't simulate one) */ status_init(); if (low_batt) @@ -633,7 +634,7 @@ void upsdrv_initups(void) ser_set_speed(upsfd, device_path, speed); upsdebugx(1, "%s: opened %s speed %s upsfd %d", - __func__, device_path, speed_val ? speed_val : "DEFAULT", upsfd); + __func__, device_path, speed_val ? speed_val : "DEFAULT", upsfd); upsdebugx(1, "%s: end", __func__); } diff --git a/drivers/bestuferrups.c b/drivers/bestuferrups.c index 6ae94ac6cc..a9bcc6339c 100644 --- a/drivers/bestuferrups.c +++ b/drivers/bestuferrups.c @@ -119,7 +119,7 @@ void upsdrv_initinfo (void) fc.model = RE1800; } else if (memcmp(temp, "C1", 2) == 0) { /* Better way to identify unit is using "d 15\r", which results in - "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ + * "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ fc.model = MD1KVA; } @@ -428,8 +428,8 @@ void upsdrv_updateinfo(void) dstate_setinfo("ambient.temperature", "%05.1f", (double)ambtemp); dstate_dataok(); - /* Tim: With out this return, it always falls over to the - datastate() at the end of the function */ + /* Tim: Without this return, it always falls over to the + * datastate() at the end of the function */ return; } else { @@ -450,7 +450,7 @@ static void ups_sync(void) fflush (stdout); /* A bit better sanity might be good here. As is, we expect the - human to observe the time being totally not a time. */ + * human to observe the time being totally not a time. */ if (execute("time\r", buf, sizeof(buf)) > 0) { fprintf(stderr, "UPS Time: %s\n", buf); diff --git a/drivers/bicker_ser.c b/drivers/bicker_ser.c index d9a14cf760..218b943825 100644 --- a/drivers/bicker_ser.c +++ b/drivers/bicker_ser.c @@ -390,10 +390,10 @@ static ssize_t bicker_receive_parameter(uint8_t id, BickerParameter *dst) parameter.value = WORDLH(data[8], data[9]); upsdebugx(3, "Parameter %u = %u (%s, min = %u, max = %u, std = %u)", - (unsigned)parameter.id, (unsigned)parameter.value, - parameter.enabled ? "enabled" : "disabled", - (unsigned)parameter.min, (unsigned)parameter.max, - (unsigned)parameter.std); + (unsigned)parameter.id, (unsigned)parameter.value, + parameter.enabled ? "enabled" : "disabled", + (unsigned)parameter.min, (unsigned)parameter.max, + (unsigned)parameter.std); if (dst != NULL) { memcpy(dst, ¶meter, sizeof(parameter)); @@ -715,7 +715,7 @@ static int bicker_setvar(const char *varname, const char *val) if (parameter.enabled) { dstate_setinfo(varname, "%u", - (unsigned)parameter.value); + (unsigned)parameter.value); } else { /* Disabled parameters are removed from NUT */ dstate_delinfo(varname); @@ -879,9 +879,9 @@ void upsdrv_updateinfo(void) status_set("DISCHRG"); } dstate_setinfo("battery.charger.status", - (u8 & 0x01) > 0 ? "charging" : - (u8 & 0x02) > 0 ? "discharging" : - "resting"); + (u8 & 0x01) > 0 ? "charging" + : (u8 & 0x02) > 0 ? "discharging" + : "resting"); status_set((u8 & 0x04) > 0 ? "OL" : "OB"); if ((u8 & 0x20) > 0) { diff --git a/drivers/clone-outlet.c b/drivers/clone-outlet.c index 98178ca7cc..e95b89bdbe 100644 --- a/drivers/clone-outlet.c +++ b/drivers/clone-outlet.c @@ -1,24 +1,24 @@ /* -* clone-outlet.c: clone an UPS, treating its outlet as if it were an UPS -* (monitoring only) -* -* Copyright (C) 2009 - Arjen de Korte -* Copyright (C) 2024 - Jim Klimov -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ + * clone-outlet.c: clone an UPS, treating its outlet as if it were an UPS + * (monitoring only) + * + * Copyright (C) 2009 - Arjen de Korte + * Copyright (C) 2024 - Jim Klimov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include "main.h" #include "parseconf.h" @@ -455,7 +455,7 @@ static int sstate_dead(int maxage) if (elapsed > maxage) { upsdebugx(3, "sstate_dead: didn't hear from driver for UPS [%s] for %g seconds (max %d)", - device_path, elapsed, maxage); + device_path, elapsed, maxage); return -1; /* dead */ } diff --git a/drivers/common_voltronic-crc.c b/drivers/common_voltronic-crc.c index 2e05603883..48af385655 100644 --- a/drivers/common_voltronic-crc.c +++ b/drivers/common_voltronic-crc.c @@ -106,7 +106,7 @@ unsigned short common_voltronic_crc_compute(const char *input, const size_t len) unsigned short common_voltronic_crc_calc(const char *input, const size_t inputlen) { size_t len; - char *cr = memchr(input, '\r', inputlen); + char *cr = (char*)memchr(input, '\r', inputlen); /* No CR, fall back to string length (and hope *input* doesn't contain inner '\0's) */ if (cr == NULL) @@ -127,7 +127,7 @@ int common_voltronic_crc_calc_and_add(const char *input, const size_t inputlen, { unsigned short crc, crc_MSB, crc_LSB; size_t len; - char *cr = memchr(input, '\r', inputlen); + char *cr = (char*)memchr(input, '\r', inputlen); /* No CR, fall back to string length (and hope *input* doesn't contain inner '\0's) */ if (cr == NULL) @@ -173,7 +173,7 @@ int common_voltronic_crc_calc_and_add(const char *input, const size_t inputlen, int common_voltronic_crc_calc_and_add_m(char *input, const size_t inputlen) { int len; - char *buf = xcalloc(inputlen, sizeof(char)); + char *buf = (char*)xcalloc(inputlen, sizeof(char)); if (!buf) return -1; @@ -203,7 +203,7 @@ int common_voltronic_crc_calc_and_add_m(char *input, const size_t inputlen) int common_voltronic_crc_check(const char *input, const size_t inputlen) { unsigned short crc, crc_MSB, crc_LSB; - char *cr = memchr(input, '\r', inputlen); + char *cr = (char*)memchr(input, '\r', inputlen); size_t len; /* No CR, fall back to string length (and hope *input* doesn't contain inner '\0's) */ @@ -244,7 +244,7 @@ int common_voltronic_crc_check_and_remove(const char *input, const size_t inputl /* *input* successfully validated -> remove CRC bytes */ - cr = memchr(input, '\r', inputlen); + cr = (char*)memchr(input, '\r', inputlen); /* No CR, fall back to string length */ if (cr == NULL) len = strlen(input); @@ -277,7 +277,7 @@ int common_voltronic_crc_check_and_remove(const char *input, const size_t inputl int common_voltronic_crc_check_and_remove_m(char *input, const size_t inputlen) { int len; - char *buf = xcalloc(inputlen, sizeof(char)); + char *buf = (char*)xcalloc(inputlen, sizeof(char)); if (!buf) return -1; diff --git a/drivers/dstate.c b/drivers/dstate.c index 5b0a13e2d5..d1cf9ba1bc 100644 --- a/drivers/dstate.c +++ b/drivers/dstate.c @@ -121,10 +121,11 @@ static void sock_fail(const char *fn) case EADDRINUSE: case EADDRNOTAVAIL: printf("\nThings to try:\n\n"); + /* NOTE: Do not reformat indentation with TABs, to keep lines aligned for consistent editing */ printf(" - ps -ef | grep '%s'\t(Linux, GNU userland)\n" " - ps -xawwu | grep '%s'\t(BSD, Solaris, embedded)\n" " To check if another copy of the driver is running; if not:\n\n", - progname, progname); + progname, progname); printf(" - ls -la %s\n To check if a (non-socket) filesystem object already exists there\n\n", fn); printf(" - rm -rf %s\n To remove any offending files (a new driver instance creates its own)\n", fn); break; @@ -2229,13 +2230,14 @@ int dstate_detect_phasecount( * tables should take care of this with converion routine and numeric * data type flags. */ #define dstate_getinfo_nonzero(var, suffix) \ - do { strncpy(bufrw_ptr, suffix, bufrw_max); \ - if ( (var = dstate_getinfo(buf)) ) { \ - if ( (var[0] == '0' && var[1] == '\0') || \ - (var[0] == '\0') ) { \ - var = NULL; \ - } \ - } \ + do { \ + strncpy(bufrw_ptr, suffix, bufrw_max); \ + if ( (var = dstate_getinfo(buf)) ) { \ + if ( (var[0] == '0' && var[1] == '\0') \ + || (var[0] == '\0') ) { \ + var = NULL; \ + } \ + } \ } while(0) dstate_getinfo_nonzero(v1, "L1.voltage"); @@ -2254,37 +2256,40 @@ int dstate_detect_phasecount( dstate_getinfo_nonzero(v0, "voltage"); dstate_getinfo_nonzero(c0, "current"); - if ( (v1 && v2 && !v3) || - (v1n && v2n && !v3n) || - (c1 && c2 && !c3) || - (v12 && !v23 && !v31) ) { + if ( (v1 && v2 && !v3) + || (v1n && v2n && !v3n) + || (c1 && c2 && !c3) + || (v12 && !v23 && !v31) + ) { upsdebugx(5, "%s(): determined a 2-phase case", __func__); *num_phases = 2; *inited_phaseinfo = 1; detected_phaseinfo = 1; - } else if ( (v1 && v2 && v3) || - (v1n && v2n && v3n) || - (c1 && (c2 || c3)) || - (c2 && (c1 || c3)) || - (c3 && (c1 || c2)) || - v12 || v23 || v31 ) { + } else if ( (v1 && v2 && v3) + || (v1n && v2n && v3n) + || (c1 && (c2 || c3)) + || (c2 && (c1 || c3)) + || (c3 && (c1 || c2)) + || v12 || v23 || v31 + ) { upsdebugx(5, "%s(): determined a 3-phase case", __func__); *num_phases = 3; *inited_phaseinfo = 1; detected_phaseinfo = 1; } else if ( /* We definitely have only one non-zero line */ - !v12 && !v23 && !v31 && ( - (c0 && !c1 && !c2 && !c3) || - (v0 && !v1 && !v2 && !v3) || - (c1 && !c2 && !c3) || - (!c1 && c2 && !c3) || - (!c1 && !c2 && c3) || - (v1 && !v2 && !v3) || - (!v1 && v2 && !v3) || - (!v1 && !v2 && v3) || - (v1n && !v2n && !v3n) || - (!v1n && v2n && !v3n) || - (!v1n && !v2n && v3n) ) ) { + !v12 && !v23 && !v31 + && ( (c0 && !c1 && !c2 && !c3) + || (v0 && !v1 && !v2 && !v3) + || (c1 && !c2 && !c3) + || (!c1 && c2 && !c3) + || (!c1 && !c2 && c3) + || (v1 && !v2 && !v3) + || (!v1 && v2 && !v3) + || (!v1 && !v2 && v3) + || (v1n && !v2n && !v3n) + || (!v1n && v2n && !v3n) + || (!v1n && !v2n && v3n) ) + ) { *num_phases = 1; *inited_phaseinfo = 1; detected_phaseinfo = 1; diff --git a/drivers/dummy-ups.c b/drivers/dummy-ups.c index 4b3f410d07..a4b455b64a 100644 --- a/drivers/dummy-ups.c +++ b/drivers/dummy-ups.c @@ -156,7 +156,7 @@ void upsdrv_initinfo(void) fatalx(EXIT_FAILURE, "Error: invalid UPS definition.\nRequired format: upsname[@hostname[:port]]"); } /* Connect to the target */ - ups = xmalloc(sizeof(*ups)); + ups = (UPSCONN_t *)xmalloc(sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { if(repeater_disable_strict_start == 1) diff --git a/drivers/eaton-pdu-marlin-mib.c b/drivers/eaton-pdu-marlin-mib.c index 7bbcd83569..02419e4012 100644 --- a/drivers/eaton-pdu-marlin-mib.c +++ b/drivers/eaton-pdu-marlin-mib.c @@ -1102,7 +1102,7 @@ static snmp_info_t eaton_marlin_mib[] = { ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.2", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL), snmp_info_default("outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, - ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", + ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL), snmp_info_default("outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.4", diff --git a/drivers/ecoflow-hid.c b/drivers/ecoflow-hid.c index 28119dc9bc..5c4b47cb05 100644 --- a/drivers/ecoflow-hid.c +++ b/drivers/ecoflow-hid.c @@ -73,7 +73,7 @@ static const char *ecoflow_battery_runtime_conversion(double hid_value) { converted_runtime = hid_value * 60.0; /* Allocate memory for string representation */ - converted_value = xmalloc(HU_INFOSIZE); + converted_value = (char*)xmalloc(HU_INFOSIZE); snprintf(converted_value, HU_INFOSIZE, "%.0f", converted_runtime); return converted_value; } diff --git a/drivers/etapro.c b/drivers/etapro.c index d2e72010de..1e077ed836 100644 --- a/drivers/etapro.c +++ b/drivers/etapro.c @@ -82,8 +82,8 @@ etapro_get_response(const char *resp_type) unsigned int n, val; /* Read until a newline is found or there is no room in the buffer. - Unlike ser_get_line(), don't discard the following characters - because we have to handle multi-line responses. */ + * Unlike ser_get_line(), don't discard the following characters + * because we have to handle multi-line responses. */ n = 0; while (ser_get_char(upsfd, (unsigned char *)&tmp[n], 1, 0) == 1) { if (n >= sizeof(tmp) - 1 || tmp[n] == '\n') @@ -292,7 +292,7 @@ upsdrv_updateinfo(void) } /* TODO: >= 1000VA models have a 24V battery (max 28V) - check - the model string returned by the RI command. */ + * the model string returned by the RI command. */ battvolt = (14.0 / 255) * x; x = etapro_get_response("SL"); /* load (on battery), 0xFF = 150% */ @@ -308,8 +308,8 @@ upsdrv_updateinfo(void) return; } /* This is the time how long the UPS has been running on battery - (in seconds, reset to zero after power returns), but there - seems to be no variable defined for this yet... */ + * (in seconds, reset to zero after power returns), but there + * seems to be no variable defined for this yet... */ status_init(); diff --git a/drivers/everups.c b/drivers/everups.c index 1401e82067..b7987790fa 100644 --- a/drivers/everups.c +++ b/drivers/everups.c @@ -162,9 +162,9 @@ void upsdrv_updateinfo(void) fVal=((double)acuV-95.0)*100.0; if (standby) - fVal/=(135.5-95.0); + fVal/=(135.5-95.0); else - fVal/=(124.5-95.0); + fVal/=(124.5-95.0); if (fVal>100) fVal=100; else if (fVal<0) diff --git a/drivers/failover.c b/drivers/failover.c index a8335cf993..b79edb65b7 100644 --- a/drivers/failover.c +++ b/drivers/failover.c @@ -595,10 +595,10 @@ static void parse_port_argument(void) continue; } - new_ups = xcalloc(1, sizeof(**ups_list)); + new_ups = (ups_device_t *)xcalloc(1, sizeof(**ups_list)); new_ups->socketname = xstrdup(token); - ups_list = xrealloc(ups_list, sizeof(*ups_list) * (ups_count + 1)); + ups_list = (ups_device_t **)xrealloc(ups_list, sizeof(*ups_list) * (ups_count + 1)); ups_list[ups_count] = new_ups; ups_count++; @@ -1428,7 +1428,7 @@ static ups_device_t *get_primary_candidate(void) __func__, ups->socketname, priority, rt, rt_low); } - ups->priority = priority; + ups->priority = (ups_priority_t)priority; } ups_primary_count = primaries; @@ -1707,12 +1707,12 @@ static int ups_add_cmd(ups_device_t *ups, const char *val) } if (ups->cmd_count >= ups->cmd_allocs) { - ups->cmd_list = xrealloc(ups->cmd_list, sizeof(*ups->cmd_list) * (ups->cmd_allocs + CMD_ALLOC_BATCH)); + ups->cmd_list = (ups_cmd_t **)xrealloc(ups->cmd_list, sizeof(*ups->cmd_list) * (ups->cmd_allocs + CMD_ALLOC_BATCH)); memset(ups->cmd_list + ups->cmd_allocs, 0, sizeof(*ups->cmd_list) * CMD_ALLOC_BATCH); ups->cmd_allocs = ups->cmd_allocs + CMD_ALLOC_BATCH; } - new_cmd = xcalloc(1, sizeof(**ups->cmd_list)); + new_cmd = (ups_cmd_t *)xcalloc(1, sizeof(**ups->cmd_list)); new_cmd->value = xstrdup(val); new_cmd->needs_export = 1; @@ -1756,7 +1756,7 @@ static int ups_del_cmd(ups_device_t *ups, const char *val) ups->cmd_allocs = 0; } else if (ups->cmd_count % CMD_ALLOC_BATCH == 0) { - ups->cmd_list = xrealloc(ups->cmd_list, sizeof(*ups->cmd_list) * ups->cmd_count); + ups->cmd_list = (ups_cmd_t **)xrealloc(ups->cmd_list, sizeof(*ups->cmd_list) * ups->cmd_count); ups->cmd_allocs = ups->cmd_count; } @@ -1811,12 +1811,12 @@ static int ups_set_var(ups_device_t *ups, const char *key, const char *value) } if (ups->var_count >= ups->var_allocs) { - ups->var_list = xrealloc(ups->var_list, sizeof(*ups->var_list) * (ups->var_allocs + VAR_ALLOC_BATCH)); + ups->var_list = (ups_var_t **)xrealloc(ups->var_list, sizeof(*ups->var_list) * (ups->var_allocs + VAR_ALLOC_BATCH)); memset(ups->var_list + ups->var_allocs, 0, sizeof(*ups->var_list) * VAR_ALLOC_BATCH); ups->var_allocs = ups->var_allocs + VAR_ALLOC_BATCH; } - new_var = xcalloc(1, sizeof(**ups->var_list)); + new_var = (ups_var_t *)xcalloc(1, sizeof(**ups->var_list)); new_var->key = xstrdup(key); new_var->value = xstrdup(value); new_var->needs_export = 1; @@ -1877,7 +1877,7 @@ static int ups_del_var(ups_device_t *ups, const char *key) ups->var_allocs = 0; } else if (ups->var_count % VAR_ALLOC_BATCH == 0) { - ups->var_list = xrealloc(ups->var_list, sizeof(*ups->var_list) * ups->var_count); + ups->var_list = (ups_var_t **)xrealloc(ups->var_list, sizeof(*ups->var_list) * ups->var_count); ups->var_allocs = ups->var_count; } @@ -1970,12 +1970,12 @@ static int ups_add_range(ups_device_t *ups, const char *key, const int min, cons } if (var->range_count >= var->range_allocs) { - var->range_list = xrealloc(var->range_list, sizeof(*var->range_list) * (var->range_allocs + SUBVAR_ALLOC_BATCH)); + var->range_list = (var_range_t **)xrealloc(var->range_list, sizeof(*var->range_list) * (var->range_allocs + SUBVAR_ALLOC_BATCH)); memset(var->range_list + var->range_allocs, 0, sizeof(*var->range_list) * SUBVAR_ALLOC_BATCH); var->range_allocs = var->range_allocs + SUBVAR_ALLOC_BATCH; } - new_range = xcalloc(1, sizeof(**var->range_list)); + new_range = (var_range_t *)xcalloc(1, sizeof(**var->range_list)); new_range->min = min; new_range->max = max; @@ -2029,7 +2029,7 @@ static int ups_del_range(ups_device_t *ups, const char *key, const int min, cons var->range_allocs = 0; } else if (var->range_count % SUBVAR_ALLOC_BATCH == 0) { - var->range_list = xrealloc(var->range_list, sizeof(*var->range_list) * var->range_count); + var->range_list = (var_range_t **)xrealloc(var->range_list, sizeof(*var->range_list) * var->range_count); var->range_allocs = var->range_count; } @@ -2062,7 +2062,7 @@ static int ups_add_enum(ups_device_t *ups, const char *key, const char *val) } if (var->enum_count >= var->enum_allocs) { - var->enum_list = xrealloc(var->enum_list, sizeof(*var->enum_list) * (var->enum_allocs + SUBVAR_ALLOC_BATCH)); + var->enum_list = (char **)xrealloc(var->enum_list, sizeof(*var->enum_list) * (var->enum_allocs + SUBVAR_ALLOC_BATCH)); memset(var->enum_list + var->enum_allocs, 0, sizeof(*var->enum_list) * SUBVAR_ALLOC_BATCH); var->enum_allocs = var->enum_allocs + SUBVAR_ALLOC_BATCH; } @@ -2118,7 +2118,7 @@ static int ups_del_enum(ups_device_t *ups, const char *key, const char *val) var->enum_allocs = 0; } else if (var->enum_count % SUBVAR_ALLOC_BATCH == 0) { - var->enum_list = xrealloc(var->enum_list, sizeof(*var->enum_list) * var->enum_count); + var->enum_list = (char **)xrealloc(var->enum_list, sizeof(*var->enum_list) * var->enum_count); var->enum_allocs = var->enum_count; } @@ -2346,7 +2346,7 @@ static ssize_t csv_arg_to_array(const char *arg, const char *argcsv, char ***arr str = xstrdup(token); - *array = xrealloc(*array, sizeof(**array) * (*countvar + 1)); + *array = (char **)xrealloc(*array, sizeof(**array) * (*countvar + 1)); (*array)[*countvar] = str; (*countvar)++; diff --git a/drivers/generic_gpio_common.c b/drivers/generic_gpio_common.c index a163f7784e..dc956e04f2 100644 --- a/drivers/generic_gpio_common.c +++ b/drivers/generic_gpio_common.c @@ -75,13 +75,13 @@ struct gpioups_t *generic_gpio_open(const char *chipName) { if (!rules) /* rules is required configuration parameter */ fatalx(EXIT_FAILURE, "UPS status calculation rules not specified"); - upsfdlocal = xcalloc(1, sizeof(*upsfdlocal)); + upsfdlocal = (struct gpioups_t *)xcalloc(1, sizeof(*upsfdlocal)); upsfdlocal->runOptions = 0; /* don't use ROPT_REQRES and ROPT_EVMODE yet */ upsfdlocal->chipName = chipName; get_ups_rules(upsfdlocal, (unsigned char *)rules); - upsfdlocal->upsLinesStates = xcalloc(upsfdlocal->upsLinesCount, sizeof(int)); + upsfdlocal->upsLinesStates = (int *)xcalloc(upsfdlocal->upsLinesCount, sizeof(int)); return upsfdlocal; } @@ -122,7 +122,7 @@ void add_rule_item(struct gpioups_t *upsfdlocal, int newValue) { int subCount = (upsfdlocal->rules[upsfdlocal->rulesCount - 1]) ? upsfdlocal->rules[upsfdlocal->rulesCount - 1]->subCount + 1 : 1; int itemSize = subCount * sizeof(upsfdlocal->rules[0]->cRules[0]) + sizeof(rulesint); - upsfdlocal->rules[upsfdlocal->rulesCount - 1] = xrealloc(upsfdlocal->rules[upsfdlocal->rulesCount - 1], itemSize); + upsfdlocal->rules[upsfdlocal->rulesCount - 1] = (struct rulesint_t *)xrealloc(upsfdlocal->rules[upsfdlocal->rulesCount - 1], itemSize); upsfdlocal->rules[upsfdlocal->rulesCount - 1]->subCount = subCount; upsfdlocal->rules[upsfdlocal->rulesCount - 1]->cRules[subCount - 1] = newValue; } @@ -197,8 +197,8 @@ void get_ups_rules(struct gpioups_t *upsfdlocal, unsigned char *rulesString) { } else { lexStatus = 1; upsfdlocal->rulesCount++; - upsfdlocal->rules = xrealloc(upsfdlocal->rules, (size_t)(sizeof(upsfdlocal->rules[0])*upsfdlocal->rulesCount)); - upsfdlocal->rules[upsfdlocal->rulesCount -1 ] = xcalloc(1, sizeof(rulesint)); + upsfdlocal->rules = (struct rulesint_t **)xrealloc(upsfdlocal->rules, (size_t)(sizeof(upsfdlocal->rules[0])*upsfdlocal->rulesCount)); + upsfdlocal->rules[upsfdlocal->rulesCount -1 ] = (struct rulesint_t *)xcalloc(1, sizeof(rulesint)); strncpy(upsfdlocal->rules[upsfdlocal->rulesCount - 1]->stateName, (char *)(rulesString + startPos), endPos - startPos); upsfdlocal->rules[upsfdlocal->rulesCount - 1]->stateName[endPos - startPos] = 0; } @@ -291,7 +291,7 @@ void get_ups_rules(struct gpioups_t *upsfdlocal, unsigned char *rulesString) { if (!pinOnList) { if (upsfdlocal->rules[i]->cRules[j] >= 0) { upsfdlocal->upsLinesCount++; - upsfdlocal->upsLines = xrealloc(upsfdlocal->upsLines, sizeof(upsfdlocal->upsLines[0])*upsfdlocal->upsLinesCount); + upsfdlocal->upsLines = (int *)xrealloc(upsfdlocal->upsLines, sizeof(upsfdlocal->upsLines[0])*upsfdlocal->upsLinesCount); upsfdlocal->upsLines[upsfdlocal->upsLinesCount - 1] = upsfdlocal->rules[i]->cRules[j]; if (upsfdlocal->upsLines[upsfdlocal->upsLinesCount - 1] > upsfdlocal->upsMaxLine) { upsfdlocal->upsMaxLine = upsfdlocal->upsLines[upsfdlocal->upsLinesCount - 1]; diff --git a/drivers/generic_gpio_libgpiod.c b/drivers/generic_gpio_libgpiod.c index 9fe7891618..a9c923ed73 100644 --- a/drivers/generic_gpio_libgpiod.c +++ b/drivers/generic_gpio_libgpiod.c @@ -121,7 +121,7 @@ static void reserve_lines_libgpiod(struct gpioups_t *gpioupsfdlocal, int inner) * and check lines numbers validity - consistency with h/w chip */ void gpio_open(struct gpioups_t *gpioupsfdlocal) { - struct libgpiod_data_t *libgpiod_data = xcalloc(1, sizeof(struct libgpiod_data_t)); + struct libgpiod_data_t *libgpiod_data = (struct libgpiod_data_t *)xcalloc(1, sizeof(struct libgpiod_data_t)); gpioupsfdlocal->lib_data = libgpiod_data; #if WITH_LIBGPIO_VERSION < 0x00020000 @@ -129,7 +129,7 @@ void gpio_open(struct gpioups_t *gpioupsfdlocal) { #else /* #if WITH_LIBGPIO_VERSION >= 0x00020000 */ if(!strchr(gpioupsfdlocal->chipName, '/')) { size_t pathNameLen = strlen(gpioupsfdlocal->chipName)+6; - char *pathName = xcalloc(pathNameLen, sizeof(char)); + char *pathName = (char *)xcalloc(pathNameLen, sizeof(char)); strncpy(pathName, "/dev/", pathNameLen); strncat(pathName, gpioupsfdlocal->chipName, pathNameLen); libgpiod_data->gpioChipHandle = gpiod_chip_open(pathName); @@ -182,7 +182,7 @@ void gpio_open(struct gpioups_t *gpioupsfdlocal) { &libgpiod_data->gpioLines ); #else /* #if WITH_LIBGPIO_VERSION >= 0x00020000 */ - libgpiod_data->values = xcalloc(gpioupsfdlocal->upsLinesCount, sizeof(*libgpiod_data->values)); + libgpiod_data->values = (enum gpiod_line_value *)xcalloc(gpioupsfdlocal->upsLinesCount, sizeof(*libgpiod_data->values)); lineSettings = gpiod_line_settings_new(); libgpiod_data->lineConfig = gpiod_line_config_new(); libgpiod_data->config = gpiod_request_config_new(); @@ -197,8 +197,9 @@ void gpio_open(struct gpioups_t *gpioupsfdlocal) { if(gpioRc) { fatal_with_errno(LOG_ERR, "Failed to set lines to GPIOD_LINE_EDGE_BOTH"); } - gpioRc = gpiod_line_config_add_line_settings(libgpiod_data->lineConfig, (unsigned int *)gpioupsfdlocal->upsLines, - gpioupsfdlocal->upsLinesCount, lineSettings); + gpioRc = gpiod_line_config_add_line_settings( + libgpiod_data->lineConfig, (unsigned int *)gpioupsfdlocal->upsLines, + gpioupsfdlocal->upsLinesCount, lineSettings); if(gpioRc) { fatalx(LOG_ERR, "Failed to attach line settings to line configuration"); } diff --git a/drivers/generic_modbus.c b/drivers/generic_modbus.c index 234f5a29e5..de3a791f4a 100644 --- a/drivers/generic_modbus.c +++ b/drivers/generic_modbus.c @@ -31,7 +31,7 @@ #endif #define DRIVER_NAME "NUT Generic Modbus driver (libmodbus link type: " NUT_MODBUS_LINKTYPE_STR ")" -#define DRIVER_VERSION "0.09" +#define DRIVER_VERSION "0.10" /* variables */ static modbus_t *mbctx = NULL; /* modbus memory context */ @@ -69,9 +69,6 @@ int upscmd(const char *cmd, const char *arg); /* read signal status */ int get_signal_state(devstate_t state); -/* count the time elapsed since start */ -long time_elapsed(struct timeval *start); - int register_write(modbus_t *mb, int addr, regtype_t type, void *data); /* driver description structure */ @@ -543,31 +540,6 @@ int register_write(modbus_t *mb, int addr, regtype_t type, void *data) return rval; } -/* returns the time elapsed since start in milliseconds */ -long time_elapsed(struct timeval *start) -{ - long rval; - struct timeval end; - - rval = gettimeofday(&end, NULL); - if (rval < 0) { - upslog_with_errno(LOG_ERR, "time_elapsed"); - } - if (start->tv_usec < end.tv_usec) { - suseconds_t nsec = (end.tv_usec - start->tv_usec) / 1000000 + 1; - end.tv_usec -= 1000000 * nsec; - end.tv_sec += nsec; - } - if (start->tv_usec - end.tv_usec > 1000000) { - suseconds_t nsec = (start->tv_usec - end.tv_usec) / 1000000; - end.tv_usec += 1000000 * nsec; - end.tv_sec -= nsec; - } - rval = (end.tv_sec - start->tv_sec) * 1000 + (end.tv_usec - start->tv_usec) / 1000; - - return rval; -} - /* instant command triggered by upsd */ int upscmd(const char *cmd, const char *arg) { @@ -582,8 +554,8 @@ int upscmd(const char *cmd, const char *arg) if (!strcasecmp(cmd, "load.off")) { upslog_INSTCMD_POWERSTATE_CHANGE(cmd, arg); - if (sigar[FSD_T].addr != NOTUSED && - (sigar[FSD_T].type == COIL || sigar[FSD_T].type == HOLDING) + if (sigar[FSD_T].addr != NOTUSED + && (sigar[FSD_T].type == COIL || sigar[FSD_T].type == HOLDING) ) { data = 1 ^ sigar[FSD_T].noro; rval = register_write(mbctx, sigar[FSD_T].addr, sigar[FSD_T].type, &data); @@ -611,7 +583,7 @@ int upscmd(const char *cmd, const char *arg) } /* wait for FSD_pulse_duration ms */ - while ((etime = time_elapsed(&start)) < FSD_pulse_duration); + while ((etime = elapsed_since_timeval(&start)) < FSD_pulse_duration); data = 0 ^ sigar[FSD_T].noro; rval = register_write(mbctx, sigar[FSD_T].addr, sigar[FSD_T].type, &data); @@ -654,7 +626,7 @@ int upscmd(const char *cmd, const char *arg) } /* wait for an increasing time interval before sending shutdown command */ - while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt)); + while ((etime = elapsed_since_timeval(&start)) < ( FSD_REPEAT_INTRV / cnt)); upsdebugx(2,"ERROR: load.off failed, wait for %lims, retries left: %d\n", etime, cnt - 1); cnt--; } @@ -688,7 +660,7 @@ int get_signal_state(devstate_t state) { int rval = -1; int reg_val; - regtype_t rtype = 0; /* register type */ + regtype_t rtype = (regtype_t)0; /* register type */ int addr = -1; /* register address */ /* assign register address and type */ @@ -855,7 +827,7 @@ void get_config_vars(void) /* check if OL register type is set and get the value otherwise set to INPUT_B */ if (testvar("OL_regtype")) { - sigar[OL_T].type = (unsigned int)strtol(getval("OL_regtype"), NULL, 10); + sigar[OL_T].type = (regtype_t)(unsigned int)strtol(getval("OL_regtype"), NULL, 10); if (sigar[OL_T].type < COIL || sigar[OL_T].type > HOLDING) { sigar[OL_T].type = INPUT_B; } @@ -876,7 +848,7 @@ void get_config_vars(void) /* check if OB register type is set and get the value otherwise set to INPUT_B */ if (testvar("OB_regtype")) { - sigar[OB_T].type = (unsigned int)strtol(getval("OB_regtype"), NULL, 10); + sigar[OB_T].type = (regtype_t)(unsigned int)strtol(getval("OB_regtype"), NULL, 10); if (sigar[OB_T].type < COIL || sigar[OB_T].type > HOLDING) { sigar[OB_T].type = INPUT_B; } @@ -897,7 +869,7 @@ void get_config_vars(void) /* check if LB register type is set and get the value otherwise set to INPUT_B */ if (testvar("LB_regtype")) { - sigar[LB_T].type = (unsigned int)strtol(getval("OB_regtype"), NULL, 10); + sigar[LB_T].type = (regtype_t)(unsigned int)strtol(getval("OB_regtype"), NULL, 10); if (sigar[LB_T].type < COIL || sigar[LB_T].type > HOLDING) { sigar[LB_T].type = INPUT_B; } @@ -918,7 +890,7 @@ void get_config_vars(void) /* check if HB register type is set and get the value otherwise set to INPUT_B */ if (testvar("HB_regtype")) { - sigar[HB_T].type = (unsigned int)strtol(getval("HB_regtype"), NULL, 10); + sigar[HB_T].type = (regtype_t)(unsigned int)strtol(getval("HB_regtype"), NULL, 10); if (sigar[HB_T].type < COIL || sigar[HB_T].type > HOLDING) { sigar[HB_T].type = INPUT_B; } @@ -939,7 +911,7 @@ void get_config_vars(void) /* check if RB register type is set and get the value otherwise set to INPUT_B */ if (testvar("RB_regtype")) { - sigar[RB_T].type = (unsigned int)strtol(getval("RB_regtype"), NULL, 10); + sigar[RB_T].type = (regtype_t)(unsigned int)strtol(getval("RB_regtype"), NULL, 10); if (sigar[RB_T].type < COIL || sigar[RB_T].type > HOLDING) { sigar[RB_T].type = INPUT_B; } @@ -960,7 +932,7 @@ void get_config_vars(void) /* check if CHRG register type is set and get the value otherwise set to INPUT_B */ if (testvar("CHRG_regtype")) { - sigar[CHRG_T].type = (unsigned int)strtol(getval("CHRG_regtype"), NULL, 10); + sigar[CHRG_T].type = (regtype_t)(unsigned int)strtol(getval("CHRG_regtype"), NULL, 10); if (sigar[CHRG_T].type < COIL || sigar[CHRG_T].type > HOLDING) { sigar[CHRG_T].type = INPUT_B; } @@ -981,7 +953,7 @@ void get_config_vars(void) /* check if DISCHRG register type is set and get the value otherwise set to INPUT_B */ if (testvar("DISCHRG_regtype")) { - sigar[DISCHRG_T].type = (unsigned int)strtol(getval("DISCHRG_regtype"), NULL, 10); + sigar[DISCHRG_T].type = (regtype_t)(unsigned int)strtol(getval("DISCHRG_regtype"), NULL, 10); if (sigar[DISCHRG_T].type < COIL || sigar[DISCHRG_T].type > HOLDING) { sigar[DISCHRG_T].type = INPUT_B; } @@ -1002,7 +974,7 @@ void get_config_vars(void) /* check if FSD register type is set and get the value otherwise set to COIL */ if (testvar("FSD_regtype")) { - sigar[FSD_T].type = (unsigned int)strtol(getval("FSD_regtype"), NULL, 10); + sigar[FSD_T].type = (regtype_t)(unsigned int)strtol(getval("FSD_regtype"), NULL, 10); if (sigar[FSD_T].type < COIL || sigar[FSD_T].type > HOLDING) { sigar[FSD_T].type = COIL; } @@ -1068,7 +1040,7 @@ modbus_t *modbus_new(const char *port) upslogx(LOG_ERR, "modbus_new_rtu: Unable to open serial port context\n"); } } else if ((sp = strchr(port, ':')) != NULL) { - char *tcp_port = xmalloc(sizeof(sp)); + char *tcp_port = (char*)xmalloc(sizeof(sp)); strncpy(tcp_port, sp + 1, sizeof(sp)); *sp = '\0'; mb = modbus_new_tcp(port, (int)strtoul(tcp_port, NULL, 10)); diff --git a/drivers/genericups.c b/drivers/genericups.c index fec4c119ad..dfeb17d420 100644 --- a/drivers/genericups.c +++ b/drivers/genericups.c @@ -194,7 +194,7 @@ void upsdrv_initinfo(void) } /* - User wants to override the input signal definitions. See also upsdrv_initups(). + * User wants to override the input signal definitions. See also upsdrv_initups(). */ if ((v = getval("OL")) != NULL) { parse_input_signals(v, &upstab[upstype].line_ol, &upstab[upstype].val_ol); @@ -319,7 +319,7 @@ void upsdrv_shutdown(void) upslogx(LOG_ERR, "No upstype set - see help text / man page!"); if (handling_upsdrv_shutdown > 0) set_exit_flag(EF_EXIT_FAILURE); - return; + return; } flags = upstab[upstype].line_sd; @@ -328,7 +328,7 @@ void upsdrv_shutdown(void) upslogx(LOG_ERR, "No shutdown command defined for this model!"); if (handling_upsdrv_shutdown > 0) set_exit_flag(EF_EXIT_FAILURE); - return; + return; } if (flags == TIOCM_ST) { @@ -338,7 +338,7 @@ void upsdrv_shutdown(void) upslogx(LOG_ERR, "Need to send a BREAK, but don't have tcsendbreak!"); if (handling_upsdrv_shutdown > 0) set_exit_flag(EF_EXIT_FAILURE); - return; + return; # endif #else /* WIN32 */ NUT_WIN32_INCOMPLETE_DETAILED("Need to send a BREAK at this point, but not addressed for WIN32 yet"); @@ -365,7 +365,7 @@ void upsdrv_shutdown(void) upslog_with_errno(LOG_ERR, "ioctl TIOCMSET"); if (handling_upsdrv_shutdown > 0) set_exit_flag(EF_EXIT_FAILURE); - return; + return; } if (getval("sdtime")) { @@ -449,10 +449,10 @@ void upsdrv_initups(void) } /* - See if the user wants to override the output signal definitions? - This must be done here, since we might go to upsdrv_shutdown() - immediately. Input signal definition override is handled in - upsdrv_initinfo() + * See if the user wants to override the output signal definitions? + * This must be done here, since we might go to upsdrv_shutdown() + * immediately. Input signal definition override is handled in + * upsdrv_initinfo() */ if ((v = getval("CP")) != NULL) { parse_output_signals(v, &upstab[upstype].line_norm); diff --git a/drivers/hidparser.c b/drivers/hidparser.c index 2132dba053..87c8dab53a 100644 --- a/drivers/hidparser.c +++ b/drivers/hidparser.c @@ -571,12 +571,12 @@ HIDData_t *FindObject_with_ID_Node(HIDDesc_t *pDesc_arg, uint8_t ReportID, HIDNo void GetValue(const unsigned char *Buf, HIDData_t *pData, long *pValue) { /* Note: https://github.com/networkupstools/nut/issues/1023 - This conversion code can easily be sensitive to 32- vs. 64- bit - compilation environments. Consider the possibility of overflow - in 32-bit representations when computing with extreme values, - for example LogMax-LogMin+1. - Test carefully in both environments if changing any declarations. - */ + * This conversion code can easily be sensitive to 32- vs. 64- bit + * compilation environments. Consider the possibility of overflow + * in 32-bit representations when computing with extreme values, + * for example LogMax-LogMin+1. + * Test carefully in both environments if changing any declarations. + */ int Weight, Bit; unsigned long mask, signbit, magMax, magMin; @@ -677,7 +677,7 @@ HIDDesc_t *Parse_ReportDesc(const usb_ctrl_charbuf ReportDesc, const usb_ctrl_ch HIDDesc_t *pDesc_var; HIDParser_t *parser; - pDesc_var = calloc(1, sizeof(*pDesc_var)); + pDesc_var = (HIDDesc_t *)calloc(1, sizeof(*pDesc_var)); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif @@ -712,13 +712,13 @@ HIDDesc_t *Parse_ReportDesc(const usb_ctrl_charbuf ReportDesc, const usb_ctrl_ch # pragma GCC diagnostic pop #endif - pDesc_var->item = calloc(MAX_REPORT, sizeof(*pDesc_var->item)); + pDesc_var->item = (HIDData_t *)calloc(MAX_REPORT, sizeof(*pDesc_var->item)); if (!pDesc_var->item) { Free_ReportDesc(pDesc_var); return NULL; } - parser = calloc(1, sizeof(*parser)); + parser = (HIDParser_t *)calloc(1, sizeof(*parser)); if (!parser) { Free_ReportDesc(pDesc_var); return NULL; @@ -762,7 +762,7 @@ HIDDesc_t *Parse_ReportDesc(const usb_ctrl_charbuf ReportDesc, const usb_ctrl_ch return NULL; } - pDesc_var->item = realloc(pDesc_var->item, pDesc_var->nitems * sizeof(*pDesc_var->item)); + pDesc_var->item = (HIDData_t *)realloc(pDesc_var->item, pDesc_var->nitems * sizeof(*pDesc_var->item)); return pDesc_var; } diff --git a/drivers/hpe-pdu-mib.c b/drivers/hpe-pdu-mib.c index ad2960f735..3c32676d5f 100644 --- a/drivers/hpe-pdu-mib.c +++ b/drivers/hpe-pdu-mib.c @@ -678,7 +678,7 @@ static snmp_info_t hpe_pdu_mib[] = { ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.2", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL), snmp_info_default("outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, - ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", + ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL), snmp_info_default("outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.4", diff --git a/drivers/huawei-ups2000.c b/drivers/huawei-ups2000.c index 0a792968c1..48291ebf6e 100644 --- a/drivers/huawei-ups2000.c +++ b/drivers/huawei-ups2000.c @@ -748,8 +748,8 @@ static int ups2000_update_status(void) * if the register is equal to the "val" we are looking * for, or if register has its n-th "bit" set... */ - if ((flag[j].val != -1 && flag[j].val == val) || - (flag[j].bit != -1 && CHECK_BIT(val, flag[j].bit)) + if ((flag[j].val != -1 && flag[j].val == val) + || (flag[j].bit != -1 && CHECK_BIT(val, flag[j].bit)) ) { /* if it has a corresponding status flag */ if (strlen(flag[j].status_name) != 0) @@ -983,7 +983,7 @@ static int ups2000_update_alarm(void) alarm_count++; - gotlen = snprintf(alarm_buf, 128, "(ID %02d/%02d): %s!", + gotlen = snprintf(alarm_buf, sizeof(alarm_buf), "(ID %02d/%02d): %s!", ups2000_alarm[i].alarm_id, ups2000_alarm[i].alarm_cause_id, ups2000_alarm[i].alarm_name); @@ -1002,8 +1002,8 @@ static int ups2000_update_alarm(void) * Log the warning only if it's a new alarm, or if a long time * has paseed since we first warned it. */ - if (!ups2000_alarm[i].active || - difftime(now, alarm_logged_since) >= UPS2000_LOG_INTERVAL + if (!ups2000_alarm[i].active + || difftime(now, alarm_logged_since) >= UPS2000_LOG_INTERVAL ) { int loglevel; const char *alarm_word; @@ -1073,7 +1073,7 @@ static int ups2000_update_alarm(void) if (alarm_count > 0) { /* append this to the alarm string as a friendly reminder */ - int gotlen = snprintf(alarm_buf, 128, "Check log for details!"); + int gotlen = snprintf(alarm_buf, sizeof(alarm_buf), "Check log for details!"); if (gotlen < 0 || (uintmax_t)gotlen > SIZE_MAX) { fatalx(EXIT_FAILURE, "alarm_buf preparation over/under-flow!"); @@ -1085,8 +1085,9 @@ static int ups2000_update_alarm(void) /* if the alarm string is too long, replace it with this */ if (all_alarms_len + 1 > ST_MAX_VALUE_LEN) { alarm_init(); /* discard all original alarms */ - snprintf(alarm_buf, 128, "UPS has %d alarms in effect, " - "check log for details!", alarm_count); + snprintf(alarm_buf, sizeof(alarm_buf), + "UPS has %d alarms in effect, " + "check log for details!", alarm_count); alarm_set(alarm_buf); } @@ -1364,11 +1365,12 @@ static void ups2000_delay_get(void) if (cmdline) { r = ups2000_delay_set(delay->name, cmdline); if (r != STAT_SET_HANDLED) { - upslogx(LOG_ERR, "servar: %s is invalid. " - "Reverting to default %s %d seconds", - delay->varname_cmdline, - delay->varname_cmdline, - delay->dfault); + upslogx(LOG_ERR, + "servar: %s is invalid. " + "Reverting to default %s %d seconds", + delay->varname_cmdline, + delay->varname_cmdline, + delay->dfault); *delay->global_var = delay->dfault; } } @@ -1590,15 +1592,17 @@ static int ups2000_instcmd_load_on(const uint16_t reg) * normal/bypass status. Also log an error and suggest "bypass.stop". */ /* FIXME: ..._INVALID ? */ - upslogx(LOG_INSTCMD_FAILED, "load.on error: UPS is already on, and is in bypass mode. " - "To enter normal mode, use bypass.stop"); + upslogx(LOG_INSTCMD_FAILED, + "load.on error: UPS is already on, and is in bypass mode. " + "To enter normal mode, use bypass.stop"); return STAT_INSTCMD_FAILED; } else { /* unreachable, see comments for r != 0 at the beginning */ /* FIXME: ..._INVALID ? */ - upslogx(LOG_INSTCMD_FAILED, "load.on error: invalid ups.status (%s) detected. " - "Please file a bug report!", status); + upslogx(LOG_INSTCMD_FAILED, + "load.on error: invalid ups.status (%s) detected. " + "Please file a bug report!", status); return STAT_INSTCMD_FAILED; } @@ -1986,8 +1990,9 @@ static int ups2000_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *des int r = -1; if (addr < 10000) - upslogx(LOG_ERR, "Invalid register read from %04d detected. " - "Please file a bug report!", addr); + upslogx(LOG_ERR, + "Invalid register read from %04d detected. " + "Please file a bug report!", addr); for (i = 0; i < 3; i++) { /* @@ -2018,8 +2023,9 @@ static int ups2000_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *des * this register returns invalid values. This is a known problem * and it's not fatal, so we use LOG_INFO. */ - if (retry_status == RETRY_ENABLE && - addr == 12002 && (dest[0] < 2 || dest[0] > 5) + if (retry_status == RETRY_ENABLE + && addr == 12002 + && (dest[0] < 2 || dest[0] > 5) ) { upslogx(LOG_INFO, "Battery status has a non-fatal read failure, it's usually harmless. Retrying... "); sleep(1); @@ -2046,8 +2052,9 @@ static int ups2000_write_registers(modbus_t *ctx, int addr, int nb, uint16_t *sr int r = -1; if (addr < 10000) - upslogx(LOG_ERR, "Invalid register write to %04d detected. " - "Please file a bug report!", addr); + upslogx(LOG_ERR, + "Invalid register write to %04d detected. " + "Please file a bug report!", addr); for (i = 0; i < 3; i++) { r = modbus_write_registers(ctx, addr, nb, src); diff --git a/drivers/libhid.c b/drivers/libhid.c index 0ead97b34c..42509e36c5 100644 --- a/drivers/libhid.c +++ b/drivers/libhid.c @@ -111,7 +111,7 @@ reportbuf_t *new_report_buffer(HIDDesc_t *arg_pDesc) if (!arg_pDesc) return NULL; - rbuf = calloc(1, sizeof(*rbuf)); + rbuf = (reportbuf_t *)calloc(1, sizeof(*rbuf)); if (!rbuf) { return NULL; } @@ -135,7 +135,7 @@ reportbuf_t *new_report_buffer(HIDDesc_t *arg_pDesc) continue; } - rbuf->data[id] = calloc(rbuf->len[id], sizeof(*(rbuf->data[id]))); + rbuf->data[id] = (unsigned char *)calloc(rbuf->len[id], sizeof(*(rbuf->data[id]))); if (rbuf->data[id]) continue; diff --git a/drivers/libshut.c b/drivers/libshut.c index ec68db5eda..e35077b879 100644 --- a/drivers/libshut.c +++ b/drivers/libshut.c @@ -373,7 +373,7 @@ static int libshut_open( SHUTDevice_t *curDevice, char *arg_device_path, int (*callback)(usb_dev_handle arg_upsfd, SHUTDevice_t *hd, - usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen)) + usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen)) { int ret, res; usb_ctrl_char buf[20] __attribute__((aligned(4))); @@ -478,7 +478,7 @@ static int libshut_open( if (res < 9) { upsdebugx(2, "DEVICE descriptor too short (expected %d, got %d)", - USB_DT_DEVICE_SIZE, res); + USB_DT_DEVICE_SIZE, res); return -1; } @@ -725,9 +725,9 @@ static int libshut_get_report( return shut_control_msg(arg_upsfd, REQUEST_TYPE_GET_REPORT, /* == USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE, */ - 0x01, - ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ - 0, raw_buf, ReportSize, SHUT_TIMEOUT); + 0x01, + ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ + 0, raw_buf, ReportSize, SHUT_TIMEOUT); } /* return ReportSize upon success ; -1 otherwise */ @@ -876,7 +876,7 @@ int shut_synchronise(usb_dev_handle arg_upsfd) { int retCode = 0; unsigned char c = SHUT_SYNC_OFF, reply; - int try; + int try_num; upsdebugx (2, "entering shut_synchronise()"); reply = '\0'; @@ -898,9 +898,9 @@ int shut_synchronise(usb_dev_handle arg_upsfd) */ /* Sync with the UPS according to notification */ - for (try = 0; try < MAX_TRY; try++) + for (try_num = 0; try_num < MAX_TRY; try_num++) { - upsdebugx (3, "Syncing communication (try %i)", try); + upsdebugx (3, "Syncing communication (try %i)", try_num); if ((ser_send_char(arg_upsfd, c)) == -1) { @@ -1156,8 +1156,15 @@ static int shut_get_descriptor( "entering shut_get_descriptor(n %02x, %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", type, size); - return shut_control_msg(arg_upsfd, USB_ENDPOINT_IN+(type>=USB_DT_HID?1:0), - USB_REQ_GET_DESCRIPTOR, (type << 8) + index, 0, buf, size, SHUT_TIMEOUT); + return shut_control_msg( + arg_upsfd, + USB_ENDPOINT_IN+(type>=USB_DT_HID?1:0), + USB_REQ_GET_DESCRIPTOR, + (type << 8) + index, + 0, + (usb_ctrl_charbuf)buf, + size, + SHUT_TIMEOUT); } /* Take care of a SHUT transfer (sending and receiving data) */ diff --git a/drivers/libusb0.c b/drivers/libusb0.c index 1780168577..ab002f36f3 100644 --- a/drivers/libusb0.c +++ b/drivers/libusb0.c @@ -354,7 +354,7 @@ static int nut_libusb_open(usb_dev_handle **udevp, bus->dirname, dev->filename); /* supported vendors are now checked by the - supplied matcher */ + * supplied matcher */ /* open the device */ *udevp = udev = usb_open(dev); @@ -387,10 +387,10 @@ static int nut_libusb_open(usb_dev_handle **udevp, } /* collect the identifying information of this - device. Note that this is safe, because - there's no need to claim an interface for - this (and therefore we do not yet need to - detach any kernel drivers). */ + * device. Note that this is safe, because + * there's no need to claim an interface for + * this (and therefore we do not yet need to + * detach any kernel drivers). */ free(curDevice->Vendor); free(curDevice->Product); @@ -601,11 +601,11 @@ static int nut_libusb_open(usb_dev_handle **udevp, rdlen1); /* SECOND METHOD: find HID descriptor among "extra" bytes of - interface descriptor, i.e., bytes tucked onto the end of - descriptor 2. */ + * interface descriptor, i.e., bytes tucked onto the end of + * descriptor 2. */ /* Note: on some broken UPS's (e.g. Tripp Lite Smart1000LCD), - only this second method gives the correct result */ + * only this second method gives the correct result */ iface = &dev->config[usb_subdriver.usb_config_index].interface[usb_subdriver.hid_rep_index].altsetting[0]; for (i=0; iextralen; i+=iface->extra[i]) { upsdebugx(4, "i=%d, extra[i]=%02x, extra[i+1]=%02x", i, @@ -630,9 +630,9 @@ static int nut_libusb_open(usb_dev_handle **udevp, rdlen2); /* when available, always choose the second value, as it - seems to be more reliable (it is the one reported e.g. by - lsusb). Note: if the need arises, can change this to use - the maximum of the two values instead. */ + * seems to be more reliable (it is the one reported e.g. by + * lsusb). Note: if the need arises, can change this to use + * the maximum of the two values instead. */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { upsdebugx(1, "Eaton device v2.02. Using full report descriptor"); rdlens[0] = rdlen1; diff --git a/drivers/libusb1.c b/drivers/libusb1.c index c56746278a..955ada91bd 100644 --- a/drivers/libusb1.c +++ b/drivers/libusb1.c @@ -344,10 +344,10 @@ static int nut_libusb_open(libusb_device_handle **udevp, udev = *udevp; /* collect the identifying information of this - device. Note that this is safe, because - there's no need to claim an interface for - this (and therefore we do not yet need to - detach any kernel drivers). */ + * device. Note that this is safe, because + * there's no need to claim an interface for + * this (and therefore we do not yet need to + * detach any kernel drivers). */ free(curDevice->Vendor); free(curDevice->Product); @@ -666,14 +666,14 @@ static int nut_libusb_open(libusb_device_handle **udevp, upsdebugx(3, "HID descriptor length (method 1) %" PRIi32, rdlen1); /* SECOND METHOD: find HID descriptor among "extra" bytes of - interface descriptor, i.e., bytes tucked onto the end of - descriptor 2. */ + * interface descriptor, i.e., bytes tucked onto the end of + * descriptor 2. */ /* Note: on some broken UPS's (e.g. Tripp Lite Smart1000LCD), - only this second method gives the correct result */ + * only this second method gives the correct result */ /* for now, we always assume configuration 0, interface 0, - altsetting 0, as above. */ + * altsetting 0, as above. */ if_desc = &(conf_desc->interface[usb_subdriver.hid_rep_index].altsetting[0]); for (i = 0; i < if_desc->extra_length; i += if_desc->extra[i]) { @@ -696,9 +696,9 @@ static int nut_libusb_open(libusb_device_handle **udevp, upsdebugx(3, "HID descriptor length (method 2) %" PRIi32, rdlen2); /* when available, always choose the second value, as it - seems to be more reliable (it is the one reported e.g. by - lsusb). Note: if the need arises, can change this to use - the maximum of the two values instead. */ + * seems to be more reliable (it is the one reported e.g. by + * lsusb). Note: if the need arises, can change this to use + * the maximum of the two values instead. */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { upsdebugx(1, "Eaton device v2.02. Using full report descriptor"); rdlens[0] = rdlen1; diff --git a/drivers/liebert-esp2.c b/drivers/liebert-esp2.c index 4672ed5fd6..68e64826cd 100644 --- a/drivers/liebert-esp2.c +++ b/drivers/liebert-esp2.c @@ -525,10 +525,10 @@ void upsdrv_shutdown(void) char reply[8]; - if(!(do_command(cmd_setOutOffMode, reply, 8) != -1) && - (do_command(cmd_setOutOffDelay, reply, 8) != -1) && - (do_command(cmd_sysLoadKey, reply, 6) != -1) && - (do_command(cmd_shutdown, reply, 8) != -1) + if(!(do_command(cmd_setOutOffMode, reply, 8) != -1) + && (do_command(cmd_setOutOffDelay, reply, 8) != -1) + && (do_command(cmd_sysLoadKey, reply, 6) != -1) + && (do_command(cmd_shutdown, reply, 8) != -1) ) { upslogx(LOG_ERR, "Failed to shutdown UPS"); if (handling_upsdrv_shutdown > 0) diff --git a/drivers/macosx-ups.c b/drivers/macosx-ups.c index 92c31bfef2..db994a933a 100644 --- a/drivers/macosx-ups.c +++ b/drivers/macosx-ups.c @@ -270,11 +270,11 @@ void upsdrv_shutdown(void) /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* NOTE: Mac OS X already has shutdown routines - this driver is more - for monitoring and notification purposes. Still, there is a key that - might be useful to set in SystemConfiguration land. */ + * for monitoring and notification purposes. Still, there is a key that + * might be useful to set in SystemConfiguration land. */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); @@ -282,7 +282,7 @@ void upsdrv_shutdown(void) set_exit_flag(EF_EXIT_FAILURE); /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ @@ -327,7 +327,7 @@ static int setvar(const char *varname, const char *val) { upsdebug_SET_STARTING(varname, val); - if (!strcasecmp(varname, "ups.test.interval")) { + if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } diff --git a/drivers/main.c b/drivers/main.c index 9a8a4fc043..9f42910978 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -799,7 +799,7 @@ static void do_addvar(int vartype, const char *name, const char *desc, int reloa tmp = tmp->next; } - tmp = xmalloc(sizeof(vartab_t)); + tmp = (vartab_t *)xmalloc(sizeof(vartab_t)); tmp->vartype = vartype; tmp->var = xstrdup(name); diff --git a/drivers/metasys.c b/drivers/metasys.c index 4dab002167..19af864ad8 100644 --- a/drivers/metasys.c +++ b/drivers/metasys.c @@ -127,7 +127,7 @@ static void dump_buffer(unsigned char *buffer, int buf_len) { } /* send a read command to the UPS, it retries 5 times before give up - it's a 4 byte request (STX, LENGTH, COMMAND and CHECKSUM) */ + * it's a 4 byte request (STX, LENGTH, COMMAND and CHECKSUM) */ static void send_read_command(unsigned char command) { int retry; ssize_t sent; @@ -147,8 +147,8 @@ static void send_read_command(unsigned char command) { } /* send a write command to the UPS, the write command and the value to be written are passed - with a char* buffer - it retries 5 times before give up */ + * with a char* buffer + * it retries 5 times before give up */ static void send_write_command(unsigned char *command, size_t command_length) { int retry, checksum; ssize_t sent; @@ -215,8 +215,8 @@ static int get_answer(unsigned char *data) { } /* now we have the whole answer from the ups, we can checksum it - checksum byte is equal to the sum modulus 256 of all the data bytes + packet_length - (no STX no checksum byte itself) */ + * checksum byte is equal to the sum modulus 256 of all the data bytes + packet_length + * (no STX no checksum byte itself) */ checksum = packet_length; for (i = 0; i < (packet_length - 1); i++) checksum += my_buf[i]; checksum = checksum % 256; @@ -231,8 +231,8 @@ static int get_answer(unsigned char *data) { } /* send a read command and try get the answer, if something fails, it retries (5 times max) - if it is on the 4th or 5th retry, it will flush the serial before sending commands - it returns the length of the received answer or -1 in case of failure */ + * if it is on the 4th or 5th retry, it will flush the serial before sending commands + * it returns the length of the received answer or -1 in case of failure */ static int command_read_sequence(unsigned char command, unsigned char *data) { int bytes_read = 0; int retry = 0; @@ -253,8 +253,8 @@ static int command_read_sequence(unsigned char command, unsigned char *data) { } /* send a write command and try get the answer, if something fails, it retries (5 times max) - if it is on the 4th or 5th retry, it will flush the serial before sending commands - it returns the length of the received answer or -1 in case of failure */ + * if it is on the 4th or 5th retry, it will flush the serial before sending commands + * it returns the length of the received answer or -1 in case of failure */ static int command_write_sequence(unsigned char *command, size_t command_length, unsigned char *answer) { int bytes_read = 0; int retry = 0; @@ -877,9 +877,9 @@ void upsdrv_shutdown(void) unsigned char command[10], answer[10]; /* Ensure that the ups is configured for automatically - restart after a complete battery discharge - and when the power comes back after a shutdown. - Similar code to "shutdown.restart" but different timeouts. + * restart after a complete battery discharge + * and when the power comes back after a shutdown. + * Similar code to "shutdown.restart" but different timeouts. */ if (! autorestart) { command[0]=UPS_SET_TIMES_ON_BATTERY; @@ -909,7 +909,7 @@ void upsdrv_shutdown(void) command_write_sequence(command, 9, answer); /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ @@ -1011,8 +1011,9 @@ static int instcmd(const char *cmdname, const char *extra) command[0]=UPS_SET_BATTERY_TEST; command[1]=0x01; /* 0 = perform battery test - 1 = force UPS on battery power - 2 = restore standard mode (mains power) */ + * 1 = force UPS on battery power + * 2 = restore standard mode (mains power) + */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } @@ -1024,8 +1025,9 @@ static int instcmd(const char *cmdname, const char *extra) command[0]=UPS_SET_BATTERY_TEST; command[1]=0x02; /* 0 = perform battery test - 1 = force UPS on battery power - 2 = restore standard mode (mains power) */ + * 1 = force UPS on battery power + * 2 = restore standard mode (mains power) + */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } @@ -1037,8 +1039,9 @@ static int instcmd(const char *cmdname, const char *extra) command[0]=UPS_SET_BATTERY_TEST; command[1]=0x00; /* 0 = perform battery test - 1 = force UPS on battery power - 2 = restore standard mode (mains power) */ + * 1 = force UPS on battery power + * 2 = restore standard mode (mains power) + */ send_write_command(command, 2); sleep(15); res = get_answer(answer); @@ -1079,8 +1082,9 @@ static int instcmd(const char *cmdname, const char *extra) command[0]=UPS_SET_BUZZER_MUTE; command[1]=0x00; /* 0 = not muted - 1 = muted - 2 = read current status */ + * 1 = muted + * 2 = read current status + */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } @@ -1090,8 +1094,9 @@ static int instcmd(const char *cmdname, const char *extra) command[0]=UPS_SET_BUZZER_MUTE; command[1]=0x01; /* 0 = not muted - 1 = muted - 2 = read current status */ + * 1 = muted + * 2 = read current status + */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } diff --git a/drivers/mge-hid.c b/drivers/mge-hid.c index 76dbf8f16d..1922a135ac 100644 --- a/drivers/mge-hid.c +++ b/drivers/mge-hid.c @@ -121,6 +121,8 @@ static usb_device_id_t mge_usb_device_table[] = { #endif /* !SHUT_MODE => USB */ typedef enum { + /* See note in the sentinel (last) entry of the mapping table + * if you ever want to change this name to a different number */ MGE_DEFAULT_OFFLINE = 0, MGE_PEGASUS = 0x100, MGE_3S = 0x110, @@ -1971,7 +1973,12 @@ static models_name_t mge_model_names [] = { "GALAXY", "3000_30", MGE_DEFAULT, "Galaxy 3000 30 kVA" }, /* end of structure. */ - { NULL, NULL, 0, NULL } + /* NOTE: Compilers want a named enum value here; + * table-iteration code may care about it being + * exactly zero to act as a sentinel. If you ever + * need to redefine MGE_DEFAULT_OFFLINE to another + * number, provide a name that resolves to zero here. */ + { NULL, NULL, MGE_DEFAULT_OFFLINE, NULL } }; diff --git a/drivers/mge-utalk.c b/drivers/mge-utalk.c index d192cff8d4..a69c260e20 100644 --- a/drivers/mge-utalk.c +++ b/drivers/mge-utalk.c @@ -129,8 +129,9 @@ static int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); static void enable_ups_comm(void); static void disable_ups_comm(void); -static void extract_info(const char *buf, const mge_info_item_t *mge, - char *infostr, size_t infolen); +static void extract_info( + const char *buf, const mge_info_item_t *mge, + char *infostr, size_t infolen); static const char *info_variable_cmd(const char *type); static bool_t info_variable_ok(const char *type); static int get_ups_status(void); @@ -259,7 +260,7 @@ void upsdrv_initinfo(void) /* loop until we have at status */ tries = 0; do { - printf("."); + printf("."); /* get model information in ASCII string form: */ bytes_rcvd = mge_command(buf, sizeof(buf), "Si 1"); @@ -289,45 +290,44 @@ void upsdrv_initinfo(void) } } else - { + { upsdebugx(1, "initinfo: 'Si 1' unavailable, switching to 'Si' command"); /* get model information, numbered form, : */ bytes_rcvd = mge_command(buf, sizeof(buf), "Si"); - if(bytes_rcvd > 0 && buf[0] != '?') { - upsdebugx(1, "initinfo: Si == >%s<", buf); + if (bytes_rcvd > 0 && buf[0] != '?') { + upsdebugx(1, "initinfo: Si == >%s<", buf); - printf("\nCAUTION : This is an older model. It may not support too much polling.\nPlease read man mge-utalk and use pollinterval\n"); + printf("\nCAUTION : This is an older model. It may not support too much polling.\nPlease read man mge-utalk and use pollinterval\n"); - p = strchr(buf, ' '); + p = strchr(buf, ' '); - if ( p != NULL ) { - *p = '\0'; - si_data1 = atoi(buf); - v = p+1; - p = strchr(v, ' '); - } + if ( p != NULL ) { + *p = '\0'; + si_data1 = atoi(buf); + v = p+1; + p = strchr(v, ' '); + } - if ( p != NULL ) { - *p = '\0'; - si_data2 = atoi(v); - } + if ( p != NULL ) { + *p = '\0'; + si_data2 = atoi(v); + } /* Parsing legacy model table in order to find it */ for ( legacy_model = mge_model ; legacy_model->name != NULL ; legacy_model++ ) { - if(legacy_model->Data1 == si_data1 && legacy_model->Data2 == si_data2){ + if (legacy_model->Data1 == si_data1 && legacy_model->Data2 == si_data2) { model = legacy_model->name; upsdebugx(1, "initinfo: UPS model == >%s<", model); break; + } } - } - - if( model == NULL ) - printf("No model found by that model and version ID\nPlease contact us with UPS model, name and reminder info\nReminder info : Data1=%i , Data2=%i\n", si_data1, si_data2); + if (model == NULL) + printf("No model found by that model and version ID\nPlease contact us with UPS model, name and reminder info\nReminder info : Data1=%i , Data2=%i\n", si_data1, si_data2); } - } + } if ( model ) { upsdebugx(2, "Got model name: %s", model); @@ -465,10 +465,10 @@ void upsdrv_updateinfo(void) dstate_dataok(); } else { - upslogx(LOG_NOTICE, "updateinfo: Cannot update %s", item->type); - /* try to re enable communication */ - disable_ups_comm(); - enable_ups_comm(); + upslogx(LOG_NOTICE, "updateinfo: Cannot update %s", item->type); + /* try to re-enable communication */ + disable_ups_comm(); + enable_ups_comm(); } } /* if item->ok */ } @@ -750,8 +750,9 @@ static void enable_ups_comm(void) NOTE: buf="?" must be handled before calling extract_info buf is changed inspite of const !!!!! */ -static void extract_info(const char *buf, const mge_info_item_t *item, - char *infostr, size_t infolen) +static void extract_info( + const char *buf, const mge_info_item_t *item, + char *infostr, size_t infolen) { /* initialize info string */ infostr[0] = '\0'; diff --git a/drivers/mge-xml.c b/drivers/mge-xml.c index ab6fb073ea..f4c74e05ab 100644 --- a/drivers/mge-xml.c +++ b/drivers/mge-xml.c @@ -132,7 +132,7 @@ typedef struct { uint32_t xmlflags; /* XML flags (to be used to determine what kind of variable this is */ size_t xmllen; /* length of the XML string */ const char *(*convert)(const char *value); /* conversion function from XML<->NUT value (returns - NULL if no further processing is required) */ + * NULL if no further processing is required) */ } xml_info_t; static const char *online_info(const char *arg_val) diff --git a/drivers/microdowell.c b/drivers/microdowell.c index f4f588cae7..efb092368f 100644 --- a/drivers/microdowell.c +++ b/drivers/microdowell.c @@ -246,8 +246,8 @@ static unsigned char * CmdSerial(unsigned char *OutBuffer, size_t Len, unsigned { /* FramePointer to valid data! */ p = InpBuff + ups.FramePointer ; - /* p now point to valid data. - check if it is a error code. */ + /* p now points to valid data. + * check if it is a error code. */ ErrCode = CheckErrCode(p) ; if (!ErrCode) { @@ -270,7 +270,7 @@ static unsigned char * CmdSerial(unsigned char *OutBuffer, size_t Len, unsigned if (ups.ErrCount > 100) ups.ErrCount = 100 ; } - return(NULL) ; /* There have been errors in the reading of the data */ + return((unsigned char *)NULL) ; /* There have been errors in the reading of the data */ } static int detect_hardware(void) @@ -908,12 +908,12 @@ void upsdrv_initinfo(void) if (detect_hardware() == -1) { fatalx(EXIT_FAILURE, - "Unable to detect a Microdowell's Enterprise UPS on port %s\nCheck the cable, port name and try again", device_path); + "Unable to detect a Microdowell's Enterprise UPS on port %s\nCheck the cable, port name and try again", device_path); } - /* I set the correspondig UPS variables - They were read in 'detect_hardware()' - some other variables were set in 'detect_hardware()' */ + /* I set the corresponding UPS variables + * They were read in 'detect_hardware()' + * some other variables were set in 'detect_hardware()' */ dstate_setinfo("ups.model", "Enterprise N%s", ups.UpsModel+3) ; dstate_setinfo("ups.power.nominal", "%d", atoi(ups.UpsModel+3) * 100) ; dstate_setinfo("ups.realpower.nominal", "%d", atoi(ups.UpsModel+3) * 60) ; @@ -1056,7 +1056,7 @@ void upsdrv_initups(void) ser_set_speed(upsfd, device_path, B19200) ; /* need to clear RTS and DTR: otherwise with default cable, communication will be problematic - It is the same as removing pin7 from cable (pin 7 is needed for Plug&Play compatibility) */ + * It is the same as removing pin7 from cable (pin 7 is needed for Plug&Play compatibility) */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 0); diff --git a/drivers/microsol-apc.h b/drivers/microsol-apc.h index 6f38d28b77..9390a773d7 100644 --- a/drivers/microsol-apc.h +++ b/drivers/microsol-apc.h @@ -29,18 +29,18 @@ /* Supported UPS models */ static const unsigned int MODELS[MODEL_COUNT] = { - 183 /* APC Back-UPS BZ2200I-BR */ , - 190 /* APC Back-UPS BZ1500-BR */ , - 191 /* APC Back-UPS BZ2200BI-BR */ + 183 /* APC Back-UPS BZ2200I-BR */ , + 190 /* APC Back-UPS BZ1500-BR */ , + 191 /* APC Back-UPS BZ2200BI-BR */ }; /* Note: int type here is aligned with the "nominal_power" * variable in microsol-common.h and many related drivers. */ static const int NOMINAL_POWER[MODEL_COUNT] = { - 2200 /* Model 183 */ , - 1500 /* Model 190 */ , - 2200 /* Model 191 */ + 2200 /* Model 183 */ , + 1500 /* Model 190 */ , + 2200 /* Model 191 */ }; /* Curves for output voltage (depends on relay state and battery state) @@ -50,32 +50,32 @@ static const int NOMINAL_POWER[MODEL_COUNT] = { /* For on-line UPS */ static const float OUTPUT_VOLTAGE_MULTIPLIER_A[MODEL_COUNT][2][8] = { { - { 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831}, - { 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566} - } /* Model 183 */ , + { 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831}, + { 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566} + } /* Model 183 */ , { - { 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266}, - { 5.59, 9.47, 13.7, 0.0, 0.0, 0.0, 0.0, 0.0} - } /* Model 190 */ , + { 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266}, + { 5.59, 9.47, 13.7, 0.0, 0.0, 0.0, 0.0, 0.0} + } /* Model 190 */ , { - { 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00}, - { 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26} - } /* Model 191 */ + { 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00}, + { 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26} + } /* Model 191 */ }; static const float OUTPUT_VOLTAGE_MULTIPLIER_B[MODEL_COUNT][2][8] = { { - { -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374}, - { 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93} - } /* Model 183 */ , + { -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374}, + { 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93} + } /* Model 183 */ , { - { 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694}, - { 5.4, 6.5, 17.6, 0.0, 0.0, 0.0, 0.0, 0.0} - } /* Model 190 */ , + { 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694}, + { 5.4, 6.5, 17.6, 0.0, 0.0, 0.0, 0.0, 0.0} + } /* Model 190 */ , { - { 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0}, - { -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91} - } /* Model 191 */ + { 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0}, + { -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91} + } /* Model 191 */ }; /* Curves for output current @@ -83,130 +83,136 @@ static const float OUTPUT_VOLTAGE_MULTIPLIER_B[MODEL_COUNT][2][8] = { */ static const float OUTPUT_CURRENT_MULTIPLIER_A[MODEL_COUNT][2] = { { - 0.0892999991774559, - 0.09070000052452087 } /* Model 183 */ , + 0.0892999991774559, + 0.09070000052452087 + } /* Model 183 */ , { - 0.1264, - 0.1303 } /* Model 190 */ , + 0.1264, + 0.1303 + } /* Model 190 */ , { - 0.13819999992847443, - 0.08959999680519104 } /* Model 191 */ , + 0.13819999992847443, + 0.08959999680519104 + } /* Model 191 */ , }; static const float OUTPUT_CURRENT_MULTIPLIER_B[MODEL_COUNT][2] = { { - 0.09350000321865082, - 0.14550000429153442 } /* Model 183 */ , + 0.09350000321865082, + 0.14550000429153442 + } /* Model 183 */ , { - 0.522, - 0.468 } /* Model 190 */ , + 0.522, + 0.468 + } /* Model 190 */ , { - 0.12999999523162842, - 0.1881999969482422 } /* Model 191 */ + 0.12999999523162842, + 0.1881999969482422 + } /* Model 191 */ }; /* Curves for input voltage (depends on nominal output voltage) * Second index: Nominal output voltage = 220V (1) or 115V (0). */ static const float INPUT_VOLTAGE_MULTIPLIER_A[MODEL_COUNT][2] = { - { 1.7937, 1.7937 } /* Model 183 */ , - { 1.8, 1.8 } /* Model 190 */ , + { 1.7937, 1.7937 } /* Model 183 */ , + { 1.8, 1.8 } /* Model 190 */ , { 1.4825, 1.4952 } /* Model 191 */ }; static const float INPUT_VOLTAGE_MULTIPLIER_B[MODEL_COUNT][2] = { - { 1.854, 1.854 } /* Model 183 */ , - { 2.224, 2.224 } /* Model 190 */ , + { 1.854, 1.854 } /* Model 183 */ , + { 2.224, 2.224 } /* Model 190 */ , { 0.0853, -2.4241 } /* Model 191 */ }; /* Curves for battery voltage */ static const float BATTERY_VOLTAGE_MULTIPLIER_A[MODEL_COUNT] = { - 0.1551 /* Model 183 */ , - 0.1513 /* Model 190 */ , - 0.1543 /* Model 191 */ + 0.1551 /* Model 183 */ , + 0.1513 /* Model 190 */ , + 0.1543 /* Model 191 */ }; static const float BATTERY_VOLTAGE_MULTIPLIER_B[MODEL_COUNT] = { - 0.0654 /* Model 183 */ , - 0.7153 /* Model 190 */ , - 0.1414 /* Model 191 */ + 0.0654 /* Model 183 */ , + 0.7153 /* Model 190 */ , + 0.1414 /* Model 191 */ }; /* Real power estimation curves (depends on relay state) */ /* * Remarks: - * - Model 190 use a direct real power determination (no need for curve selectors) + * - Model 190 uses a direct real power determination (no need for curve selectors) */ static const float REAL_POWER_CURVE_SELECTOR_A1[MODEL_COUNT][8] = { - { 0.24, 0.26, 0.0, 0.0, 0.24, 0.26, 0.0, 0.28 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 0.24, 0.26, 0.0, 0.0, 0.24, 0.26, 0.0, 0.28 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.24, 0.26, 0.0, 0.0, 0.24, 0.26, 0.0, 0.28 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B1[MODEL_COUNT][8] = { - { 83.15, 81.23, 0.0, 0.0, 83.49, 79.05, 0.0, 85.67 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 83.15, 81.23, 0.0, 0.0, 83.49, 79.05, 0.0, 85.67 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 83.15, 81.23, 0.0, 0.0, 83.49, 79.05, 0.0, 85.67 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_A2[MODEL_COUNT][8] = { - { 0.0763, 0.081, 0.0919, 0.0, 0.0741, 0.0828, 0.0, 0.0938 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 0.0763, 0.081, 0.0919, 0.0, 0.0741, 0.0828, 0.0, 0.0938 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.0763, 0.081, 0.0919, 0.0, 0.0741, 0.0828, 0.0, 0.0938 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B2[MODEL_COUNT][8] = { - { 81.732, 94.459, 86.686, 0.0, 84.657, 84.999, 0.0, 78.097 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 81.732, 94.459, 86.686, 0.0, 84.657, 84.999, 0.0, 78.097 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 81.732, 94.459, 86.686, 0.0, 84.657, 84.999, 0.0, 78.097 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_A3[MODEL_COUNT][8] = { - { 0.0744, 0.0808, 0.0885, 0.0, 0.0732, 0.084, 0.0, 0.0955 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 0.0744, 0.0808, 0.0885, 0.0, 0.0732, 0.084, 0.0, 0.0955 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.0744, 0.0808, 0.0885, 0.0, 0.0732, 0.084, 0.0, 0.0955 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B3[MODEL_COUNT][8] = { - { 122.06, 122.9, 125.75, 0.0, 120.39, 108.52, 0.0, 92.239 } /* Model 183 */ , - { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , + { 122.06, 122.9, 125.75, 0.0, 120.39, 108.52, 0.0, 92.239 } /* Model 183 */ , + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 122.06, 122.9, 125.75, 0.0, 120.39, 108.52, 0.0, 92.239 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A1[MODEL_COUNT][8] = { - { 0.08040007075206226, 0.0894, 0.0999, 0.0, 0.0813, 0.0905, 0.0, 0.1005 } /* Model 183 */ , - { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , + { 0.08040007075206226, 0.0894, 0.0999, 0.0, 0.0813, 0.0905, 0.0, 0.1005 } /* Model 183 */ , + { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.08040007075206226, 0.0894, 0.0999, 0.0, 0.0813, 0.0905, 0.0, 0.1005 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B1[MODEL_COUNT][8] = { - { 45.292, 41.928, 41.727, 0.0, 40.269, 41.81, 0.0, 43.458 } /* Model 183 */ , - { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , + { 45.292, 41.928, 41.727, 0.0, 40.269, 41.81, 0.0, 43.458 } /* Model 183 */ , + { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { 45.292, 41.928, 41.727, 0.0, 40.269, 41.81, 0.0, 43.458 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A2[MODEL_COUNT][8] = { - { 0.08630063689870031, 0.0946, 0.1068, 0.0, 0.086, 0.0967, 0.0, 0.1088 } /* Model 183 */ , - { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , + { 0.08630063689870031, 0.0946, 0.1068, 0.0, 0.086, 0.0967, 0.0, 0.1088 } /* Model 183 */ , + { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.08630063689870031, 0.0946, 0.1068, 0.0, 0.086, 0.0967, 0.0, 0.1088 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B2[MODEL_COUNT][8] = { - { 8.3927, 9.2393, 8.2852, 0.0, 8.301, 6.7636, 0.0, 8.2842 } /* Model 183 */ , - { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , + { 8.3927, 9.2393, 8.2852, 0.0, 8.301, 6.7636, 0.0, 8.2842 } /* Model 183 */ , + { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { 8.3927, 9.2393, 8.2852, 0.0, 8.301, 6.7636, 0.0, 8.2842 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A3[MODEL_COUNT][8] = { - { 0.0896001146881468, 0.0991, 0.1116, 0.0, 0.0967, 0.1068, 0.0, 0.1169 } /* Model 183 */ , - { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , + { 0.0896001146881468, 0.0991, 0.1116, 0.0, 0.0967, 0.1068, 0.0, 0.1169 } /* Model 183 */ , + { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.0896001146881468, 0.0991, 0.1116, 0.0, 0.0967, 0.1068, 0.0, 0.1169 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B3[MODEL_COUNT][8] = { - { -31.115, -33.777, -33.826, 0.0, -59.513, -57.729, 0.0, -41.333 } /* Model 183 */ , - { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , + { -31.115, -33.777, -33.826, 0.0, -59.513, -57.729, 0.0, -41.333 } /* Model 183 */ , + { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { -31.115, -33.777, -33.826, 0.0, -59.513, -57.729, 0.0, -41.333 } /* Model 191 */ }; @@ -215,16 +221,16 @@ static const float REAL_POWER_MULTIPLIER_B3[MODEL_COUNT][8] = { * Second index: Recharging battery flag: charging (1) or charged/discharging (0) */ static const float MAX_BATTERY_VOLTAGE[MODEL_COUNT][2] = { - { 27.0, 29.5 } /* Model 183 */ , - { 27.0, 29.5 } /* Model 190 */ , + { 27.0, 29.5 } /* Model 183 */ , + { 27.0, 29.5 } /* Model 190 */ , { 27.0, 29.5 } /* Model 191 */ }; /** Minimum battery voltage, used to estimate battery charge */ static const float MIN_BATTERY_VOLTAGE[MODEL_COUNT] = { - 20 /* Model 183 */ , - 20 /* Model 190 */ , - 20 /* Model 191 */ + 20 /* Model 183 */ , + 20 /* Model 190 */ , + 20 /* Model 191 */ }; -#endif /* INCLUDED_MICROSOL_APC_H */ +#endif /* INCLUDED_MICROSOL_APC_H */ diff --git a/drivers/netxml-ups.c b/drivers/netxml-ups.c index 20faa09229..8313a75eaa 100644 --- a/drivers/netxml-ups.c +++ b/drivers/netxml-ups.c @@ -247,7 +247,7 @@ static char *product_page = NULL; /* Support functions */ static void netxml_alarm_set(void); static void netxml_status_set(void); -static int netxml_authenticate(void *userdata, const char *realm, int attempt, char *username, char *password); +static int netxml_authenticate(void *userdata, const char *realm, int try_num, char *username, char *password); static int netxml_dispatch_request(ne_request *request, ne_xml_parser *parser); static int netxml_get_page(const char *page); @@ -423,13 +423,13 @@ void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* fatalx(EXIT_FAILURE, "shutdown not supported"); */ /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ @@ -840,7 +840,7 @@ static int netxml_alarm_subscribe(const char *page) ne_request_destroy(request); /* due to different formats used by the various NMCs, we need to\ - break up the reply in lines and parse each one separately */ + * break up the reply in lines and parse each one separately */ for (s = strtok(resp_buf, "\r\n"); s != NULL; s = strtok(NULL, "\r\n")) { long long int tmp_port = -1, tmp_secret = -1; upsdebugx(2, "%s: parsing %s", __func__, s); @@ -974,12 +974,12 @@ static int netxml_dispatch_request(ne_request *request, ne_xml_parser *parser) } /* Supply the 'login' and 'password' when authentication is required */ -static int netxml_authenticate(void *userdata, const char *realm, int attempt, char *username, char *password) +static int netxml_authenticate(void *userdata, const char *realm, int try_num, char *username, char *password) { char *val; NUT_UNUSED_VARIABLE(userdata); - upsdebugx(2, "%s: realm = [%s], attempt = %d", __func__, realm, attempt); + upsdebugx(2, "%s: realm = [%s], attempt = %d", __func__, realm, try_num); val = getval("login"); snprintf(username, NE_ABUFSIZ, "%s", val ? val : ""); @@ -987,7 +987,7 @@ static int netxml_authenticate(void *userdata, const char *realm, int attempt, c val = getval("password"); snprintf(password, NE_ABUFSIZ, "%s", val ? val : ""); - return attempt; + return try_num; } /* Convert the local status information to NUT format and set NUT diff --git a/drivers/nhs_ser.c b/drivers/nhs_ser.c index a7dbfe0954..5b08856c7f 100644 --- a/drivers/nhs_ser.c +++ b/drivers/nhs_ser.c @@ -945,7 +945,7 @@ static int write_serial_int(int fd, const unsigned int *data, size_t size) { uint8_t *message = NULL; size_t i = 0; - message = xcalloc(size, sizeof(uint8_t)); + message = (uint8_t *)xcalloc(size, sizeof(uint8_t)); for (i = 0; i < size; i++) { message[i] = (uint8_t)data[i]; /* //upsdebugx(5, "%d %c %u %d %c %u", message[i], message[i], data[i], data[i]); */ diff --git a/drivers/nut-ipmipsu.c b/drivers/nut-ipmipsu.c index c9229f8e7a..477c6271f4 100644 --- a/drivers/nut-ipmipsu.c +++ b/drivers/nut-ipmipsu.c @@ -27,7 +27,7 @@ #include "nut-ipmi.h" #define DRIVER_NAME "IPMI PSU driver" -#define DRIVER_VERSION "0.36" +#define DRIVER_VERSION "0.37" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -190,7 +190,7 @@ static int setvar(const char *varname, const char *val) { upsdebug_SET_STARTING(varname, val); - if (!strcasecmp(varname, "ups.test.interval")) { + if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } diff --git a/drivers/nut-libfreeipmi.c b/drivers/nut-libfreeipmi.c index 8e37414772..e136d026fb 100644 --- a/drivers/nut-libfreeipmi.c +++ b/drivers/nut-libfreeipmi.c @@ -336,25 +336,30 @@ static void libfreeipmi_cleanup(void) if (fru_ctx) { ipmi_fru_close_device_id (fru_ctx); ipmi_fru_ctx_destroy (fru_ctx); + fru_ctx = NULL; } if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); + sdr_ctx = NULL; } #ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); + sdr_parse_ctx = NULL; } #endif if (ipmi_ctx) { ipmi_ctx_close (ipmi_ctx); ipmi_ctx_destroy (ipmi_ctx); + ipmi_ctx = NULL; } if (mon_ctx) { ipmi_monitoring_ctx_destroy (mon_ctx); + mon_ctx = NULL; } } @@ -632,15 +637,16 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) if (ipmi_sdr_ctx_errnum (sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { - if (ipmi_sdr_cache_create (sdr_ctx, - ipmi_ctx, CACHE_LOCATION, - NUT_IPMI_SDR_CACHE_DEFAULTS, - NULL, NULL) < 0) + if (ipmi_sdr_cache_create ( + sdr_ctx, ipmi_ctx, CACHE_LOCATION, + NUT_IPMI_SDR_CACHE_DEFAULTS, + NULL, NULL) < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", ipmi_sdr_ctx_errormsg (sdr_ctx)); } + if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) { if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) @@ -808,11 +814,13 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) /* Cleanup */ if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); + sdr_ctx = NULL; } #ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); + sdr_parse_ctx = NULL; } #endif /* HAVE_FREEIPMI_11X_12X */ diff --git a/drivers/nut-upower.c b/drivers/nut-upower.c new file mode 100644 index 0000000000..84a1ac0a0e --- /dev/null +++ b/drivers/nut-upower.c @@ -0,0 +1,354 @@ +/* drivers/nut-upower.c - Driver for UPower via D-Bus + * + * Copyright (C) 2026 Tim Niemueller + * + * Links against standard NUT driver core. + * Requires: glib-2.0, gio-2.0 + */ + +#include "main.h" +#include "dstate.h" + +#include +#include +#include +#include + +#define DRIVER_NAME "UPower D-Bus Driver" +#define DRIVER_VERSION "0.01" + +/* UPower Constants */ +#define UPOWER_BUS "org.freedesktop.UPower" +#define UPOWER_PATH "/org/freedesktop/UPower" +#define UPOWER_IFACE "org.freedesktop.UPower" +#define DEVICE_IFACE "org.freedesktop.UPower.Device" +#define PROPS_IFACE "org.freedesktop.DBus.Properties" + +/* Global DBus Connection Objects */ +static GDBusConnection *connection = NULL; +static char *ups_object_path = NULL; +static double lowbatt_pct = 20.0; + +/* NUT Driver Info Structure */ +upsdrv_info_t upsdrv_info = { + DRIVER_NAME, + DRIVER_VERSION, + "Tim Niemueller ", + DRV_EXPERIMENTAL, + { NULL } +}; + +/* -------------------------------------------------------------------------- */ +/* Map UPower State to NUT Status */ +/* -------------------------------------------------------------------------- */ +static void set_nut_status(guint state, gdouble percentage) +{ + /* Clear previous status */ + status_init(); + + /* UPower States: + * 1: Charging + * 2: Discharging + * 3: Empty + * 4: Fully Charged + * 5: Pending Charge + * 6: Pending Discharge + */ + + switch (state) { + case 1: /* Charging */ + status_set("OL CHRG"); + break; + case 2: /* Discharging */ + status_set("OB DISCHRG"); + break; + case 4: /* Full */ + status_set("OL"); + break; + case 3: /* Empty */ + status_set("OB LB"); + break; + default: /* Unknown / Pending */ + status_set("OL"); /* Default to Online to prevent shutdowns */ + break; + } + + /* Override for Low Battery based on percentage */ + if (percentage < lowbatt_pct) { + status_set("LB"); + } + + status_commit(); +} + +/* -------------------------------------------------------------------------- */ +/* Find the First UPS Device (auto) or a specific one (device_path not auto) */ +/* -------------------------------------------------------------------------- */ +static int find_ups_device(void) +{ + GError *error = NULL; + GVariant *result; + GVariantIter iter; + gchar *obj_path; + int found = 0; + + /* Call EnumerateDevices on the main UPower object */ + result = g_dbus_connection_call_sync( + connection, + UPOWER_BUS, UPOWER_PATH, UPOWER_IFACE, + "EnumerateDevices", + NULL, /* No params */ + G_VARIANT_TYPE("(ao)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error + ); + + if (error) { + fatalx(EXIT_FAILURE, "DBus Error enumerating devices: %s", error->message); + } + + /* Iterate the result array of object paths */ + g_variant_iter_init(&iter, g_variant_get_child_value(result, 0)); + + while (g_variant_iter_loop(&iter, "o", &obj_path)) { + upsdebugx(2, "Enumerated UPower device: %s", obj_path); + + /* Check if we are looking for a specific path */ + if (device_path && strcmp(device_path, "auto") != 0 && *device_path != '\0') { + if (strstr(obj_path, device_path)) { + upsdebugx(1, "Match found for specific path '%s': %s", device_path, obj_path); + ups_object_path = strdup(obj_path); + found = 1; + break; + } + } else { + /* Auto-detection: Check for substring "ups_" */ + if (strstr(obj_path, "ups_")) { + upsdebugx(1, "Auto-detected UPS device: %s", obj_path); + ups_object_path = strdup(obj_path); + found = 1; + break; + } + } + } + + g_variant_unref(result); + return found; +} + +/* -------------------------------------------------------------------------- */ +/* List Available UPower Devices */ +/* -------------------------------------------------------------------------- */ +static void list_upower_devices(void) +{ + GError *error = NULL; + GDBusConnection *conn; + GVariant *result; + GVariantIter iter; + gchar *obj_path; + + /* Initialize GLib type system */ + #if !GLIB_CHECK_VERSION(2, 36, 0) + g_type_init(); + #endif + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!conn) { + printf("Error: Failed to connect to System Bus: %s\n", error->message); + g_error_free(error); + return; + } + + result = g_dbus_connection_call_sync( + conn, + UPOWER_BUS, UPOWER_PATH, UPOWER_IFACE, + "EnumerateDevices", + NULL, + G_VARIANT_TYPE("(ao)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error + ); + + if (error) { + printf("Error enumerating devices: %s\n", error->message); + g_error_free(error); + g_object_unref(conn); + return; + } + + printf("\nAvailable UPower devices:\n"); + g_variant_iter_init(&iter, g_variant_get_child_value(result, 0)); + + while (g_variant_iter_loop(&iter, "o", &obj_path)) { + printf(" %s\n", obj_path); + } + + g_variant_unref(result); + g_object_unref(conn); +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Help / Usage */ +/* -------------------------------------------------------------------------- */ +void upsdrv_help(void) +{ + list_upower_devices(); +} +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Initialize Command Line Args */ +/* -------------------------------------------------------------------------- */ +void upsdrv_makevartable(void) +{ + addvar(VAR_VALUE, "lowbatt", "Low battery threshold, in percent (default: 20)"); +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Initialize UPS Connection */ +/* -------------------------------------------------------------------------- */ +void upsdrv_initups(void) +{ + GError *error = NULL; + const char *val; + + /* Initialize GLib type system */ + #if !GLIB_CHECK_VERSION(2, 36, 0) + g_type_init(); + #endif + + /* Connect to System Bus */ + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!connection) { + fatalx(EXIT_FAILURE, "Failed to connect to System Bus: %s", error->message); + } + + /* Find the UPS */ + if (!find_ups_device()) { + fatalx(EXIT_FAILURE, "No UPower device found containing 'ups_' in path."); + } + + upslogx(LOG_INFO, "Connected to UPower Device: %s", ups_object_path); + dstate_setinfo("driver.parameter.port", "%s", ups_object_path); + + /* Handle low battery threshold */ + if ((val = getval("lowbatt"))) { + lowbatt_pct = atof(val); + upsdebugx(1, "Low battery threshold set to: %.1f%%", lowbatt_pct); + } +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Update Info (The Main Loop) */ +/* -------------------------------------------------------------------------- */ +void upsdrv_updateinfo(void) +{ + GError *error = NULL; + GVariant *result, *props; + GVariantIter iter; + gchar *key; + GVariant *value; + gdouble voltage = 0.0, percentage = 0.0; + gint64 time_empty = 0; + guint state = 0; + const gchar *model = "Unknown"; + const gchar *vendor = "Unknown"; + const gchar *serial = "Unknown"; + + /* Fetch All Properties */ + result = g_dbus_connection_call_sync( + connection, + UPOWER_BUS, ups_object_path, PROPS_IFACE, + "GetAll", + g_variant_new("(s)", DEVICE_IFACE), + G_VARIANT_TYPE("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error + ); + + if (error) { + dstate_datastale(); + upslogx(LOG_WARNING, "Failed to get properties: %s", error->message); + g_error_free(error); + return; + } + + /* Parse Dictionary */ + props = g_variant_get_child_value(result, 0); + g_variant_iter_init(&iter, props); + + while (g_variant_iter_loop(&iter, "{sv}", &key, &value)) { + if (g_strcmp0(key, "Voltage") == 0) { + voltage = g_variant_get_double(value); + } else if (g_strcmp0(key, "Percentage") == 0) { + percentage = g_variant_get_double(value); + } else if (g_strcmp0(key, "State") == 0) { + state = g_variant_get_uint32(value); + } else if (g_strcmp0(key, "TimeToEmpty") == 0) { + time_empty = g_variant_get_int64(value); + } else if (g_strcmp0(key, "Model") == 0) { + model = g_variant_get_string(value, NULL); + } else if (g_strcmp0(key, "Vendor") == 0) { + vendor = g_variant_get_string(value, NULL); + } else if (g_strcmp0(key, "Serial") == 0) { + serial = g_variant_get_string(value, NULL); + } + } + + /* Update NUT Data Store (dstate) */ + dstate_setinfo("battery.charge", "%.1f", percentage); + dstate_setinfo("battery.voltage", "%.1f", voltage); + + if (time_empty > 0) { + dstate_setinfo("battery.runtime", "%lld", (long long)time_empty); + } + + dstate_setinfo("device.mfr", "%s", vendor); + dstate_setinfo("device.model", "%s", model); + dstate_setinfo("device.serial", "%s", serial); + + /* Update Status Flags */ + set_nut_status(state, percentage); + + /* Commit data */ + dstate_dataok(); + + g_variant_unref(props); + g_variant_unref(result); +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Tweak Program Names */ +/* -------------------------------------------------------------------------- */ +void upsdrv_tweak_prognames(void) +{ +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Initialize Info */ +/* -------------------------------------------------------------------------- */ +void upsdrv_initinfo(void) +{ + upsdrv_updateinfo(); +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Shutdown */ +/* -------------------------------------------------------------------------- */ +void upsdrv_shutdown(void) +{ + upslogx(LOG_ERR, "shutdown not supported"); +} + +/* -------------------------------------------------------------------------- */ +/* NUT Hook: Cleanup */ +/* -------------------------------------------------------------------------- */ +void upsdrv_cleanup(void) +{ + if (ups_object_path) free(ups_object_path); + if (connection) g_object_unref(connection); +} diff --git a/drivers/nutdrv_atcl_usb.c b/drivers/nutdrv_atcl_usb.c index b7745d142a..b51b7fa534 100644 --- a/drivers/nutdrv_atcl_usb.c +++ b/drivers/nutdrv_atcl_usb.c @@ -339,10 +339,10 @@ static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDev } /* collect the identifying information of this - device. Note that this is safe, because - there's no need to claim an interface for - this (and therefore we do not yet need to - detach any kernel drivers). */ + * device. Note that this is safe, because + * there's no need to claim an interface for + * this (and therefore we do not yet need to + * detach any kernel drivers). */ free(device->Vendor); free(device->Product); diff --git a/drivers/nutdrv_hashx.c b/drivers/nutdrv_hashx.c index 08c316af5d..ff6f7f81b5 100644 --- a/drivers/nutdrv_hashx.c +++ b/drivers/nutdrv_hashx.c @@ -139,8 +139,9 @@ static ssize_t hashx_recv(char *buf, size_t bufsize) { ssize_t nread; - nread = ser_get_line(upsfd, buf, bufsize - 1, ENDCHAR, IGNCHAR, - SER_WAIT_SEC, SER_WAIT_USEC); + nread = ser_get_line( + upsfd, buf, bufsize - 1, ENDCHAR, IGNCHAR, + SER_WAIT_SEC, SER_WAIT_USEC); assert(nread < (ssize_t) bufsize); buf[nread] = '\0'; @@ -149,8 +150,10 @@ static ssize_t hashx_recv(char *buf, size_t bufsize) char base_msg[128]; int n; - n = snprintf(base_msg, sizeof(base_msg), - "%s: read %" PRIiSIZE ": ", __func__, nread); + n = snprintf( + base_msg, sizeof(base_msg), + "%s: read %" PRIiSIZE ": ", + __func__, nread); assert(n > 0); upsdebug_ascii(4, base_msg, buf, nread); } @@ -188,14 +191,16 @@ static int hashx_send_command(const char *command) int status; if ((transferred = ser_send(upsfd, "%s%c", command, ENDCHAR)) != strlen (command) + 1) { - upslogx(LOG_ERR, "%s: Failed to send command: %s", - __func__, command); + upslogx(LOG_ERR, + "%s: Failed to send command: %s", + __func__, command); return STATUS_UNKNOWN_FAILURE; } if ((status = hashx_status_value(buf, sizeof(buf))) != STATUS_SUCCESS) { - upslogx(LOG_ERR, "%s: unexpected hash protocol response: %s (status %d)", - __func__, buf, status); + upslogx(LOG_ERR, + "%s: unexpected hash protocol response: %s (status %d)", + __func__, buf, status); } return status; @@ -256,8 +261,9 @@ void upsdrv_initinfo(void) for (i = 0; ; ++i) { upsdebugx(4, "Checking if device supports the #-protocol... [%" PRIuSIZE "]", i+1); if ((transferred = ser_send_char(upsfd, ENDCHAR)) != 1) { - fatalx(EXIT_FAILURE, "%s: Initialization failure %s", - __func__, device_path); + fatalx(EXIT_FAILURE, + "%s: Initialization failure %s", + __func__, device_path); } if ((status = hashx_status_value(buf, sizeof(buf))) == -1) { break; @@ -267,8 +273,9 @@ void upsdrv_initinfo(void) continue; } - fatalx(EXIT_FAILURE, "%s: unexpected hash protocol response: %s (status %d)", - __func__, buf, status); + fatalx(EXIT_FAILURE, + "%s: unexpected hash protocol response: %s (status %d)", + __func__, buf, status); } /* The K19 function needs a 16 bytes value and the device should reply @@ -277,17 +284,20 @@ void upsdrv_initinfo(void) * send one value we know about, to verify the protocol. */ if ((status = hashx_send_command(COMMAND_SET_SESSION_ID":"SESSION_ID)) != STATUS_SUCCESS) { - fatalx(EXIT_FAILURE, "%s: Failed to set session ID: %s", - __func__, SESSION_ID); + fatalx(EXIT_FAILURE, + "%s: Failed to set session ID: %s", + __func__, SESSION_ID); } if ((transferred = ser_send(upsfd, COMMAND_GET_SESSION_HASH"%c", ENDCHAR)) != 4) { fatalx(EXIT_FAILURE, "%s: Failed to get session hash", __func__); } - if ((transferred = hashx_recv(buf, sizeof(buf))) != strlen(SESSION_HASH) + 1 || - (transferred > 0 && strncmp(buf, "#"SESSION_HASH, sizeof(buf)) != 0)) { - fatalx(EXIT_FAILURE, "%s: unexpected hash protocol response: %s", - __func__, buf); + if ((transferred = hashx_recv(buf, sizeof(buf))) != strlen(SESSION_HASH) + 1 + || (transferred > 0 && strncmp(buf, "#"SESSION_HASH, sizeof(buf)) != 0) + ) { + fatalx(EXIT_FAILURE, + "%s: unexpected hash protocol response: %s", + __func__, buf); } /* XXX: Maybe now repeat the same with a random value, without checking @@ -314,8 +324,9 @@ void upsdrv_initinfo(void) fatalx(EXIT_FAILURE, "%s: Failed to get UPS info", __func__); } if ((transferred = hashx_recv(buf, sizeof(buf))) < 3) { - fatalx(EXIT_FAILURE, "%s: unexpected UPS info response: %s", - __func__, buf); + fatalx(EXIT_FAILURE, + "%s: unexpected UPS info response: %s", + __func__, buf); } /* This is in the format: * #1200,PE02022.002,000000000000,000000000000000000 @@ -362,8 +373,9 @@ void upsdrv_initinfo(void) upslogx(LOG_ERR, "%s: Failed to get UPS power info", __func__); } if ((transferred = hashx_recv(buf, sizeof(buf))) < 3) { - upslogx(LOG_ERR, "%s: unexpected UPS power info response: %s", - __func__, buf); + upslogx(LOG_ERR, + "%s: unexpected UPS power info response: %s", + __func__, buf); } /* This is in the format: * #1200,0720,230,40,70,05.20 @@ -396,9 +408,10 @@ void upsdrv_initinfo(void) } if (strsep(&reply, ",") != NULL) { - upslogx(LOG_WARNING, "This UPS returns unexpected power info fields (%s), " - "previously decoded values may have not been correctly assigned!", - buf + 1); + upslogx(LOG_WARNING, + "This UPS returns unexpected power info fields (%s), " + "previously decoded values may have not been correctly assigned!", + buf + 1); } upsh.instcmd = hashx_instcmd; @@ -450,22 +463,24 @@ void upsdrv_updateinfo(void) * S) UPS Status bytes (see below) */ status = buf + 1; - if ((ret = sscanf(status, "I%fO%fL%dB%dV%fF%fH%fR%dS", - &input_voltage, &output_voltage, &output_load, - &battery_charge, &battery_voltage, &input_frequency, - &output_frequency, &remaining_runtime)) == EOF || - ret < 1) { + if ((ret = sscanf( + status, "I%fO%fL%dB%dV%fF%fH%fR%dS", + &input_voltage, &output_voltage, &output_load, + &battery_charge, &battery_voltage, &input_frequency, + &output_frequency, &remaining_runtime)) == EOF || + ret < 1 + ) { upslogx(LOG_ERR, "%s: Impossible to parse: %s", __func__, status); dstate_datastale(); return; } upsdebugx(6, "Poll: input voltage %.1f, output voltage %.1f, load balance %d%%, " - "battery level: %d%%, battery voltage: %.1f, input frequency: %.1f, " - "output frequency %.1f, remaining runtime: %d minutes", - input_voltage, output_voltage, output_load, - battery_charge, battery_voltage, input_frequency, - output_frequency, remaining_runtime); + "battery level: %d%%, battery voltage: %.1f, input frequency: %.1f, " + "output frequency %.1f, remaining runtime: %d minutes", + input_voltage, output_voltage, output_load, + battery_charge, battery_voltage, input_frequency, + output_frequency, remaining_runtime); if (input_voltage >= 0) { dstate_setinfo("input.voltage", "%.1f", input_voltage); @@ -510,7 +525,7 @@ void upsdrv_updateinfo(void) if (!status_bytes || status_bytes_size < 5) { upslogx(LOG_ERR, "Status bytes are not enough: %" PRIuSIZE, - status_bytes_size); + status_bytes_size); dstate_dataok(); return; } @@ -621,7 +636,7 @@ static int hashx_instcmd(const char *cmd_name, const char *extra) return STAT_INSTCMD_HANDLED; upslogx(LOG_INSTCMD_FAILED, "Failed to execute command [%s] [%s]: %d", - NUT_STRARG(cmd_name), NUT_STRARG(extra), status); + NUT_STRARG(cmd_name), NUT_STRARG(extra), status); return STAT_INSTCMD_FAILED; } diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index 2dba7df7eb..ba6d6a4914 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -58,7 +58,7 @@ # define DRIVER_NAME "Generic Q* Serial driver" #endif /* QX_USB */ -#define DRIVER_VERSION "0.48" +#define DRIVER_VERSION "0.49" #ifdef QX_SERIAL # include "serial.h" @@ -333,7 +333,7 @@ static void analyze_mapping_usage(void) { return; } - unused_names = xcalloc(unused_bufsize, sizeof(char)); + unused_names = (char *)xcalloc(unused_bufsize, sizeof(char)); for (item = subdriver->qx2nut; item->info_type != NULL; item++) { if (!item) @@ -385,7 +385,7 @@ static void analyze_mapping_usage(void) { if (*pBufSize < SIZE_MAX - LARGEBUF) { *pBufSize = *pBufSize + LARGEBUF; upsdebugx(1, "%s: buffer overflowed, trying to re-allocate as %" PRIuSIZE, __func__, *pBufSize); - *pNames = realloc(*pNames, *pBufSize); + *pNames = (char *)realloc(*pNames, *pBufSize); if (!*pNames) { upsdebugx(1, "%s: buffer overflowed, will not report unused descriptor names", __func__); @@ -1798,7 +1798,7 @@ static int phoenixtec_command(const char *cmd, size_t cmdlen, char *buf, size_t *buf = '\0'; return ret; } - if ((e = memchr(p, '\r', (size_t)ret)) != NULL) break; + if ((e = (char *)memchr(p, '\r', (size_t)ret)) != NULL) break; } if (e != NULL && ++e < buf + buflen) { *e = '\0'; @@ -2252,12 +2252,12 @@ static int armac_command(const char *cmd, size_t cmdlen, char *buf, size_t bufle #if WITH_LIBUSB_1_0 /* Be conservative and do not break old Armac UPSes */ - use_interrupt = armac_endpoint_cache.ok + use_interrupt = (bool_t)(armac_endpoint_cache.ok && armac_endpoint_cache.in_endpoint_address == 0x82 && armac_endpoint_cache.in_bmAttributes & LIBUSB_TRANSFER_TYPE_INTERRUPT && armac_endpoint_cache.out_endpoint_address == 0x02 && armac_endpoint_cache.out_bmAttributes & LIBUSB_TRANSFER_TYPE_INTERRUPT - && armac_endpoint_cache.in_wMaxPacketSize == 64; + && armac_endpoint_cache.in_wMaxPacketSize == 64); #endif /* WITH_LIBUSB_1_0 */ if (use_interrupt && cmddatalen < armac_endpoint_cache.in_wMaxPacketSize) { @@ -3326,7 +3326,7 @@ void upsdrv_makevartable(void) snprintf(temp, sizeof(temp), "Set polling frequency, in seconds, to reduce data flow (default=%d)", - DEFAULT_POLLFREQ); + DEFAULT_POLLFREQ); addvar(VAR_VALUE, QX_VAR_POLLFREQ, temp); addvar(VAR_VALUE, "protocol", @@ -3445,6 +3445,8 @@ void upsdrv_updateinfo(void) retry = 0; dstate_dataok(); + + upsdebugx(1, "%s finished", __func__); } /* Initialise data from UPS */ @@ -3516,8 +3518,14 @@ void upsdrv_initinfo(void) upsh.instcmd = instcmd; /* Subdriver initinfo */ - if (subdriver->initinfo != NULL) + if (subdriver->initinfo != NULL) { + upsdebugx(2, "%s calling subdriver-specific initinfo()...", __func__); subdriver->initinfo(); + } else { + upsdebugx(2, "%s there is no subdriver-specific initinfo() to call", __func__); + } + + upsdebugx(1, "%s finished", __func__); } /* Open the port and the like and choose the subdriver */ @@ -3635,7 +3643,7 @@ void upsdrv_initups(void) ser_set_rts(upsfd, cablepower[i].rts); /* Allow some time to settle for the cablepower */ - usleep(100000); + usleep(1100000); # endif /* TESTING */ @@ -3725,7 +3733,7 @@ void upsdrv_initups(void) default: fatalx(EXIT_FAILURE, "Invalid regular expression: %s", - regex_array[ret]); + regex_array[ret]); } /* Link the matchers */ @@ -3793,12 +3801,32 @@ void upsdrv_initups(void) #endif /* QX_USB */ /* Choose subdriver */ +#if defined(QX_SERIAL) && defined(QX_USB) + upsdebugx(1, "%s: trying to match the handler for %s device", __func__, is_usb ? "USB" : "Serial"); +#else +# ifdef QX_SERIAL + upsdebugx(1, "%s: trying to match the handler for Serial device", __func__); +# endif +# ifdef QX_USB + upsdebugx(1, "%s: trying to match the handler for USB device", __func__); +# endif +# if !(defined(QX_SERIAL)) && !(defined(QX_USB)) + /* Should not get here... so it is even more interesting to see this */ + upsdebugx(1, "%s: trying to match the handler for a device (weird build of the driver does not discern Serial/USB)", __func__); +# endif +#endif if (!subdriver_matcher()) fatalx(EXIT_FAILURE, "Device not supported!"); /* Subdriver initups */ - if (subdriver->initups != NULL) + if (subdriver->initups != NULL) { + upsdebugx(2, "%s calling subdriver-specific initups()...", __func__); subdriver->initups(); + } else { + upsdebugx(2, "%s there is no subdriver-specific initups() to call", __func__); + } + + upsdebugx(1, "%s finished", __func__); } /* Close the ports and the like */ @@ -3844,6 +3872,7 @@ void upsdrv_cleanup(void) #endif /* TESTING */ + upsdebugx(1, "%s finished", __func__); } @@ -4096,6 +4125,8 @@ static int subdriver_matcher(void) const char *protocol = getval("protocol"); int i; + upsdebugx(2, "%s...", __func__); + /* Select the subdriver for this device */ for (i = 0; subdriver_list[i] != NULL; i++) { @@ -4124,10 +4155,13 @@ static int subdriver_matcher(void) subdriver = subdriver_list[i]; + upsdebugx(2, "%s: Trying protocol %s...", __func__, subdriver->name); if (subdriver->claim()) { + upsdebugx(1, "%s: Trying protocol %s: claim succeeded", __func__, subdriver->name); break; } + upsdebugx(2, "%s: Trying protocol %s: claim failed", __func__, subdriver->name); subdriver = NULL; } @@ -4139,11 +4173,14 @@ static int subdriver_matcher(void) if (!subdriver) { upslogx(LOG_ERR, "Device not supported!"); + upsdebugx(2, "%s finished", __func__); return 0; } upslogx(LOG_INFO, "Using protocol: %s", subdriver->name); + upsdebugx(2, "%s finished", __func__); + return 1; } @@ -4395,6 +4432,7 @@ static bool_t qx_ups_walk(walkmode_t mode) previous_item.answer); /* Process the answer */ + errno = 0; retcode = qx_process_answer(item, strlen(item->answer)); /* ..otherwise: execute command to get answer from the UPS */ @@ -4626,11 +4664,15 @@ item_t *find_nut_info(const char *varname, const unsigned long flag, const unsig /* Process the answer we got back from the UPS * Return -1 on errors, 0 on success * Can set errno, note that EINVAL means unsupported - * parameter value here! + * parameter value here, and ETIMEDOUT can be passed + * from previous context for short reads, or set + * unilaterally for zero-length reads! */ static int qx_process_answer(item_t *item, const size_t len) { - errno = 0; + /* Initial errno inherited from caller, e.g. may be qx_command() + * in qx_process(), but may be from other memset() etc. after it + */ /* Query rejected by the UPS */ if (subdriver->rejected && !strcasecmp(item->answer, subdriver->rejected)) { @@ -4642,12 +4684,19 @@ static int qx_process_answer(item_t *item, const size_t len) /* Short reply */ if (item->answer_len && len < item->answer_len) { - upsdebugx(2, "%s: short reply (%s) %" PRIuSIZE "<%" PRIuSIZE, + upsdebug_with_errno(2, "%s: short reply (%s) %" PRIuSIZE "<%" PRIuSIZE, __func__, item->info_type, len, item->answer_len); - errno = EINVAL; + if (len == 0 || errno == ETIMEDOUT) { + errno = ETIMEDOUT; + } else { + errno = EINVAL; + } return -1; } + /* Not a systemic error by default */ + errno = 0; + /* Wrong leading character */ if (item->leading && item->answer[0] != item->leading) { upsdebugx(2, @@ -4674,6 +4723,7 @@ static int qx_process_answer(item_t *item, const size_t len) snprintf(item->value, sizeof(item->value), "%s", ""); } + /* Reset the common error level, if some method above raised it */ errno = 0; return 0; } @@ -4689,7 +4739,7 @@ int qx_process(item_t *item, const char *command) size_t cmdsz = (sizeof(char) * cmdlen); /* in bytes, to be pedantic */ int cmd_len; - if ( !(cmd = xmalloc(cmdsz)) ) { + if ( !(cmd = (char *)xmalloc(cmdsz)) ) { upslogx(LOG_ERR, "qx_process() failed to allocate buffer"); return -1; } diff --git a/drivers/nutdrv_qx_masterguard.c b/drivers/nutdrv_qx_masterguard.c index ed4811d37d..508e9d5689 100644 --- a/drivers/nutdrv_qx_masterguard.c +++ b/drivers/nutdrv_qx_masterguard.c @@ -355,7 +355,7 @@ static int masterguard_output_voltages(item_t *item, char *value, const size_t v for (w = strtok(item->value, sep); w; w = strtok(NULL, sep)) { n++; upsdebugx(4, "output voltage #%" PRIuSIZE ": %s", n, w); - if ((masterguard_e_outvolts = realloc(masterguard_e_outvolts, n * sizeof(info_rw_t))) == NULL) { + if ((masterguard_e_outvolts = (info_rw_t*)realloc(masterguard_e_outvolts, n * sizeof(info_rw_t))) == NULL) { upsdebugx(1, "output voltages: allocating #%" PRIuSIZE " failed", n); return -1; } @@ -363,7 +363,7 @@ static int masterguard_output_voltages(item_t *item, char *value, const size_t v masterguard_e_outvolts[n - 1].preprocess = NULL; } /* need to do this seperately in case the loop is run zero times */ - if ((masterguard_e_outvolts = realloc(masterguard_e_outvolts, (n + 1) * sizeof(info_rw_t))) == NULL) { + if ((masterguard_e_outvolts = (info_rw_t*)realloc(masterguard_e_outvolts, (n + 1) * sizeof(info_rw_t))) == NULL) { upsdebugx(1, "output voltages: allocating terminator after #%" PRIuSIZE " failed", n); return -1; } diff --git a/drivers/nutdrv_qx_voltronic-axpert.c b/drivers/nutdrv_qx_voltronic-axpert.c index c5da6fb5e3..9f2f754ac6 100644 --- a/drivers/nutdrv_qx_voltronic-axpert.c +++ b/drivers/nutdrv_qx_voltronic-axpert.c @@ -2419,7 +2419,7 @@ static int voltronic_sunny_energy_hour(item_t *item, char *command, const size_t return -1; } - buf = xcalloc(commandlen, sizeof(char)); + buf = (char *)xcalloc(commandlen, sizeof(char)); if (!buf) { upsdebugx(2, "%s: cannot allocate buffer", __func__); return -1; @@ -2448,7 +2448,7 @@ static int voltronic_sunny_energy_day(item_t *item, char *command, const size_t return -1; } - buf = xcalloc(commandlen, sizeof(char)); + buf = (char *)xcalloc(commandlen, sizeof(char)); if (!buf) { upsdebugx(2, "%s: cannot allocate buffer", __func__); return -1; @@ -2477,7 +2477,7 @@ static int voltronic_sunny_energy_month(item_t *item, char *command, const size_ return -1; } - buf = xcalloc(commandlen, sizeof(char)); + buf = (char *)xcalloc(commandlen, sizeof(char)); if (!buf) { upsdebugx(2, "%s: cannot allocate buffer", __func__); return -1; @@ -2506,7 +2506,7 @@ static int voltronic_sunny_energy_year(item_t *item, char *command, const size_t return -1; } - buf = xcalloc(commandlen, sizeof(char)); + buf = (char *)xcalloc(commandlen, sizeof(char)); if (!buf) { upsdebugx(2, "%s: cannot allocate buffer", __func__); return -1; diff --git a/drivers/nutdrv_qx_voltronic.c b/drivers/nutdrv_qx_voltronic.c index 1e6efa9495..408864a396 100644 --- a/drivers/nutdrv_qx_voltronic.c +++ b/drivers/nutdrv_qx_voltronic.c @@ -25,7 +25,7 @@ #include "nutdrv_qx.h" #include "nutdrv_qx_voltronic.h" -#define VOLTRONIC_VERSION "Voltronic 0.13" +#define VOLTRONIC_VERSION "Voltronic 0.14" /* Support functions */ static int voltronic_claim(void); @@ -1685,40 +1685,61 @@ static testing_t voltronic_testing[] = { /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int voltronic_claim(void) { + int query_result; /* We need at least QGS and QPI to run this subdriver */ item_t *item = find_nut_info("input.voltage", 0, 0); - /* Don't know what happened */ - if (!item) + /* Don't know what happened - should have looked up in the mapping table here! */ + if (!item) { + upsdebug_with_errno(4, "%s: did not find 'input.voltage' in mapping table", __func__); return 0; + } /* No reply/Unable to get value */ - if (qx_process(item, NULL)) - return 0; + if ((query_result = qx_process(item, NULL))) { + upsdebug_with_errno(4, "%s: failed (%d) to get 'input.voltage'", __func__, query_result); + + if (errno == ETIMEDOUT) { + upsdebugx(2, "%s: Sometimes the device is laggy, and we could have posted many queries and the buffer is full of replies to them (or it is still producing the answers); try to sleep, flush it and ask again", __func__); + usleep(5000000); /* arbitrary 5s delay for the device to maybe produce answers to earlier voltage requests */ + upsdebugx(2, "%s: Retry the query now, buffers will be flushed then", __func__); + query_result = qx_process(item, NULL); + } + + if (query_result) { + /* Not a known timeout/zero-read initially, or still a bad response */ + return 0; + } + } /* Unable to process value */ - if (ups_infoval_set(item) != 1) + if ((query_result = ups_infoval_set(item)) != 1) { + upsdebug_with_errno(4, "%s: failed (%d) to set infoval for 'input.voltage'", __func__, query_result); return 0; + } /* UPS Protocol */ item = find_nut_info("ups.firmware.aux", 0, 0); /* Don't know what happened */ if (!item) { + upsdebug_with_errno(4, "%s: did not find 'ups.firmware.aux' in mapping table", __func__); dstate_delinfo("input.voltage"); return 0; } /* No reply/Unable to get value */ - if (qx_process(item, NULL)) { + if ((query_result = qx_process(item, NULL))) { + upsdebug_with_errno(4, "%s: failed (%d) to get 'ups.firmware.aux'", __func__, query_result); dstate_delinfo("input.voltage"); return 0; } /* Unable to process value/Protocol out of range */ - if (ups_infoval_set(item) != 1) { + if ((query_result = ups_infoval_set(item)) != 1) { + upsdebug_with_errno(4, "%s: failed (%d) to set infoval for 'ups.firmware.aux'", __func__, query_result); dstate_delinfo("input.voltage"); return 0; } diff --git a/drivers/optiups.c b/drivers/optiups.c index 4a81ad1fb5..4625b8aa6b 100644 --- a/drivers/optiups.c +++ b/drivers/optiups.c @@ -101,9 +101,11 @@ enum { typedef struct ezfill_s { const char *cmd; const char *var; - const float scale; /* if 0, no conversion is done and the string - is passed to dstate as is, otherwise a float - conversion with single decimal is applied */ + + /* if scale is 0, no conversion is done and the + * string is passed to dstate as is; otherwise a + * float conversion with single decimal is applied */ + const float scale; } ezfill_t; /* These can be polled right into a string usable by NUT. @@ -132,8 +134,8 @@ static ezfill_t opti_pollv_zinto[] = { * test with a PS-1440RM at 230V the change is only applied to PowerSeries models. */ static ezfill_t opti_pollv_ps[] = { - { "OL", "ups.load", 1.0 }, - { "FF", "input.frequency", 0.1 }, + { "OL", "ups.load", 1.0 }, + { "FF", "input.frequency", 0.1 }, { "BT", "ups.temperature", 0 }, }; diff --git a/drivers/pijuice.c b/drivers/pijuice.c index bc815ec5d7..e44f58fa81 100644 --- a/drivers/pijuice.c +++ b/drivers/pijuice.c @@ -84,11 +84,14 @@ static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) union i2c_smbus_data data; int err; - if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, - I2C_SMBUS_BYTE_DATA, &data)) < 0) + if ((err = i2c_smbus_access( + file, I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data)) < 0 + ) { return err; - else + } else { return 0x0FF & data.byte; + } } # endif @@ -99,11 +102,14 @@ static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value int err; data.byte = value; - if ((err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, - I2C_SMBUS_BYTE_DATA, &data)) < 0) + if ((err = i2c_smbus_access( + file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BYTE_DATA, &data)) < 0 + ) { return err; - else + } else { return 0x0FF & data.byte; + } } # endif @@ -113,11 +119,14 @@ static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) union i2c_smbus_data data; int err; - if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, - I2C_SMBUS_WORD_DATA, &data)) < 0) + if ((err = i2c_smbus_access( + file, I2C_SMBUS_READ, command, + I2C_SMBUS_WORD_DATA, &data)) < 0 + ) { return err; - else + } else { return 0x0FFFF & data.word; + } } # endif @@ -128,11 +137,14 @@ static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 valu int err; data.word = value; - if ((err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, - I2C_SMBUS_WORD_DATA, &data)) < 0) + if ((err = i2c_smbus_access( + file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_WORD_DATA, &data)) < 0 + ) { return err; - else + } else { return 0x0FFFF & data.word; + } } # endif @@ -150,11 +162,14 @@ static inline __u8* i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 l data.block[0] = length; memcpy(data.block + 1, values, length); - if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data)) < 0) + if ((err = i2c_smbus_access( + file, I2C_SMBUS_READ, command, + I2C_SMBUS_I2C_BLOCK_DATA, &data)) < 0 + ) { return NULL; - else + } else { memcpy(values, &data.block[1], data.block[0]); + } return values; } @@ -410,9 +425,9 @@ static void get_status(void) upsdebugx(1, "Power Input 5v: UNKNOWN"); } - if ( batteryStatus == BATT_NORMAL || - batteryStatus == BATT_CHARGING_FROM_IN || - batteryStatus == BATT_CHARGING_FROM_5V ) + if ( batteryStatus == BATT_NORMAL + || batteryStatus == BATT_CHARGING_FROM_IN + || batteryStatus == BATT_CHARGING_FROM_5V ) { get_charge_level_hi_res(); @@ -432,12 +447,12 @@ static void get_status(void) status_set("RB"); } - if ( batteryStatus <= BATT_NOT_PRESENT && - powerInput <= POWER_PRESENT && - powerInput5vIo <= POWER_PRESENT ) + if ( batteryStatus <= BATT_NOT_PRESENT + && powerInput <= POWER_PRESENT + && powerInput5vIo <= POWER_PRESENT ) { - if ( powerInput == POWER_NOT_PRESENT && - ( powerInput5vIo != POWER_NOT_PRESENT )) + if ( powerInput == POWER_NOT_PRESENT + && ( powerInput5vIo != POWER_NOT_PRESENT )) { if ( usb_power != 1 || gpio_power != 0 ) { @@ -461,9 +476,9 @@ static void get_status(void) dstate_setinfo( "battery.charger.status", "%s", "resting" ); } } - else if ( powerInput5vIo == POWER_NOT_PRESENT && - ( powerInput != POWER_NOT_PRESENT && - powerInput <= POWER_PRESENT )) + else if ( powerInput5vIo == POWER_NOT_PRESENT + && powerInput != POWER_NOT_PRESENT + && powerInput <= POWER_PRESENT ) { if ( gpio_power != 1 || usb_power != 0 ) { @@ -487,8 +502,8 @@ static void get_status(void) dstate_setinfo( "battery.charger.status", "%s", "resting" ); } } - else if ( ( powerInput != POWER_NOT_PRESENT && powerInput <= POWER_PRESENT ) && - ( powerInput5vIo != POWER_NOT_PRESENT && powerInput5vIo <= POWER_PRESENT )) + else if ( ( powerInput != POWER_NOT_PRESENT && powerInput <= POWER_PRESENT ) + && ( powerInput5vIo != POWER_NOT_PRESENT && powerInput5vIo <= POWER_PRESENT )) { if ( usb_power != 1 || gpio_power != 1 ) { diff --git a/drivers/powercom-hid.c b/drivers/powercom-hid.c index 6047bb8fcb..eecbec2b4b 100644 --- a/drivers/powercom-hid.c +++ b/drivers/powercom-hid.c @@ -28,7 +28,7 @@ #include /* isdigit() */ -#define POWERCOM_HID_VERSION "PowerCOM HID 0.73" +#define POWERCOM_HID_VERSION "PowerCOM HID 0.74" /* FIXME: experimental flag to be put in upsdrv_info */ /* PowerCOM */ @@ -97,11 +97,23 @@ static const char *powercom_startup_fun(double value) static double powercom_startup_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.start"); + const char *cfg = getval("ondelay"); uint32_t val, command; int iv; - /* Start with seconds "as is" - convert into whole minutes */ - iv = atoi(value ? value : s) / 60; /* minutes */ + /* Priority: 1) command value, 2) config ondelay, 3) UPS current, 4) default + * Note we start with seconds "as is" - convert into whole minutes for the device protocol + */ + if (value && *value) { + iv = atoi(value) / 60; + } else if (cfg && *cfg) { + iv = atoi(cfg) / 60; + } else if (s && *s) { + iv = atoi(s) / 60; + } else { + iv = 2; /* Default: 2 minutes (120 seconds) */ + } + #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif @@ -165,10 +177,23 @@ static const char *powercom_shutdown_fun(double value) static double powercom_shutdown_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.shutdown"); + const char *cfg = getval("offdelay"); uint16_t val, command; int iv; - iv = atoi(value ? value : s); /* seconds */ + /* Priority: 1) command value, 2) config offdelay, 3) UPS current, 4) default + * Note we start with seconds "as is" - convert into magic numbers for the device protocol below + */ + if (value && *value) { + iv = atoi(value); + } else if (cfg && *cfg) { + iv = atoi(cfg); + } else if (s && *s) { + iv = atoi(s); + } else { + iv = 60; /* Default: 60 seconds */ + } + if (iv < 0 || (intmax_t)iv > (intmax_t)UINT16_MAX) { upsdebugx(0, "%s: value = %d is not in uint16_t range", __func__, iv); return 0; @@ -219,11 +244,24 @@ static info_lkp_t powercom_shutdown_info[] = { static double powercom_stayoff_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.shutdown"); + const char *cfg = getval("offdelay"); uint16_t val, command; int iv; /* FIXME: Anything for powercom_sdcmd_discrete_delay? */ - iv = atoi(value ? value : s); + /* Priority: 1) command value, 2) config offdelay, 3) UPS current, 4) default + * Note we start with seconds "as is" - convert into magic numbers for the device protocol below + */ + if (value && *value) { + iv = atoi(value); + } else if (cfg && *cfg) { + iv = atoi(cfg); + } else if (s && *s) { + iv = atoi(s); + } else { + iv = 60; /* Default: 60 seconds */ + } + if (iv < 0 || (intmax_t)iv > (intmax_t)UINT16_MAX) { upsdebugx(0, "%s: value = %d is not in uint16_t range", __func__, iv); return 0; diff --git a/drivers/powercom.c b/drivers/powercom.c index 9426f2c788..11743dbf47 100644 --- a/drivers/powercom.c +++ b/drivers/powercom.c @@ -378,12 +378,12 @@ static int validate_raw_data (void) num_of_tests = sizeof types[0].validation / sizeof types[0].validation[0]; - for (i = 0; - i < num_of_tests && - raw_data[ - types[type].validation[i].index_of_byte] == - types[type].validation[i].required_value; - i++) ; + for ( + i = 0; + i < num_of_tests + && raw_data[types[type].validation[i].index_of_byte] + == types[type].validation[i].required_value; + i++) ; return (i < num_of_tests) ? 1 : 0; } @@ -595,13 +595,13 @@ static float output_voltage(void) /* FIXME: may miss a last processing with ErrorVal = 5 | 10 */ } } else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { - tmp=raw_data[OUTPUT_VOLTAGE]*2.0; + tmp = raw_data[OUTPUT_VOLTAGE]*2.0; } else { - tmp= linevoltage >= 220 ? - types[type].voltage[0] * raw_data[OUTPUT_VOLTAGE] + - types[type].voltage[1] : - types[type].voltage[2] * raw_data[OUTPUT_VOLTAGE] + - types[type].voltage[3]; + tmp = linevoltage >= 220 + ? types[type].voltage[0] * raw_data[OUTPUT_VOLTAGE] + + types[type].voltage[1] + : types[type].voltage[2] * raw_data[OUTPUT_VOLTAGE] + + types[type].voltage[3]; } if (tmp<0) tmp=0.0; return tmp; @@ -781,37 +781,37 @@ void upsdrv_updateinfo(void) /* input.frequency */ upsdebugx(3, "input.frequency (raw data): [raw: %u]", - raw_data[INPUT_FREQUENCY]); + raw_data[INPUT_FREQUENCY]); dstate_setinfo("input.frequency", "%02.2f", input_freq()); upsdebugx(2, "input.frequency: %s", dstate_getinfo("input.frequency")); /* output.frequency */ upsdebugx(3, "output.frequency (raw data): [raw: %u]", - raw_data[OUTPUT_FREQUENCY]); + raw_data[OUTPUT_FREQUENCY]); dstate_setinfo("output.frequency", "%02.2f", output_freq()); upsdebugx(2, "output.frequency: %s", dstate_getinfo("output.frequency")); /* ups.load */ upsdebugx(3, "ups.load (raw data): [raw: %u]", - raw_data[UPS_LOAD]); + raw_data[UPS_LOAD]); dstate_setinfo("ups.load", "%03.1f", load_level()); upsdebugx(2, "ups.load: %s", dstate_getinfo("ups.load")); /* battery.charge */ upsdebugx(3, "battery.charge (raw data): [raw: %u]", - raw_data[BATTERY_CHARGE]); + raw_data[BATTERY_CHARGE]); dstate_setinfo("battery.charge", "%03.1f", batt_level()); upsdebugx(2, "battery.charge: %s", dstate_getinfo("battery.charge")); /* input.voltage */ upsdebugx(3, "input.voltage (raw data): [raw: %u]", - raw_data[INPUT_VOLTAGE]); + raw_data[INPUT_VOLTAGE]); dstate_setinfo("input.voltage", "%03.1f",input_voltage()); upsdebugx(2, "input.voltage: %s", dstate_getinfo("input.voltage")); /* output.voltage */ upsdebugx(3, "output.voltage (raw data): [raw: %u]", - raw_data[OUTPUT_VOLTAGE]); + raw_data[OUTPUT_VOLTAGE]); dstate_setinfo("output.voltage", "%03.1f",output_voltage()); upsdebugx(2, "output.voltage: %s", dstate_getinfo("output.voltage")); @@ -882,9 +882,10 @@ void upsdrv_initups(void) /* get and check type */ if (testvar("type")) { - for (i = 0; - i < NUM_OF_SUBTYPES && strcmp(types[i].name, getval("type")); - i++) ; + for ( + i = 0; + i < NUM_OF_SUBTYPES && strcmp(types[i].name, getval("type")); + i++) ; if (i >= NUM_OF_SUBTYPES) { printf("Given UPS type '%s' isn't valid!\n", getval("type")); exit (1); @@ -906,95 +907,100 @@ void upsdrv_initups(void) tmp = atoi(getval("numOfBytesFromUPS")); if (! (tmp > 0 && tmp <= MAX_NUM_OF_BYTES_FROM_UPS) ) { printf("Given numOfBytesFromUPS '%d' is out of range (1 to %d)\n", - tmp, MAX_NUM_OF_BYTES_FROM_UPS); + tmp, MAX_NUM_OF_BYTES_FROM_UPS); exit (1); } types[type].num_of_bytes_from_ups = (unsigned char) tmp; } if (testvar("methodOfFlowControl")) { - for (i = 0; - i < NUM_OF_SUBTYPES && - strcmp(types[i].flowControl.name, - getval("methodOfFlowControl")); - i++) ; + for ( + i = 0; + i < NUM_OF_SUBTYPES + && strcmp(types[i].flowControl.name, getval("methodOfFlowControl")); + i++) ; if (i >= NUM_OF_SUBTYPES) { printf("Given methodOfFlowControl '%s' isn't valid!\n", - getval("methodOfFlowControl")); + getval("methodOfFlowControl")); exit (1); } types[type].flowControl = types[i].flowControl; } - if (testvar("validationSequence") && - sscanf(getval("validationSequence"), - "{{%u,%x},{%u,%x},{%u,%x}}", - &types[type].validation[0].index_of_byte, - &types[type].validation[0].required_value, - &types[type].validation[1].index_of_byte, - &types[type].validation[1].required_value, - &types[type].validation[2].index_of_byte, - &types[type].validation[2].required_value - ) < 6 - ) { + if (testvar("validationSequence") + && sscanf(getval("validationSequence"), + "{{%u,%x},{%u,%x},{%u,%x}}", + &types[type].validation[0].index_of_byte, + &types[type].validation[0].required_value, + &types[type].validation[1].index_of_byte, + &types[type].validation[1].required_value, + &types[type].validation[2].index_of_byte, + &types[type].validation[2].required_value + ) < 6 + ) { printf("Given validationSequence '%s' isn't valid!\n", - getval("validationSequence")); + getval("validationSequence")); exit (1); } /* NOTE: %hhu is not supported before C99; that would need reading * arguments into an uint as %u, checking range and casting */ - if (testvar("shutdownArguments") && - sscanf(getval("shutdownArguments"), "{{%hhu,%hhu},%c}", - &types[type].shutdown_arguments.delay[0], - &types[type].shutdown_arguments.delay[1], - &types[type].shutdown_arguments.minutesShouldBeUsed - ) < 3 - ) { - printf("Given shutdownArguments '%s' isn't valid!\n", - getval("shutdownArguments")); + if (testvar("shutdownArguments") + && sscanf(getval("shutdownArguments"), + "{{%hhu,%hhu},%c}", + &types[type].shutdown_arguments.delay[0], + &types[type].shutdown_arguments.delay[1], + &types[type].shutdown_arguments.minutesShouldBeUsed + ) < 3 + ) { + printf("Given shutdownArguments '%s' isn't valid!\n", + getval("shutdownArguments")); exit (1); } - if (testvar("frequency") && - sscanf(getval("frequency"), "{%f,%f}", - &types[type].freq[0], &types[type].freq[1] - ) < 2 - ) { + if (testvar("frequency") + && sscanf(getval("frequency"), + "{%f,%f}", + &types[type].freq[0], &types[type].freq[1] + ) < 2 + ) { printf("Given frequency '%s' isn't valid!\n", - getval("frequency")); + getval("frequency")); exit (1); } - if (testvar("loadPercentage") && - sscanf(getval("loadPercentage"), "{%f,%f,%f,%f}", - &types[type].loadpct[0], &types[type].loadpct[1], - &types[type].loadpct[2], &types[type].loadpct[3] - ) < 4 - ) { + if (testvar("loadPercentage") + && sscanf(getval("loadPercentage"), + "{%f,%f,%f,%f}", + &types[type].loadpct[0], &types[type].loadpct[1], + &types[type].loadpct[2], &types[type].loadpct[3] + ) < 4 + ) { printf("Given loadPercentage '%s' isn't valid!\n", - getval("loadPercentage")); + getval("loadPercentage")); exit (1); } - if (testvar("batteryPercentage") && - sscanf(getval("batteryPercentage"), "{%f,%f,%f,%f,%f}", - &types[type].battpct[0], &types[type].battpct[1], - &types[type].battpct[2], &types[type].battpct[3], - &types[type].battpct[4] - ) < 5 - ) { + if (testvar("batteryPercentage") + && sscanf(getval("batteryPercentage"), + "{%f,%f,%f,%f,%f}", + &types[type].battpct[0], &types[type].battpct[1], + &types[type].battpct[2], &types[type].battpct[3], + &types[type].battpct[4] + ) < 5 + ) { printf("Given batteryPercentage '%s' isn't valid!\n", - getval("batteryPercentage")); + getval("batteryPercentage")); exit (1); } - if (testvar("voltage") && - sscanf(getval("voltage"), "{%f,%f,%f,%f}", - &types[type].voltage[0], &types[type].voltage[1], - &types[type].voltage[2], &types[type].voltage[3] - ) < 4 - ) { + if (testvar("voltage") + && sscanf(getval("voltage"), + "{%f,%f,%f,%f}", + &types[type].voltage[0], &types[type].voltage[1], + &types[type].voltage[2], &types[type].voltage[3] + ) < 4 + ) { printf("Given voltage '%s' isn't valid!\n", getval("voltage")); exit (1); } @@ -1143,34 +1149,34 @@ void upsdrv_initinfo(void) upsdebugx(1, " line voltage : '%u'", linevoltage); upsdebugx(1, " type : '%s'", types[type].name); upsdebugx(1, " number of bytes from UPS: '%u'", - types[type].num_of_bytes_from_ups); + types[type].num_of_bytes_from_ups); upsdebugx(1, " method of flow control : '%s'", - types[type].flowControl.name); + types[type].flowControl.name); upsdebugx(1, " validation sequence: '{{%u,%#x},{%u,%#x},{%u,%#x}}'", - types[type].validation[0].index_of_byte, - types[type].validation[0].required_value, - types[type].validation[1].index_of_byte, - types[type].validation[1].required_value, - types[type].validation[2].index_of_byte, - types[type].validation[2].required_value); + types[type].validation[0].index_of_byte, + types[type].validation[0].required_value, + types[type].validation[1].index_of_byte, + types[type].validation[1].required_value, + types[type].validation[2].index_of_byte, + types[type].validation[2].required_value); upsdebugx(1, " shutdown arguments: '{{%u,%u},%c}'", - types[type].shutdown_arguments.delay[0], - types[type].shutdown_arguments.delay[1], - types[type].shutdown_arguments.minutesShouldBeUsed); + types[type].shutdown_arguments.delay[0], + types[type].shutdown_arguments.delay[1], + types[type].shutdown_arguments.minutesShouldBeUsed); if ( strcmp(types[type].name, "KIN") && strcmp(types[type].name, "BNT") && strcmp(types[type].name, "IMP")) { upsdebugx(1, " frequency calculation coefficients: '{%f,%f}'", - types[type].freq[0], types[type].freq[1]); + types[type].freq[0], types[type].freq[1]); upsdebugx(1, " load percentage calculation coefficients: " - "'{%f,%f,%f,%f}'", - types[type].loadpct[0], types[type].loadpct[1], - types[type].loadpct[2], types[type].loadpct[3]); + "'{%f,%f,%f,%f}'", + types[type].loadpct[0], types[type].loadpct[1], + types[type].loadpct[2], types[type].loadpct[3]); upsdebugx(1, " battery percentage calculation coefficients: " - "'{%f,%f,%f,%f,%f}'", - types[type].battpct[0], types[type].battpct[1], - types[type].battpct[2], types[type].battpct[3], - types[type].battpct[4]); + "'{%f,%f,%f,%f,%f}'", + types[type].battpct[0], types[type].battpct[1], + types[type].battpct[2], types[type].battpct[3], + types[type].battpct[4]); upsdebugx(1, " voltage calculation coefficients: '{%f,%f}'", - types[type].voltage[2], types[type].voltage[3]); + types[type].voltage[2], types[type].voltage[3]); } /* write constant data for this model */ diff --git a/drivers/powerp-bin.c b/drivers/powerp-bin.c index 67d2d94be9..f7105c9c93 100644 --- a/drivers/powerp-bin.c +++ b/drivers/powerp-bin.c @@ -274,9 +274,9 @@ static int powpan_instcmd(const char *cmdname, const char *extra) upslog_INSTCMD_POWERSTATE_CHECKED(cmdname, extra); ret = powpan_command(cmdtab[i].command, cmdtab[i].len); assert(cmdtab[i].len < SSIZE_MAX); - if (ret >= 0 && - (ret == (ssize_t)(cmdtab[i].len - 1)) && - (!memcmp(powpan_answer, cmdtab[i].command, cmdtab[i].len - 1)) + if (ret >= 0 + && (ret == (ssize_t)(cmdtab[i].len - 1)) + && (!memcmp(powpan_answer, cmdtab[i].command, cmdtab[i].len - 1)) ) { return STAT_INSTCMD_HANDLED; } diff --git a/drivers/rhino.c b/drivers/rhino.c index 1a8bc55360..10c7165e50 100644 --- a/drivers/rhino.c +++ b/drivers/rhino.c @@ -481,7 +481,7 @@ send_command( unsigned char cmd ) ssize_t ret = -1; unsigned char ch, *psend = NULL; - if ( !(psend = xmalloc(sizeof(char) * sizes)) ) { + if ( !(psend = (unsigned char *)xmalloc(sizeof(char) * sizes)) ) { upslogx(LOG_ERR, "send_command() failed to allocate buffer"); return -1; } diff --git a/drivers/richcomm_usb.c b/drivers/richcomm_usb.c index 766e56d8ea..c20e1b6ea2 100644 --- a/drivers/richcomm_usb.c +++ b/drivers/richcomm_usb.c @@ -389,10 +389,10 @@ static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDev } /* collect the identifying information of this - device. Note that this is safe, because - there's no need to claim an interface for - this (and therefore we do not yet need to - detach any kernel drivers). */ + * device. Note that this is safe, because + * there's no need to claim an interface for + * this (and therefore we do not yet need to + * detach any kernel drivers). */ free(device->Vendor); free(device->Product); @@ -703,13 +703,13 @@ void upsdrv_updateinfo(void) status_init(); if (online) { - status_set("OL"); + status_set("OL"); } else { - status_set("OB"); + status_set("OB"); } if (!battery_normal) { - status_set("LB"); + status_set("LB"); } status_commit(); diff --git a/drivers/riello_ser.c b/drivers/riello_ser.c index f553362071..d2844a20bf 100644 --- a/drivers/riello_ser.c +++ b/drivers/riello_ser.c @@ -1333,7 +1333,7 @@ static int setvar(const char *varname, const char *val) { upsdebug_SET_STARTING(varname, val); - if (!strcasecmp(varname, "ups.test.interval")) { + if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } diff --git a/drivers/riello_usb.c b/drivers/riello_usb.c index 4e47b6ae4d..c04d411ffa 100644 --- a/drivers/riello_usb.c +++ b/drivers/riello_usb.c @@ -1244,13 +1244,13 @@ void upsdrv_shutdown(void) int retry; /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ diff --git a/drivers/serial.c b/drivers/serial.c index 0317493e7b..926609ec02 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -448,7 +448,7 @@ ssize_t ser_send_buf_pace(TYPE_FD_SER fd, useconds_t d_usec, const void *buf, { ssize_t ret = 0; ssize_t sent; - const char *data = buf; + const char *data = (const char *)buf; assert(buflen < SSIZE_MAX); for (sent = 0; sent < (ssize_t)buflen; sent += ret) { @@ -486,7 +486,7 @@ ssize_t ser_get_buf_len(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, { ssize_t ret; ssize_t recv; - char *data = buf; + char *data = (char *)buf; assert(buflen < SSIZE_MAX); memset(buf, '\0', buflen); @@ -513,7 +513,7 @@ ssize_t ser_get_line_alert(TYPE_FD_SER fd, void *buf, size_t buflen, char endcha { ssize_t i, ret; char tmp[64]; - char *data = buf; + char *data = (char *)buf; ssize_t count = 0, maxcount; assert(buflen < SSIZE_MAX && buflen > 0); diff --git a/drivers/skel.c b/drivers/skel.c index 4a5cbc6104..c98d462304 100644 --- a/drivers/skel.c +++ b/drivers/skel.c @@ -108,7 +108,7 @@ void upsdrv_shutdown(void) /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if - it doesn't respond at first if possible */ + * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ @@ -117,7 +117,7 @@ void upsdrv_shutdown(void) set_exit_flag(EF_EXIT_FAILURE); /* you may have to check the line status since the commands - for toggling power are frequently different for OL vs. OB */ + * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ @@ -153,7 +153,7 @@ static int setvar(const char *varname, const char *val) { upsdebug_SET_STARTING(varname, val); - if (!strcasecmp(varname, "ups.test.interval")) { + if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } diff --git a/drivers/snmp-ups-helpers.c b/drivers/snmp-ups-helpers.c index 6fbfd9ef7a..c3d313af8a 100644 --- a/drivers/snmp-ups-helpers.c +++ b/drivers/snmp-ups-helpers.c @@ -69,7 +69,7 @@ const char *su_usdate_to_isodate_info_fun(void *raw_date) /* Try to convert from US date string to time */ /* Note strptime returns NULL upon failure, and a ptr to the last - null char of the string upon success. Just try blindly the conversion! */ + * null char of the string upon success. Just try blindly the conversion! */ strptime(usdate, "%m/%d/%Y", &tm); if (strftime(su_scratch_buf, 254, "%F", &tm) != 0) { upsdebugx(3, "%s: successfully reformated: %s", __func__, su_scratch_buf); diff --git a/drivers/snmp-ups.c b/drivers/snmp-ups.c index a97ffb618e..4cf3fb42b9 100644 --- a/drivers/snmp-ups.c +++ b/drivers/snmp-ups.c @@ -80,6 +80,7 @@ #include "emerson-avocent-pdu-mib.h" #include "hpe-pdu-mib.h" #include "hpe-pdu3-cis-mib.h" +#include "vertiv-mib.h" #endif /* WITH_DMFMIB */ /* Address API change */ @@ -159,6 +160,7 @@ static mib2nut_info_t *mib2nut[] = { &netvision, /* This struct comes from : netvision-mib.c */ &raritan, /* This struct comes from : raritan-pdu-mib.c */ &raritan_px2, /* This struct comes from : raritan-px2-mib.c */ + &vertiv, /* This struct comes from : vertiv-mib.c */ &xppc, /* This struct comes from : xppc-mib.c */ /* * Prepend vendor specific MIB mappings before IETF, so that @@ -213,7 +215,7 @@ static const char *mibvers; #else # define DRIVER_NAME "Generic SNMP UPS driver" #endif /* WITH_DMFMIB */ -#define DRIVER_VERSION "1.38" +#define DRIVER_VERSION "1.39" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -296,7 +298,7 @@ static void analyze_mapping_usage(void) { return; } - unused_names = xcalloc(unused_bufsize, sizeof(char)); + unused_names = (char*)xcalloc(unused_bufsize, sizeof(char)); for (su_info_p = &snmp_info[0]; (su_info_p != NULL && su_info_p->info_type != NULL) ; su_info_p++) { @@ -349,7 +351,7 @@ static void analyze_mapping_usage(void) { if (*pBufSize < SIZE_MAX - LARGEBUF) { *pBufSize = *pBufSize + LARGEBUF; upsdebugx(1, "%s: buffer overflowed, trying to re-allocate as %" PRIuSIZE, __func__, *pBufSize); - *pNames = realloc(*pNames, *pBufSize); + *pNames = (char*)realloc(*pNames, *pBufSize); if (!*pNames) { upsdebugx(1, "%s: buffer overflowed, will not report unused descriptor names", __func__); @@ -903,7 +905,8 @@ void upsdrv_initups(void) if (!strcmp(mibs, "--list")) { int i; - printf("The 'mibs' argument is '%s', so just listing the mappings this driver knows,\n" + printf( + "The 'mibs' argument is '%s', so just listing the mappings this driver knows,\n" "and for 'mibs=auto' these mappings will be tried in the following order until\n" "the first one matches your device\n\n", mibs); printf("%7s\t%-23s\t%-7s\t%-31s\t%-s\n", @@ -1499,9 +1502,10 @@ static struct snmp_pdu **nut_snmp_walk(const char *OID, int max_iteration) * SNMPv1). This allows to proceed interpreting large * responses when one entry in the middle is rejectable. */ - if (response->variables->type == SNMP_NOSUCHOBJECT || - response->variables->type == SNMP_NOSUCHINSTANCE || - response->variables->type == SNMP_ENDOFMIBVIEW) { + if (response->variables->type == SNMP_NOSUCHOBJECT + || response->variables->type == SNMP_NOSUCHINSTANCE + || response->variables->type == SNMP_ENDOFMIBVIEW + ) { upslogx(LOG_WARNING, "[%s] Warning: type error exception (OID = %s)", upsname?upsname:device_name, OID); snmp_free_pdu(response); @@ -1515,7 +1519,7 @@ static struct snmp_pdu **nut_snmp_walk(const char *OID, int max_iteration) nb_iteration++; /* +1 is for the terminating NULL */ - new_ret_array = realloc( + new_ret_array = (struct snmp_pdu**)realloc( ret_array, sizeof(struct snmp_pdu*) * ((size_t)nb_iteration+1) ); @@ -1736,7 +1740,7 @@ bool_t nut_snmp_get_int(const char *OID, long *pval) switch (pdu->variables->type) { case ASN_OCTET_STR: case ASN_OPAQUE: - buf = xmalloc(pdu->variables->val_len + 1); + buf = (char*)xmalloc(pdu->variables->val_len + 1); memcpy(buf, pdu->variables->val.string, pdu->variables->val_len); buf[pdu->variables->val_len] = '\0'; value = strtol(buf, NULL, 0); @@ -2548,9 +2552,13 @@ const char *su_find_infoval(info_lkp_t *oid2info, void *raw_value) #endif /* WITH_SNMP_LKP_FUN */ /* Otherwise, use the simple values mapping */ - for (info_lkp = oid2info; (info_lkp != NULL) && - (info_lkp->info_value != NULL) && (strcmp(info_lkp->info_value, "NULL")); info_lkp++) { - + for ( + info_lkp = oid2info; + (info_lkp != NULL) + && (info_lkp->info_value != NULL) + && (strcmp(info_lkp->info_value, "NULL")); + info_lkp++ + ) { if (info_lkp->oid_value == value) { upsdebugx(1, "%s: found %s (value: %ld)", __func__, info_lkp->info_value, value); @@ -3657,7 +3665,8 @@ bool_t snmp_ups_walk(int mode) /* skip instcmd, not linked to outlets */ if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && !(su_info_p->flags & SU_OUTLET) - && !(su_info_p->flags & SU_OUTLET_GROUP)) { + && !(su_info_p->flags & SU_OUTLET_GROUP) + ) { upsdebugx(1, "SU_CMD_MASK => %s", su_info_p->OID); continue; } @@ -3681,8 +3690,7 @@ bool_t snmp_ups_walk(int mode) /* Set default value if we cannot fetch it * and set static flag on this element. * Not applicable to outlets (need SU_FLAG_STATIC tagging) */ - if ( - (su_info_p->flags & SU_FLAG_ABSENT) + if ( (su_info_p->flags & SU_FLAG_ABSENT) && !(su_info_p->flags & SU_OUTLET) && !(su_info_p->flags & SU_OUTLET_GROUP) && !(su_info_p->flags & SU_AMBIENT_TEMPLATE)) diff --git a/drivers/snmp-ups.h b/drivers/snmp-ups.h index ae179e87c9..c954444fda 100644 --- a/drivers/snmp-ups.h +++ b/drivers/snmp-ups.h @@ -347,9 +347,10 @@ typedef struct { #define SU_FLAG_NAINVALID (1UL << 7) /* Invalid if "N/A" value */ #define SU_CMD_OFFSET (1UL << 8) /* Add +1 to the OID index */ -#define SU_FLAG_SEMI_STATIC (1UL << 9) /* Refresh this entry once in several walks - * (for R/W values user can set on device, - * like descriptions or contacts) */ +#define SU_FLAG_SEMI_STATIC (1UL << 9) + /* Refresh this entry once in several walks + * (for R/W values user can set on device, + * like descriptions or contacts) */ /* Notes on outlet templates usage: * - outlet.count MUST exist and MUST be declared before any outlet template diff --git a/drivers/socomec_jbus.c b/drivers/socomec_jbus.c index d4b14ec2c8..6affbdbbdd 100644 --- a/drivers/socomec_jbus.c +++ b/drivers/socomec_jbus.c @@ -106,13 +106,13 @@ void upsdrv_initinfo(void) } if (tab_reg[3] && tab_reg[4] && tab_reg[5] && tab_reg[6] && tab_reg[7]) { - dstate_setinfo("ups.serial", "%c%c%c%c%c%c%c%c%c%c", - (tab_reg[3]&0xFF), (tab_reg[3]>>8), - (tab_reg[4]&0xFF), (tab_reg[4]>>8), - (tab_reg[5]&0xFF), (tab_reg[5]>>8), - (tab_reg[6]&0xFF), (tab_reg[6]>>8), - (tab_reg[7]&0xFF), (tab_reg[7]>>8) - ); + dstate_setinfo("ups.serial", "%c%c%c%c%c%c%c%c%c%c", + (tab_reg[3]&0xFF), (tab_reg[3]>>8), + (tab_reg[4]&0xFF), (tab_reg[4]>>8), + (tab_reg[5]&0xFF), (tab_reg[5]>>8), + (tab_reg[6]&0xFF), (tab_reg[6]>>8), + (tab_reg[7]&0xFF), (tab_reg[7]>>8) + ); } /* upsh.instcmd = instcmd; */ diff --git a/drivers/solis.c b/drivers/solis.c index bc3472a52b..d11a7fed05 100644 --- a/drivers/solis.c +++ b/drivers/solis.c @@ -194,10 +194,10 @@ static void send_shutdown( void ) { int i; for (i = 0; i < 10; i++) - ser_send_char(upsfd, CMD_SHUT ); + ser_send_char(upsfd, CMD_SHUT); - upslogx(LOG_NOTICE, "Ups shutdown command sent"); - printf("Ups shutdown command sent\n"); + upslogx(LOG_NOTICE, "UPS shutdown command sent"); + printf("UPS shutdown command sent\n"); } /* save config ups */ @@ -447,7 +447,7 @@ static void scan_received_pack(void) { /* Specific for STAY1200_USB */ if (SolisModel == 16) { - InFreq = ((float)(0.37 * (257 - (aux >> 8)))); + InFreq = ((float)(0.37 * (257 - (aux >> 8)))); } else InFreq = 0; diff --git a/drivers/tripplite-hid.c b/drivers/tripplite-hid.c index ed93b3dd4d..ee5f41f8b2 100644 --- a/drivers/tripplite-hid.c +++ b/drivers/tripplite-hid.c @@ -248,8 +248,8 @@ static info_lkp_t tripplite_ioamp[] = { /* TRIPPLITE usage table */ static usage_lkp_t tripplite_usage_lkp[] = { /* currently unknown: - 00ff0001, ffff007d, ffff00c0, ffff00c1, ffff00c2, - ffff00c3, ffff00c4, ffff00c5, ffff00d2, ffff0091, ffff00c7 */ + * 00ff0001, ffff007d, ffff00c0, ffff00c1, ffff00c2, + * ffff00c3, ffff00c4, ffff00c5, ffff00d2, ffff0091, ffff00c7 */ { "TLCustom", 0xffff0010 }, { "TLDelayBeforeStartup", 0xffff0056 }, /* in minutes */ @@ -278,7 +278,7 @@ static usage_lkp_t tripplite_usage_lkp[] = { { "TLOutletsStatusMask", 0xffff0096 }, /* it looks like Tripp Lite confused pages 0x84 and 0x85 for the - following 4 items, on some OMNI1000LCD devices. */ + * following 4 items, on some OMNI1000LCD devices. */ { "TLCharging", 0x00840044 }, /* conflicts with HID spec! */ /* conflicts with HID spec (and HP implementation) for TrippLite! * Refer to tripplite_discharging_info */ @@ -529,8 +529,8 @@ static int tripplite_claim(HIDDevice_t *hd) { if (hd->ProductID == 0x0001) { /* e.g. SMART550USB, SMART3000RM2U */ upsdebugx(0, "This Tripp Lite device (%04x/%04x) is not supported by usbhid-ups.\n" - "Please use the tripplite_usb driver instead.\n", - hd->VendorID, hd->ProductID); + "Please use the tripplite_usb driver instead.\n", + hd->VendorID, hd->ProductID); return 0; } diff --git a/drivers/tripplite_usb.c b/drivers/tripplite_usb.c index 1e5661be27..8802813c6e 100644 --- a/drivers/tripplite_usb.c +++ b/drivers/tripplite_usb.c @@ -309,13 +309,16 @@ static usb_communication_subdriver_t *comm_driver = &usb_subdriver; /* Interval notation for Q% = 10% <= [minV, maxV] <= 100% */ static double V_interval[2] = {MIN_VOLT, MAX_VOLT}; -static long battery_voltage_nominal = 12, - input_voltage_nominal = 120, - input_voltage_scaled = 120, - /* input_voltage_maximum = -1, - input_voltage_minimum = -1, */ - switchable_load_banks = 0, - unit_id = DEFAULT_UPSID; /*!< range: 1-65535, most likely */ +static long + battery_voltage_nominal = 12, + input_voltage_nominal = 120, + input_voltage_scaled = 120, + /* + input_voltage_maximum = -1, + input_voltage_minimum = -1, + */ + switchable_load_banks = 0, + unit_id = DEFAULT_UPSID; /*!< range: 1-65535, most likely */ /*! Time in seconds to delay before shutting down. */ static unsigned int offdelay = DEFAULT_OFFDELAY; @@ -556,74 +559,86 @@ static void decode_v(const unsigned char *value) battery_voltage_nominal = bv * 6; } - ivn = value[1]; + ivn = value[1]; lb = value[4]; if( is_smart_protocol() && (tl_model != TRIPP_LITE_SMART_3017) ) { switch(ivn) { case 0: - case '0': input_voltage_nominal = - input_voltage_scaled = 100; - break; + case '0': + input_voltage_nominal = + input_voltage_scaled = 100; + break; case 1: - case '1': input_voltage_nominal = - input_voltage_scaled = 110; - break; + case '1': + input_voltage_nominal = + input_voltage_scaled = 110; + break; case 2: /* protocol 3005 */ - case '2': input_voltage_nominal = - input_voltage_scaled = 120; - break; + case '2': + input_voltage_nominal = + input_voltage_scaled = 120; + break; case 3: - case '3': input_voltage_nominal = - input_voltage_scaled = 127; - break; + case '3': + input_voltage_nominal = + input_voltage_scaled = 127; + break; case 4: - case '4': input_voltage_nominal = - input_voltage_scaled = 208; - break; + case '4': + input_voltage_nominal = + input_voltage_scaled = 208; + break; case 5: - case '5': input_voltage_nominal = - input_voltage_scaled = 220; - break; + case '5': + input_voltage_nominal = + input_voltage_scaled = 220; + break; case 6: - case '6': input_voltage_nominal = - input_voltage_scaled = 230; - break; + case '6': + input_voltage_nominal = + input_voltage_scaled = 230; + break; case 7: - case '7': input_voltage_nominal = - input_voltage_scaled = 240; - break; + case '7': + input_voltage_nominal = + input_voltage_scaled = 240; + break; default: - upslogx(LOG_WARNING, "Unknown input voltage range: 0x%02x", (unsigned int)ivn); - break; + upslogx(LOG_WARNING, "Unknown input voltage range: 0x%02x", (unsigned int)ivn); + break; } } else { /* Lots of odd cases here; maybe some of the SMART protocols got mixed in, too: */ switch(ivn) { - case '0': input_voltage_nominal = - input_voltage_scaled = 100; - break; + case '0': + input_voltage_nominal = + input_voltage_scaled = 100; + break; - case '1': input_voltage_nominal = - input_voltage_scaled = 120; - break; + case '1': + input_voltage_nominal = + input_voltage_scaled = 120; + break; /* UK SMX1200XLHG protocol 3017 confirmed: */ - case '2': input_voltage_nominal = - input_voltage_scaled = 230; - break; + case '2': + input_voltage_nominal = + input_voltage_scaled = 230; + break; - case '3': input_voltage_nominal = 208; - input_voltage_scaled = 230; - break; + case '3': + input_voltage_nominal = 208; + input_voltage_scaled = 230; + break; case 6: input_voltage_nominal = input_voltage_scaled = 230; @@ -662,7 +677,7 @@ void upsdrv_initinfo(void); */ static void usb_comm_fail(int res, const char *msg) { - static int try = 0; + static int try_num = 0; switch(res) { case LIBUSB_ERROR_BUSY: @@ -679,18 +694,18 @@ static void usb_comm_fail(int res, const char *msg) "%s: Device detached? (error %d: %s)", msg, res, nut_usb_strerror(res)); - upslogx(LOG_NOTICE, "Reconnect attempt #%d", ++try); + upslogx(LOG_NOTICE, "Reconnect attempt #%d", ++try_num); hd = NULL; reconnect_ups(); if(hd) { upslogx(LOG_NOTICE, "Successfully reconnected"); - try = 0; + try_num = 0; dstate_setinfo("driver.state", "reconnect.updateinfo"); upsdrv_initinfo(); dstate_setinfo("driver.state", "quiet"); } else { - if(try > MAX_RECONNECT_TRIES) { + if(try_num > MAX_RECONNECT_TRIES) { fatalx(EXIT_FAILURE, "Too many unsuccessful reconnection attempts"); } } @@ -1137,7 +1152,7 @@ void upsdrv_initinfo(void) s_msg[] = "S", u_msg[] = "U", v_msg[] = "V", w_msg[] = "W\0"; char *model, *model_end; unsigned char proto_value[9], f_value[9], p_value[9], s_value[9], - u_value[9], v_value[9], w_value[9]; + u_value[9], v_value[9], w_value[9]; long va; ssize_t ret; unsigned int proto_number = 0; @@ -1148,8 +1163,9 @@ void upsdrv_initinfo(void) fatalx(EXIT_FAILURE, "Error reading protocol"); } - proto_number = ((unsigned)(proto_value[1]) << 8) - | (unsigned)(proto_value[2]); + proto_number = + ( (unsigned)(proto_value[1]) << 8 ) + | (unsigned)(proto_value[2]); tl_model = decode_protocol(proto_number); if(tl_model == TRIPP_LITE_UNKNOWN) @@ -1600,8 +1616,10 @@ void upsdrv_updateinfo(void) /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - if( tl_model == TRIPP_LITE_OMNIVS || tl_model == TRIPP_LITE_OMNIVS_2001 || - is_smart_protocol() ) { + if (tl_model == TRIPP_LITE_OMNIVS + || tl_model == TRIPP_LITE_OMNIVS_2001 + || is_smart_protocol() + ) { /* dq ~= sqrt(dV) is a reasonable approximation * Results fit well against the discrete function used in the Tripp Lite * source, but give a continuous result. */ diff --git a/drivers/tripplitesu.c b/drivers/tripplitesu.c index f00fae5153..3fd1828fae 100644 --- a/drivers/tripplitesu.c +++ b/drivers/tripplitesu.c @@ -66,6 +66,7 @@ The following parameters (ups.conf) are supported: lowbatt + command_delay The following variables are supported (RW = read/write): ambient.humidity (1) @@ -126,7 +127,7 @@ #include "nut_stdint.h" #define DRIVER_NAME "Tripp Lite SmartOnline driver" -#define DRIVER_VERSION "0.11" +#define DRIVER_VERSION "0.12" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -163,6 +164,8 @@ static struct { unsigned long commands_available; } ups; +static long command_delay = 0; /* delay in milliseconds before each command, 0 = no delay by default */ + /* bits in commands_available */ #define WDG_AVAILABLE (1UL << 1) @@ -224,6 +227,11 @@ static ssize_t do_command(char type, const char *command, const char *parameters ser_flush_io(upsfd); + /* Apply configurable delay if enabled (> 0) to prevent communication timeouts */ + if (command_delay > 0) { + usleep((useconds_t)command_delay*1000); + } + if (response) { *response = '\0'; } @@ -302,9 +310,9 @@ static ssize_t do_command(char type, const char *command, const char *parameters upsdebugx(3, "do_command: %" PRIiSIZE " bytes read [%s]", ret, response); /* Tripp Lite pads their string responses with spaces. - I don't like that, so I remove them. This is safe to - do with all responses for this protocol, so I just - do that here. */ + * I don't like that, so I remove them. This is safe to + * do with all responses for this protocol, so I just + * do that here. */ str_rtrim(response, ' '); return ret; @@ -427,7 +435,7 @@ static int get_sensitivity(void) { for (i = 0; i < SIZEOF_ARRAY(sensitivity); i++) { if (sensitivity[i].code == atoi(response)) { dstate_setinfo("input.sensitivity", "%s", - sensitivity[i].name); + sensitivity[i].name); return 1; } } @@ -606,7 +614,7 @@ void upsdrv_initinfo(void) if (!init_comm()) fatalx(EXIT_FAILURE, "Unable to detect Tripp Lite SmartOnline UPS on port %s\n", - device_path); + device_path); min_low_transfer = max_low_transfer = 0; min_high_transfer = max_high_transfer = 0; @@ -621,16 +629,16 @@ void upsdrv_initinfo(void) ptr = field(response, 0); if (ptr) dstate_setinfo("input.voltage.nominal", "%d", - atoi(ptr)); + atoi(ptr)); ptr = field(response, 2); if (ptr) { dstate_setinfo("output.voltage.nominal", "%d", - atoi(ptr)); + atoi(ptr)); } ptr = field(response, 14); if (ptr) dstate_setinfo("battery.voltage.nominal", "%d", - atoi(ptr)); + atoi(ptr)); ptr = field(response, 10); if (ptr) { int ipv = atoi(ptr); @@ -677,7 +685,7 @@ void upsdrv_initinfo(void) dstate_setflags("input.sensitivity", ST_FLAG_RW); for (i = 0; i < SIZEOF_ARRAY(sensitivity); i++) dstate_addenum("input.sensitivity", "%s", - sensitivity[i].name); + sensitivity[i].name); } if (ups.outlet_banks) { dstate_addcmd("load.off"); @@ -699,8 +707,10 @@ void upsdrv_initinfo(void) upsh.instcmd = instcmd; upsh.setvar = setvar; - printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"), - dstate_getinfo("ups.model"), device_path); + printf("Detected %s %s on %s\n", + dstate_getinfo("ups.mfr"), + dstate_getinfo("ups.model"), + device_path); } void upsdrv_updateinfo(void) @@ -758,15 +768,15 @@ void upsdrv_updateinfo(void) ptr = field(response, 3); if (ptr) dstate_setinfo("output.voltage", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); ptr = field(response, 1); if (ptr) dstate_setinfo("output.frequency", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); ptr = field(response, 4); if (ptr) dstate_setinfo("output.current", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); low_battery = 0; if (do_command(POLL, STATUS_BATTERY, "", response) <= 0) { @@ -786,18 +796,22 @@ void upsdrv_updateinfo(void) if (ptr) { dstate_setinfo("battery.charge", "%d", atoi(ptr)); ptr2 = getval("lowbatt"); - if (ptr2 && atoi(ptr2) > 0 && atoi(ptr2) <= 99 && - atoi(ptr) <= atoi(ptr2)) + if (ptr2 + && atoi(ptr2) > 0 + && atoi(ptr2) <= 99 + && atoi(ptr) <= atoi(ptr2) + ) { low_battery = 1; + } } ptr = field(response, 6); if (ptr) dstate_setinfo("battery.voltage", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); ptr = field(response, 7); if (ptr) dstate_setinfo("battery.current", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); if (low_battery) status_set("LB"); @@ -813,11 +827,11 @@ void upsdrv_updateinfo(void) ptr = field(response, 2); if (ptr) dstate_setinfo("input.voltage", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); ptr = field(response, 1); if (ptr) dstate_setinfo("input.frequency", "%03.1f", - (double) (atoi(ptr)) / 10.0); + (double) (atoi(ptr)) / 10.0); } if (do_command(POLL, TEST_RESULT, "", response) > 0) { @@ -870,7 +884,7 @@ void upsdrv_shutdown(void) printf("Status failed. Assuming it's on battery and trying a shutdown anyway.\n"); auto_reboot(1); /* in case the power is on, tell it to automatically reboot. if - it is off, this has no effect. */ + * it is off, this has no effect. */ snprintf(parm, sizeof(parm), "%d", 1); /* delay before reboot, in minutes */ do_command(SET, TSU_SHUTDOWN_RESTART, parm, NULL); snprintf(parm, sizeof(parm), "%d", 5); /* delay before shutdown, in seconds */ @@ -890,12 +904,35 @@ void upsdrv_tweak_prognames(void) void upsdrv_makevartable(void) { addvar(VAR_VALUE, "lowbatt", "Set low battery level, in percent"); + addvar(VAR_VALUE, "command_delay", + "Delay in milliseconds before each command (default: 0 = no delay; " + "set to 1000ms if experiencing communication timeouts)"); } void upsdrv_initups(void) { + const char *val; + upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); + + /* Initialize command_delay from configuration */ + val = getval("command_delay"); + if (val) { + long temp = atol(val); + /* 0 (no delay) or positive values */ + if (temp < 0) { + fatalx(EXIT_FAILURE, "Invalid command_delay parameter: %s (must be >= 0)", val); + } + command_delay = temp; + if (command_delay == 0) { + upsdebugx(2, "command_delay is explicitly set to 0 (no delay)"); + } else { + upsdebugx(2, "Setting command_delay to %ld milliseconds", command_delay); + } + } else { + upsdebugx(2, "Using default command_delay of %ld (no delay)", command_delay); + } } void upsdrv_cleanup(void) diff --git a/drivers/upscode2.c b/drivers/upscode2.c index 58134b841a..bbbaeb8720 100644 --- a/drivers/upscode2.c +++ b/drivers/upscode2.c @@ -1043,8 +1043,8 @@ static ssize_t upscrecv(char *buf) ssize_t res; /* NOTE: the serial port is set to use Canonical Mode Input Processing, - which means ser_get_buf() either returns one line terminated with - ENDCHAR, an error or times out. */ + * which means ser_get_buf() either returns one line terminated with + * ENDCHAR, an error or times out. */ while (1) { res = ser_get_buf(upsfd, buf, UPSC_BUFLEN, input_timeout_sec, 0); diff --git a/drivers/upsdrvctl.c b/drivers/upsdrvctl.c index 08bbf12e26..8b1ee9a9db 100644 --- a/drivers/upsdrvctl.c +++ b/drivers/upsdrvctl.c @@ -92,6 +92,17 @@ static char *pt_root = NULL, *pt_user = NULL, *pt_cmd = NULL; static int nut_debug_level_passthrough = 0; static int nut_foreground_passthrough = -1; +/* Users can pass a -D[...] option to enable debugging. + * For the service tracing purposes, also the ups.conf + * can define a debug_min value in the global or device + * section, to set the minimal debug level (CLI provided + * value less than that would not have effect, can only + * have more). Finally, it can also be set over socket + * protocol, taking precedence over other inputs. + */ +static int nut_debug_level_args = -1; +static int nut_debug_level_global = -1; + /* Keep track of requested operation (function pointer) */ static void (*command)(const ups_t *) = NULL; @@ -107,6 +118,28 @@ static int signal_flag = 0; static char *signal_flag = NULL; #endif /* WIN32 */ +/* Reduced version of code from drivers/main.c */ +static void assign_debug_level(void) { + /* CLI debug level can not be smaller than debug_min specified + * in ups.conf, and for upsdrvctl tool we care about the global + * value (not any specified for a driver config section). + * Note that a non-zero debug_min does not impact foreground + * running mode. + */ + + /* At minimum, use the verbosity we started with - via CLI + * arguments; but maybe a greater debug_min is set in current + * config file. + */ + nut_debug_level = nut_debug_level_args; + if (nut_debug_level_global > nut_debug_level) { + /* Applying debug_min=%d from ups.conf global section */ + nut_debug_level = nut_debug_level_global; + } + + upsdebugx(1, "debug level for upsdrvctl is '%d'", nut_debug_level); +} + void do_upsconf_args(char *arg_upsname, char *var, char *val) { ups_t *tmp, *last; @@ -141,6 +174,22 @@ void do_upsconf_args(char *arg_upsname, char *var, char *val) } } + /* Allow to specify its minimal debugging level for all drivers - + * or the upsdrvctl tool here - and admins can set more with + * command-line args, but can't set less without changing config. + * Should help debug of services. + */ + if (!strcasecmp(var, "debug_min")) { + int lvl = -1; /* typeof common/common.c: int nut_debug_level */ + if ( str_to_int (val, &lvl, 10) && lvl >= 0 ) { + nut_debug_level_global = lvl; + } else { + upslogx(LOG_INFO, "WARNING : Invalid debug_min value found in ups.conf global settings"); + } + + return; + } + /* ignore anything else - it's probably for main */ return; @@ -183,10 +232,10 @@ void do_upsconf_args(char *arg_upsname, char *var, char *val) return; } - tmp = tmp->next; + tmp = (ups_t*)tmp->next; } - tmp = xmalloc(sizeof(ups_t)); + tmp = (ups_t*)xmalloc(sizeof(ups_t)); tmp->upsname = xstrdup(arg_upsname); tmp->driver = NULL; tmp->port = NULL; @@ -388,8 +437,97 @@ static void stop_driver(const ups_t *ups) } if (ret != 0) { + ssize_t udq_ret; + udq_pipe_conn_t *udq_pipe; + upslog_with_errno(LOG_ERR, "Can't open %s either", pidfn); - exec_error++; + + udq_pipe = upsdrvquery_connect_drvname_upsname(ups->driver, ups->upsname); + if (udq_pipe) { + upslogx(LOG_ERR, "At least could open the driver socket"); + } else { + /* There IS a chance that the driver is still + * starting and not listening on the socket yet. + * FIXME: Could align with ups->maxstartdelay... + * but if it is just not running -- this may + * mean minutes of fruitless sleep. + */ + upsdebugx(1, "%s: initial driver socket connection failed, retrying shortly", __func__); + sleep(5); + udq_pipe = upsdrvquery_connect_drvname_upsname(ups->driver, ups->upsname); + if (udq_pipe) { + upslogx(LOG_ERR, "At least could open the driver socket"); + } + } + + if (testmode) { + udq_ret = (udq_pipe == NULL ? -1 : 0); + } else { + char buf[LARGEBUF]; + struct timeval tv; + + memset(buf, 0, sizeof(buf)); + /* Post the query and wait for reply */ + /* FIXME: coordinate with pollfreq? */ + + /* Below we poke reads inside ping every 0.1s, + * which is not too often but responsive enough. + * Sometimes we do get into being able to send + * "PING" but as the channel is closing, the + * reads return 0 and errno=Success infinitely. + * So we first ping with a 1-second timeout, + * then retry (and maybe fail instantly but + * definitely with EPIPE) with a 3-sec backoff, + * and then again with a longer common countdown + * (tv = 15.0s caried over remaining retries). + */ + tv.tv_sec = 1; + tv.tv_usec = 0; + udq_ret = upsdrvquery_oneshot_conn(udq_pipe, "INSTCMD driver.exit\n", buf, sizeof(buf), &tv); + upsdebugx(1, "%s: upsdrvquery_oneshot_conn() replied to 'exit' (%" PRIiSIZE "): '%s'", __func__, udq_ret, buf); + + if (udq_ret >= 0) { + int n = 0; + + upsdrvquery_write(udq_pipe, "NOBROADCAST"); + while (upsdrvquery_ping(udq_pipe, &tv, 100000) > (n == 0 ? -1 : 0)) { + /* 0 = no reply, -1 = socket error; either way driver deemed dead? */ + upsdebugx(1, "%s: keep waiting for driver exit", __func__); + sleep(1); + n++; + switch (n) { + case 1: + /* New TO for longer backoff, once */ + tv.tv_sec = 3; + tv.tv_usec = 0; + break; + case 2: + /* New TO overall, set once */ + tv.tv_sec = 15; + tv.tv_usec = 0; + break; + default: + break; + } + } + upsdebug_with_errno(1, "%s: final PING did not PONG back", __func__); + /* Let the driver's exit() finish */ + usleep(1000000); + } + } + + upslogx(LOG_ERR, "%s to %s the 'exit' command to the driver socket", + (udq_ret < 0) ? "Failed" : "Succeeded", + testmode ? "emulate" : "send"); + + if (udq_ret < 0) { + upslogx(LOG_ERR, "Failed to stop the driver %s for %s, it may be not running or not fully started yet", + ups->driver, ups->upsname); + exec_error++; + } + + upsdrvquery_close(udq_pipe); + return; } } else { @@ -805,7 +943,7 @@ static void forkexec(char *const argv[], const ups_t *ups) BOOL ret; DWORD res; DWORD exit_code = 0; - char commandline[SMALLBUF]; + char commandline[LARGEBUF]; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; int i = 1; @@ -813,15 +951,34 @@ static void forkexec(char *const argv[], const ups_t *ups) memset(&StartupInfo, 0, sizeof(STARTUPINFO)); /* the command line is made of the driver name followed by args */ - snprintf(commandline, sizeof(commandline), "%s", ups->driver); + if (strstr(argv[0], ups->driver)) { + /* We already know whom to call (got a pointer + * to needle in the haystack); that path may + * have spaces ("Program Files") so quoted. + */ + snprintf(commandline, sizeof(commandline), "\"%s\"", argv[0]); + } else { + /* Hope for the PATH based resolution to work, perhaps the + * driver program is located nearby (depends on configure + * options). Note that for builds tested in the workspace + * this may be misleading ("nearby" is under ".libs/" and + * fails to run directly without the tweaks of libtool + * wrapper provided in the directory just above). + */ + snprintf(commandline, sizeof(commandline), "%s%s", ups->driver, EXEEXT); + } + while (argv[i] != NULL) { + /* TOTHINK: No known toxic spaces to quote here... */ snprintfcat(commandline, sizeof(commandline), " %s", argv[i]); i++; } + upsdebugx(1, "%s[WIN32]: CreateProcess(argv0='%s' cmdline='%s')...", + __func__, argv[0], commandline); ret = CreateProcess( - argv[0], - commandline, + argv[0], /* Application/Module name, often the program to run */ + commandline, /* Full command line including the program to run and its args */ NULL, NULL, FALSE, @@ -897,7 +1054,8 @@ static void status_driver(const ups_t *ups) #ifndef WIN32 snprintf(pidfn, sizeof(pidfn), "%s/%s-%s.pid", altpidpath(), ups->driver, ups->upsname); pidFromFile = parsepidfile(pidfn); - if (pidFromFile >= 0) { /* this method actively reports errors, if any */ + if (pidFromFile >= 0) { + /* this method actively reports errors, if any */ cmdret = sendsignalpid(pidFromFile, 0, ups->driver, 1); /* returns zero for a successfully sent signal */ if (cmdret == 0) @@ -1098,7 +1256,10 @@ static void start_driver(const ups_t *ups) #ifndef WIN32 snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver); #else /* WIN32 */ - snprintf(dfn, sizeof(dfn), "%s/%s.exe", driverpath, ups->driver); + if (driverpath && *driverpath == '/') + snprintf(dfn, sizeof(dfn), "%s/%s.exe", driverpath, ups->driver); + else /* Assume windows-style path with backslashes */ + snprintf(dfn, sizeof(dfn), "%s\\%s.exe", driverpath, ups->driver); #endif /* WIN32 */ ret = stat(dfn, &fs); @@ -1365,7 +1526,7 @@ static void send_one_driver(void (*command_func)(const ups_t *), const char *arg return; } - ups = ups->next; + ups = (ups_t*)ups->next; } fatalx(EXIT_FAILURE, "UPS %s not found in ups.conf", arg_upsname); @@ -1386,7 +1547,7 @@ static void send_all_drivers(void (*command_func)(const ups_t *)) if (command_func == &list_driver || command_func == &status_driver) { while (ups) { command_func(ups); - ups = ups->next; + ups = (ups_t*)ups->next; } fflush(stdout); @@ -1420,7 +1581,7 @@ static void send_all_drivers(void (*command_func)(const ups_t *)) while (ups) { command_func(ups); - ups = ups->next; + ups = (ups_t*)ups->next; } return; @@ -1432,7 +1593,7 @@ static void send_all_drivers(void (*command_func)(const ups_t *)) if (ups->sdorder == i) command_func(ups); - ups = ups->next; + ups = (ups_t*)ups->next; } } } @@ -1451,7 +1612,7 @@ static void exit_cleanup(void) ) { /* First stop the drivers, if any are running */ while (tmp) { - next = tmp->next; + next = (ups_t*)tmp->next; if (tmp->pid != -1) { stop_driver(tmp); } @@ -1461,7 +1622,7 @@ static void exit_cleanup(void) tmp = upstable; while (tmp) { - next = tmp->next; + next = (ups_t*)tmp->next; free(tmp->driver); free(tmp->port); @@ -1483,6 +1644,10 @@ int main(int argc, char **argv) prog = argv[0]; +#if (defined ENABLE_SHARED_PRIVATE_LIBS) && ENABLE_SHARED_PRIVATE_LIBS + callback_upsconf_args = do_upsconf_args; +#endif + /* Historically special banner*/ snprintf(progdesc, sizeof(progdesc), "%s - UPS driver controller", xbasename(prog)); print_banner_once(progdesc, 0); @@ -1509,7 +1674,9 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); case 'D': - nut_debug_level++; + if (nut_debug_level_args < 0) + nut_debug_level_args = 0; + nut_debug_level_args++; break; case 'd': @@ -1607,10 +1774,10 @@ int main(int argc, char **argv) char *s = getenv("NUT_DEBUG_LEVEL"); int l; if (s && str_to_int(s, &l, 10)) { - if (l > 0 && nut_debug_level < 1) { + if (l > 0 && nut_debug_level_args < 1) { upslogx(LOG_INFO, "Defaulting debug verbosity to NUT_DEBUG_LEVEL=%d " "since none was requested by command-line options", l); - nut_debug_level = l; + nut_debug_level_args = l; } /* else follow -D settings */ } /* else nothing to bother about */ } @@ -1660,6 +1827,18 @@ int main(int argc, char **argv) if (!command) fatalx(EXIT_FAILURE, "Error: unrecognized command [%s]", argv[0]); +#ifndef WIN32 + driverpath = xstrdup(DRVPATH); /* set default */ +#else /* WIN32 */ + driverpath = getfullpath2(DRVPATH, PATH_BIN); /* Can get converted to relative path in WIN32 */ +#endif /* WIN32 */ + + atexit(exit_cleanup); + + read_upsconf(1); + + assign_debug_level(); + if (nut_debug_level_passthrough == 0 && (command == &start_driver || command == &shutdown_driver)) { upsdebugx(2, "\n" "If you're not a NUT core developer, chances are that you're told to enable debugging\n" @@ -1673,16 +1852,6 @@ int main(int argc, char **argv) "pass its current debug level to the launched driver, and '-B' keeps it backgrounded.\n"); } -#ifndef WIN32 - driverpath = xstrdup(DRVPATH); /* set default */ -#else /* WIN32 */ - driverpath = getfullpath2(DRVPATH, PATH_BIN); /* Can get converted to relative path in WIN32 */ -#endif /* WIN32 */ - - atexit(exit_cleanup); - - read_upsconf(1); - if (argc == lastarg) { ups_t *tmp = upstable; char tag[SMALLBUF]; @@ -1690,7 +1859,7 @@ int main(int argc, char **argv) upscount = 0; while (tmp) { - tmp = tmp->next; + tmp = (ups_t*)tmp->next; upscount++; } @@ -1832,7 +2001,7 @@ int main(int argc, char **argv) } } - tmp = tmp->next; + tmp = (ups_t*)tmp->next; } #else /* WIN32 */ /* TOTHINK: Is there something we can do on the platform? */ @@ -1866,7 +2035,7 @@ int main(int argc, char **argv) * and exit the tool - with error if applicable. */ while (tmp) { - next = tmp->next; + next = (ups_t*)tmp->next; if (tmp->pid != -1) { int status; if (waitpid(tmp->pid, &status, WNOHANG) == tmp->pid) { @@ -1928,7 +2097,7 @@ int main(int argc, char **argv) tmp = upstable; while (tmp) { - next = tmp->next; + next = (ups_t*)tmp->next; signal_driver(tmp); tmp = next; } diff --git a/drivers/upsdrvquery.c b/drivers/upsdrvquery.c index 0fc348ec5f..a105e53624 100644 --- a/drivers/upsdrvquery.c +++ b/drivers/upsdrvquery.c @@ -52,6 +52,14 @@ */ int nut_upsdrvquery_debug_level = NUT_UPSDRVQUERY_DEBUG_LEVEL_DEFAULT; +/* Do our best to disable SIGPIPE in failed write()/send() attempts? + * Note errno=EPIPE should still be raised in case of failure, just + * the process using this code would not crash. Feature is enabled + * by default, but consumers which handle their signals specially + * can disable it by setting upsdrvquery_NOSIGPIPE=0 + */ +int upsdrvquery_NOSIGPIPE = 1; + udq_pipe_conn_t *upsdrvquery_connect(const char *sockfn) { udq_pipe_conn_t *conn = (udq_pipe_conn_t*)xcalloc(1, sizeof(udq_pipe_conn_t)); @@ -187,8 +195,59 @@ void upsdrvquery_close(udq_pipe_conn_t *conn) { if (VALID_FD(conn->sockfd)) { int nudl = nut_upsdrvquery_debug_level; ssize_t ret; + + /* The connection may be closed on the other side, + * so send() can issue SIGPIPE and by default the + * process crashes. Try to work around that here. + * https://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly + * NOTE: in upsdrvquery_write() we use MSG_NOSIGNAL + * where available instead of plain write(). + */ +#ifndef WIN32 +# ifndef MSG_NOSIGNAL +# ifdef SO_NOSIGPIPE + /* Just for this one socket (and gonna be gone soon): */ + int set = 1; + if (upsdrvquery_NOSIGPIPE) + setsockopt(conn->sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); +# else /* !SO_NOSIGPIPE */ + /* Not thread-safe, but we do not aim for this here, hopefully + * (any nut-scanner users, though?) and this is a last-resort + * variant during build. Probably plain signal(SIGPIPE, SIG_IGN) + * would be as good (used all over NUT code base) -- but we do + * not know whether a random API consumer handles or ignores + * the signal?.. + */ + sigset_t old_state, set; + + if (upsdrvquery_NOSIGPIPE) { + /* get the current state */ + sigprocmask(SIG_BLOCK, NULL, &old_state); + + /* add signal_to_block to that existing state */ + set = old_state; + sigaddset(&set, SIGPIPE); + + /* block that signal also */ + sigprocmask(SIG_BLOCK, &set, NULL); + } +# endif /* !SO_NOSIGPIPE */ +# endif /* !MSG_NOSIGNAL */ +#endif /* !WIN32 */ + upsdebugx(5, "%s: closing driver socket, try to say goodbye", __func__); + ret = upsdrvquery_write(conn, "LOGOUT\n"); + +#ifndef WIN32 +# ifndef MSG_NOSIGNAL +# ifndef SO_NOSIGPIPE + if (upsdrvquery_NOSIGPIPE) + sigprocmask(SIG_BLOCK, &old_state, NULL); +# endif /* !SO_NOSIGPIPE */ +# endif /* !MSG_NOSIGNAL */ +#endif /* !WIN32 */ + if (7 <= ret) { upsdebugx(5, "%s: okay", __func__); #ifdef WIN32 @@ -196,7 +255,15 @@ void upsdrvquery_close(udq_pipe_conn_t *conn) { #endif /* WIN32 */ usleep(1000000); } else { - upsdebugx(5, "%s: must have been closed on the other side", __func__); + if (errno == EPIPE) { + upsdebug_with_errno(5, "%s: write failed, socket must have been closed on the other side - okay for goodbye", __func__); +#ifdef WIN32 + loggedOut = 1; +#endif /* WIN32 */ + usleep(1000000); + } else { + upsdebug_with_errno(5, "%s: write failed", __func__); + } } nut_upsdrvquery_debug_level = nudl; } @@ -399,7 +466,15 @@ ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf) { } #ifndef WIN32 +# ifdef MSG_NOSIGNAL + if (upsdrvquery_NOSIGPIPE) + ret = send(conn->sockfd, buf, buflen, MSG_NOSIGNAL); + else + ret = write(conn->sockfd, buf, buflen); +# else + /* Per docs, same as send() with zero flags value */ ret = write(conn->sockfd, buf, buflen); +# endif if (ret < 0 || ret != (int)buflen) { if (nut_debug_level > 0 || nut_upsdrvquery_debug_level >= NUT_UPSDRVQUERY_DEBUG_LEVEL_DIALOG) @@ -424,35 +499,43 @@ ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf) { return -1; } -ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { - struct timeval start, now; +/* Return 1 if we had a reply, 0 if not, -1 on socket errors */ +ssize_t upsdrvquery_ping(udq_pipe_conn_t *conn, struct timeval *ptv, useconds_t read_interval) { + struct timeval start, now, last, tv; + double maxdiff; - if (!conn || INVALID_FD(conn->sockfd)) - return -1; - - /* Avoid noise */ - if (upsdrvquery_write(conn, "NOBROADCAST\n") < 0) - goto socket_error; - - if (tv.tv_sec < 1 && tv.tv_usec < 1) { - upsdebugx(5, "%s: proclaiming readiness for tracked commands without flush of server messages", __func__); - return 1; + if (!ptv) { + tv.tv_sec = 5; + tv.tv_usec = 0; + ptv = &tv; } + maxdiff = (double)(ptv->tv_sec) + 0.000001 * (double)(ptv->tv_usec); - /* flush incoming, if any */ gettimeofday(&start, NULL); if (upsdrvquery_write(conn, "PING\n") < 0) - goto socket_error; + return -1; - upsdebugx(5, "%s: waiting for a while to flush server messages", __func__); + last = start; while (1) { - char *buf; - upsdrvquery_read_timeout(conn, tv); + char *buf; + ssize_t read_ret; + double delta; + + errno = 0; + read_ret = upsdrvquery_read_timeout(conn, *ptv); + + if (errno == EPIPE) { + upsdebug_with_errno(5, "%s: upsdrvquery_read_timeout() connection was closed: %" PRIiSIZE, __func__, read_ret); + return -1; + } + + upsdebug_with_errno(5, "%s: upsdrvquery_read_timeout() returned %" PRIiSIZE, __func__, read_ret); + gettimeofday(&now, NULL); - if (difftimeval(now, start) > ((double)(tv.tv_sec) + 0.000001 * (double)(tv.tv_usec))) { + if (difftimeval(now, start) > maxdiff) { upsdebugx(5, "%s: requested timeout expired", __func__); - break; + return 0; } /* Await a PONG for quick confirmation of achieved quietness @@ -467,7 +550,7 @@ ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { while (buf && *buf) { if (!strncmp(buf, "PONG\n", 5)) { upsdebugx(5, "%s: got expected PONG", __func__); - goto finish; + return 1; } buf = strchr(buf, '\n'); if (buf) { @@ -479,17 +562,70 @@ ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { } } - /* Diminishing timeouts for read() */ - tv.tv_usec -= (suseconds_t)(difftimeval(now, start)); - while (tv.tv_usec < 0) { - tv.tv_sec--; - tv.tv_usec = 1000000 + tv.tv_usec; /* Note it is negative */ + if (read_interval) { + upsdebugx(5, "%s: sleep %" PRIuMAX "usec", __func__, (uintmax_t)read_interval); + usleep(read_interval); + } + + /* Diminishing timeouts for read() and later processing */ + last = now; + gettimeofday(&now, NULL); + delta = difftimeval(now, last); + upsdebugx(7, "%s: start tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "}", + __func__, (intmax_t)start.tv_sec, (intmax_t)start.tv_usec); + upsdebugx(7, "%s: last tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "}", + __func__, (intmax_t)last.tv_sec, (intmax_t)last.tv_usec); + upsdebugx(7, "%s: now tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "}", + __func__, (intmax_t)now.tv_sec, (intmax_t)now.tv_usec); + upsdebugx(6, "%s: initial tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "}; applying delta %g", + __func__, (intmax_t)ptv->tv_sec, (intmax_t)ptv->tv_usec, + delta); + + /* Note: delta is in whole seconds and fractional useconds */ + while (delta > 1) { + delta -= 1; + ptv->tv_sec--; + } + + /* Fractional remainder */ + ptv->tv_usec -= (suseconds_t)(delta * 1000000); + upsdebugx(7, "%s: semiupd tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "} (1e6*delta = %" PRIiMAX ")", + __func__, (intmax_t)ptv->tv_sec, (intmax_t)ptv->tv_usec, + (intmax_t)(delta * 1000000)); + while (ptv->tv_usec < 0) { + ptv->tv_sec--; + ptv->tv_usec = 1000000 + ptv->tv_usec; /* Note it is negative */ } - if (tv.tv_sec <= 0 && tv.tv_usec <= 0) { + upsdebugx(6, "%s: updated tv={sec=%" PRIiMAX ", usec=%06" PRIiMAX "}", + __func__, (intmax_t)ptv->tv_sec, (intmax_t)ptv->tv_usec); + if (ptv->tv_sec < 0) { upsdebugx(5, "%s: requested timeout expired", __func__); - break; + return 0; } } +} + +ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { + if (!conn || INVALID_FD(conn->sockfd)) + return -1; + + /* Avoid noise */ + if (upsdrvquery_write(conn, "NOBROADCAST\n") < 0) + goto socket_error; + + if (tv.tv_sec < 1 && tv.tv_usec < 1) { + upsdebugx(5, "%s: proclaiming readiness for tracked commands without flush of server messages", __func__); + return 1; + } + + /* flush incoming, if any */ + upsdebugx(5, "%s: waiting for a while to flush server messages - posting a PING, waiting for PONG", __func__); + switch (upsdrvquery_ping(conn, &tv, 1000)) { + case -1: goto socket_error; + case 0: goto finish; /* No reply - maybe handle somehow? */ + case 1: break; /* Got PONG */ + default: break; + } /* Check that we can have a civilized dialog -- * nope, this one is for network protocol diff --git a/drivers/upsdrvquery.h b/drivers/upsdrvquery.h index 8d84a4314e..cd2aac5077 100644 --- a/drivers/upsdrvquery.h +++ b/drivers/upsdrvquery.h @@ -42,6 +42,9 @@ void upsdrvquery_close(udq_pipe_conn_t *conn); ssize_t upsdrvquery_read_timeout(udq_pipe_conn_t *conn, struct timeval tv); ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf); +/* Return 1 if we had a reply within timeout specified by *ptv (5 sec if NULL), + * 0 if not, -1 on socket errors */ +ssize_t upsdrvquery_ping(udq_pipe_conn_t *conn, struct timeval *ptv, useconds_t read_interval); ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv); ssize_t upsdrvquery_request(udq_pipe_conn_t *conn, struct timeval tv, const char *query); ssize_t upsdrvquery_restore_broadcast(udq_pipe_conn_t *conn); @@ -60,4 +63,12 @@ extern int nut_upsdrvquery_debug_level; #define NUT_UPSDRVQUERY_DEBUG_LEVEL_CONNECT 5 #define NUT_UPSDRVQUERY_DEBUG_LEVEL_DIALOG 4 +/* Do our best to disable SIGPIPE in failed write()/send() attempts? + * Note errno=EPIPE should still be raised in case of failure, just + * the process using this code would not crash. Feature is enabled + * by default, but consumers which handle their signals specially + * can disable it by setting upsdrvquery_NOSIGPIPE=0 + */ +extern int upsdrvquery_NOSIGPIPE; + #endif /* NUT_UPSDRVQUERY_H_SEEN */ diff --git a/drivers/upshandler.h b/drivers/upshandler.h index 3d8a378968..c2267fd7b3 100644 --- a/drivers/upshandler.h +++ b/drivers/upshandler.h @@ -181,9 +181,9 @@ struct ups_handler strstr(cmdname, "shutdown.") == cmdname || \ strstr(cmdname, "load.off") == cmdname || \ strstr(cmdname, "load.cycle") == cmdname || \ - ( strstr(cmdname, "outlet.") == cmdname && ( \ - strstr(cmdname, "shutdown.") || \ - strstr(cmdname, "load") \ + ( strstr(cmdname, "outlet.") == cmdname && \ + ( strstr(cmdname, "shutdown.") \ + || strstr(cmdname, "load") \ ) ) \ ) { \ upslog_INSTCMD_POWERSTATE_CHANGE(cmdname, extra) ; \ diff --git a/drivers/usb-common.c b/drivers/usb-common.c index 4834714cc8..65068c7bff 100644 --- a/drivers/usb-common.c +++ b/drivers/usb-common.c @@ -26,26 +26,40 @@ int is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *de int retval = NOT_SUPPORTED; usb_device_id_t *usbdev; - for (usbdev = usb_device_id_list; - (usbdev->vendorID != 0 || usbdev->productID != 0 || usbdev->fun != NULL); - usbdev++ + upsdebugx(3, "%s: checking if this driver can support USB device VID:PID 0x%04X:0x%04X", + __func__, (unsigned int)device->VendorID, (unsigned int)device->ProductID); + + for ( + usbdev = usb_device_id_list; + (usbdev->vendorID != 0 || usbdev->productID != 0 || usbdev->fun != NULL); + usbdev++ ) { + upsdebugx(4, "%s: checking table entry for VID:PID 0x%04X:0x%04X " + "(custom init handler is%s available)", + __func__, (unsigned int)usbdev->vendorID, + (unsigned int)usbdev->productID, + (usbdev->fun == NULL ? " NOT" : "")); + if (usbdev->vendorID != device->VendorID) { + upsdebugx(4, "%s: NOT_SUPPORTED: vendor ID mismatch", __func__); continue; } /* flag as possibly supported if we see a known vendor */ retval = POSSIBLY_SUPPORTED; + upsdebugx(4, "%s: POSSIBLY_SUPPORTED: known vendor ID at least", __func__); if (usbdev->productID != device->ProductID) { continue; } /* call the specific handler, if it exists */ if (usbdev->fun != NULL) { + upsdebugx(4, "%s: call the custom init handler", __func__); (*usbdev->fun)(device); } + upsdebugx(4, "%s: SUPPORTED: known vendor and product IDs", __func__); return SUPPORTED; } @@ -65,37 +79,37 @@ static int match_function_exact(USBDevice_t *hd, void *privdata) if (hd->VendorID != data->VendorID) { upsdebugx(2, "%s: failed match of %s: %4x != %4x", - __func__, "VendorID", hd->VendorID, data->VendorID); + __func__, "VendorID", hd->VendorID, data->VendorID); return 0; } if (hd->ProductID != data->ProductID) { upsdebugx(2, "%s: failed match of %s: %4x != %4x", - __func__, "ProductID", hd->ProductID, data->ProductID); + __func__, "ProductID", hd->ProductID, data->ProductID); return 0; } if (strcmp_null(hd->Vendor, data->Vendor) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "Vendor", hd->Vendor, data->Vendor); + __func__, "Vendor", hd->Vendor, data->Vendor); return 0; } if (strcmp_null(hd->Product, data->Product) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "Product", hd->Product, data->Product); + __func__, "Product", hd->Product, data->Product); return 0; } if (strcmp_null(hd->Serial, data->Serial) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "Serial", hd->Serial, data->Serial); + __func__, "Serial", hd->Serial, data->Serial); return 0; } #ifdef DEBUG_EXACT_MATCH_BUS if (strcmp_null(hd->Bus, data->Bus) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "Bus", hd->Bus, data->Bus); + __func__, "Bus", hd->Bus, data->Bus); return 0; } #endif @@ -103,7 +117,7 @@ static int match_function_exact(USBDevice_t *hd, void *privdata) # ifdef DEBUG_EXACT_MATCH_BUSPORT if (strcmp_null(hd->BusPort, data->BusPort) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "BusPort", hd->BusPort, data->BusPort); + __func__, "BusPort", hd->BusPort, data->BusPort); return 0; } # endif @@ -111,7 +125,7 @@ static int match_function_exact(USBDevice_t *hd, void *privdata) #ifdef DEBUG_EXACT_MATCH_DEVICE if (strcmp_null(hd->Device, data->Device) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", - __func__, "Device", hd->Device, data->Device); + __func__, "Device", hd->Device, data->Device); return 0; } #endif @@ -127,12 +141,12 @@ int USBNewExactMatcher(USBDeviceMatcher_t **matcher, USBDevice_t *hd) USBDeviceMatcher_t *m; USBDevice_t *data; - m = malloc(sizeof(*m)); + m = (USBDeviceMatcher_t*)malloc(sizeof(*m)); if (!m) { return -1; } - data = calloc(1, sizeof(*data)); + data = (USBDevice_t*)calloc(1, sizeof(*data)); if (!data) { free(m); return -1; @@ -209,10 +223,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %4x !~ %s", - __func__, "VendorID", hd->VendorID, data->regex[0]); + __func__, "VendorID", hd->VendorID, data->regex[0]); */ upsdebugx(2, "%s: failed match of %s: %4x", - __func__, "VendorID", hd->VendorID); + __func__, "VendorID", hd->VendorID); return r; } @@ -220,10 +234,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %4x !~ %s", - __func__, "ProductID", hd->ProductID, data->regex[1]); + __func__, "ProductID", hd->ProductID, data->regex[1]); */ upsdebugx(2, "%s: failed match of %s: %4x", - __func__, "ProductID", hd->ProductID); + __func__, "ProductID", hd->ProductID); return r; } @@ -231,10 +245,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Vendor", hd->Vendor, data->regex[2]); + __func__, "Vendor", hd->Vendor, data->regex[2]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Vendor", hd->Vendor); + __func__, "Vendor", hd->Vendor); return r; } @@ -242,10 +256,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Product", hd->Product, data->regex[3]); + __func__, "Product", hd->Product, data->regex[3]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Product", hd->Product); + __func__, "Product", hd->Product); return r; } @@ -253,10 +267,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Serial", hd->Serial, data->regex[4]); + __func__, "Serial", hd->Serial, data->regex[4]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Serial", hd->Serial); + __func__, "Serial", hd->Serial); return r; } @@ -264,10 +278,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Bus", hd->Bus, data->regex[5]); + __func__, "Bus", hd->Bus, data->regex[5]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Bus", hd->Bus); + __func__, "Bus", hd->Bus); return r; } @@ -275,10 +289,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Device", hd->Device, data->regex[6]); + __func__, "Device", hd->Device, data->regex[6]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Device", hd->Device); + __func__, "Device", hd->Device); return r; } @@ -287,10 +301,10 @@ static int match_function_regex(USBDevice_t *hd, void *privdata) if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", - __func__, "Device", hd->Device, data->regex[6]); + __func__, "Device", hd->Device, data->regex[6]); */ upsdebugx(2, "%s: failed match of %s: %s", - __func__, "Bus Port", hd->BusPort); + __func__, "Bus Port", hd->BusPort); return r; } #endif @@ -315,12 +329,12 @@ int USBNewRegexMatcher(USBDeviceMatcher_t **matcher, char **regex, int cflags) USBDeviceMatcher_t *m; regex_matcher_data_t *data; - m = malloc(sizeof(*m)); + m = (USBDeviceMatcher_t*)malloc(sizeof(*m)); if (!m) { return -1; } - data = calloc(1, sizeof(*data)); + data = (regex_matcher_data_t*)calloc(1, sizeof(*data)); if (!data) { free(m); return -1; diff --git a/drivers/usb-common.h b/drivers/usb-common.h index 7355b20965..35dae8b146 100644 --- a/drivers/usb-common.h +++ b/drivers/usb-common.h @@ -203,14 +203,14 @@ usb_ctrl_charbuf bytes, int size, int timeout) { /* - Map from libusb-0.1 API => libusb-1.0 API: - int LIBUSB_CALL libusb_control_transfer( - libusb_device_handle *dev_handle, uint8_t request_type, - uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout); - Note: In libusb-0.1 bytes was a (char*) but our consumer code - was already fixed to use "usb_ctrl_charbuf" to match other methods. - */ + * Map from libusb-0.1 API => libusb-1.0 API: + * int LIBUSB_CALL libusb_control_transfer( + * libusb_device_handle *dev_handle, uint8_t request_type, + * uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + * unsigned char *data, uint16_t wLength, unsigned int timeout); + * Note: In libusb-0.1 bytes was a (char*) but our consumer code + * was already fixed to use "usb_ctrl_charbuf" to match other methods. + */ if (requesttype < 0 || (uintmax_t)requesttype > UINT8_MAX || request < 0 || (uintmax_t)request > UINT8_MAX @@ -239,13 +239,13 @@ usb_ctrl_charbuf bytes, int size, int timeout) { /* NOTE: Also for routines below: - Map from libusb-0.1 API => libusb-1.0 API plus change of logic per below code: - int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - Note: In libusb-0.1 bytes was a (char*) but our consumer code - was already fixed to use "usb_ctrl_charbuf" to match other methods. - */ + * Map from libusb-0.1 API => libusb-1.0 API plus change of logic per below code: + * int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, + * unsigned char endpoint, unsigned char *data, int length, + * int *actual_length, unsigned int timeout); + * Note: In libusb-0.1 bytes was a (char*) but our consumer code + * was already fixed to use "usb_ctrl_charbuf" to match other methods. + */ int ret; if (ep < 0 || (uintmax_t)ep > UCHAR_MAX @@ -255,8 +255,9 @@ "usb_interrupt_read() args out of range for libusb_interrupt_transfer() implementation"); } - ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, - size, &size, (unsigned int)timeout); + ret = libusb_interrupt_transfer( + dev, (unsigned char)ep, (unsigned char *) bytes, + size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } @@ -274,8 +275,9 @@ "usb_interrupt_write() args out of range for libusb_interrupt_transfer() implementation"); } - ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, - size, &size, (unsigned int)timeout); + ret = libusb_interrupt_transfer( + dev, (unsigned char)ep, (unsigned char *) bytes, + size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } @@ -293,8 +295,9 @@ "usb_bulk_read() args out of range for libusb_interrupt_transfer() implementation"); } - ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, - size, &size, (unsigned int)timeout); + ret = libusb_interrupt_transfer( + dev, (unsigned char)ep, (unsigned char *) bytes, + size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } @@ -312,8 +315,9 @@ "usb_bulk_write() args out of range for libusb_interrupt_transfer() implementation"); } - ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, - size, &size, (unsigned int)timeout); + ret = libusb_interrupt_transfer( + dev, (unsigned char)ep, (unsigned char *) bytes, + size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } @@ -497,7 +501,7 @@ typedef struct USBDevice_s { char *Product; /*!< Device's Product Name */ char *Serial; /*!< Product serial number */ /* These data points can be determined by the driver for some devices - or by libusb to detail its connection topology: */ + * or by libusb to detail its connection topology: */ char *Bus; /*!< Bus name, e.g. "003" */ uint16_t bcdDevice; /*!< Device release number */ char *Device; /*!< Device name on the bus, e.g. "001" */ diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index da3672be1d..d0c443efb9 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -699,8 +699,8 @@ static void analyze_mapping_usage(void) { return; } - unused_names = xcalloc(unused_bufsize, sizeof(char)); - halfused_names = xcalloc(halfused_bufsize, sizeof(char)); + unused_names = (char *)xcalloc(unused_bufsize, sizeof(char)); + halfused_names = (char *)xcalloc(halfused_bufsize, sizeof(char)); for (d = 0; d < pDesc->nitems; d++) { HIDData_t *pData = &pDesc->item[d]; @@ -770,7 +770,7 @@ static void analyze_mapping_usage(void) { if (*pBufSize < SIZE_MAX - LARGEBUF) { *pBufSize = *pBufSize + LARGEBUF; upsdebugx(1, "%s: buffer overflowed, trying to re-allocate as %" PRIuSIZE, __func__, *pBufSize); - *pNames = realloc(*pNames, *pBufSize); + *pNames = (char *)realloc(*pNames, *pBufSize); if (!*pNames) { upsdebugx(1, "%s: buffer overflowed, will not report unused descriptor names", __func__); @@ -1779,7 +1779,7 @@ void upsdrv_initups(void) } /* Search for the first supported UPS matching the - regular expression (USB) or device_path (SHUT) */ + * regular expression (USB) or device_path (SHUT) */ ret = comm_driver->open_dev(&udev, &curDevice, subdriver_matcher, &callback); if (ret < 1) fatalx(EXIT_FAILURE, "No matching HID UPS found"); diff --git a/drivers/vertiv-mib.c b/drivers/vertiv-mib.c new file mode 100644 index 0000000000..f83cc46faa --- /dev/null +++ b/drivers/vertiv-mib.c @@ -0,0 +1,174 @@ +/* vertiv-mib.h - Driver for Vertiv Liebert PSI5 UPS (maybe other Vertiv too) + * + * Copyright (C) + * 2026 jawz101 + Gemini + * 2026 Jim Klimov - cleanup + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Includes support for: + * - Basic Monitoring (Voltage, Load, Temperature) + * - Battery Management (Charge, Runtime) + * - Alarms (Replace Battery, Overload, etc.) + * - Beeper Control + */ + +#include "vertiv-mib.h" + +#define VERTIV_MIB_VERSION "0.01" + +/* Base OIDs from IS-UNITY-DP Card */ +#define VERTIV_BASEOID ".1.3.6.1.4.1.476.1.42" +#define VERTIV_ID_OID VERTIV_BASEOID ".2.4.2.1.4.1" +#define VERTIV_VAL_OID VERTIV_BASEOID ".3.9.30.1.20.1.2.1" +#define VERTIV_ALM_OID VERTIV_BASEOID ".3.9.20.1.10.1.2.100" +#define VERTIV_PWRSTATUS_OID VERTIV_BASEOID ".3.5.3" +#define VERTIV_BEEPER_OID VERTIV_VAL_OID ".6188" + +#ifdef VERTIV_WITH_IETF_BEEPER_FALLBACK +/* May be defined in experimental builds */ +static info_lkp_t ietf_beeper_status_info[] = { + info_lkp_default(1, "disabled"), + info_lkp_default(2, "enabled"), + info_lkp_default(3, "muted"), + info_lkp_sentinel +}; +#endif /* VERTIV_WITH_IETF_BEEPER_FALLBACK */ + +static info_lkp_t vertiv_beeper_status_info[] = { + info_lkp_default(1, "enabled"), + info_lkp_default(2, "disabled"), + info_lkp_sentinel +}; + +/* FIXME: the below may introduce status redundancy, that needs to be + * addressed by the driver, as for usbhid-ups! */ +/* + * DESCRIPTION + * The present source of output power. The enumeration + * none(2) indicates that there is no source of output + * power (and therefore no output power), for example, + * the system has opened the output breaker. + * + * NOTE: In a single-module system, this point + * is intended to have the same behavior as + * the RFC1628 point upsOutputSource." + */ +static info_lkp_t vertiv_power_source_info[] = { + info_lkp_default(1, ""), /* other */ + info_lkp_default(2, "OFF"), /* none */ + info_lkp_default(3, "OL"), /* normal */ + info_lkp_default(4, "BYPASS"), /* bypass */ + info_lkp_default(5, "OB"), /* battery */ + info_lkp_default(6, "BOOST"), /* booster */ + info_lkp_default(7, "TRIM"), /* reducer */ + info_lkp_sentinel +}; + +static snmp_info_t vertiv_mib[] = { + /* Standard IETF MIB items */ + snmp_info_default("device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK | SU_FLAG_SEMI_STATIC, NULL), + snmp_info_default("device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK | SU_FLAG_SEMI_STATIC, NULL), + snmp_info_default("device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK | SU_FLAG_SEMI_STATIC, NULL), + + /* Device Identification from vendor MIB */ + snmp_info_default("device.mfr", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".2.1.1.0", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("device.model", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".2.4.2.1.4.1", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("device.serial", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".2.4.2.1.7.1", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("ups.firmware", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".2.4.2.1.5.1", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + + /* Extended Identification */ + snmp_info_default("device.type", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".3.9.20.1.20.1.2.1.4553", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("ups.mfr", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".3.9.20.1.20.1.2.1.4333", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("ups.model", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".3.9.20.1.20.1.2.1.4240", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + + /* UPS Measurements & Topology (High-precision) */ + snmp_info_default("ups.load", 0, 1.0, VERTIV_VAL_OID ".5861", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("ups.temperature", 0, 1.0, VERTIV_BASEOID ".3.9.30.1.10.1.2.1.4291", NULL, SU_FLAG_NEGINVALID, NULL), + snmp_info_default("ups.type", ST_FLAG_STRING, 1.0, VERTIV_BASEOID ".3.9.20.1.20.1.2.1.6199", NULL, SU_FLAG_OK | SU_FLAG_STATIC, NULL), + + /* Battery Data */ + snmp_info_default("battery.charge", 0, 1.0, VERTIV_VAL_OID ".4153", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + /* Multiplier 60.0 converts UPS minutes to NUT seconds */ + snmp_info_default("battery.runtime", 0, 60.0, VERTIV_VAL_OID ".4150", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("battery.voltage", 0, 1.0, VERTIV_VAL_OID ".4148", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("battery.voltage.nominal", 0, 1.0, VERTIV_VAL_OID ".6189", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + + /* Power Quality - Scaled (0.1) for high precision decimal values (tenths of Volts/Amps/Hz) */ + snmp_info_default("input.voltage", 0, 0.1, VERTIV_VAL_OID ".4096", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("input.current", 0, 0.1, VERTIV_VAL_OID ".4113", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("input.frequency", 0, 0.1, VERTIV_VAL_OID ".4105", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("input.voltage.nominal", 0, 1.0, VERTIV_VAL_OID ".4102", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("input.current.nominal", 0, 1.0, VERTIV_VAL_OID ".4104", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("input.frequency.nominal", 0, 1.0, VERTIV_VAL_OID ".4103", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("output.voltage", 0, 0.1, VERTIV_VAL_OID ".4385", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("output.current", 0, 0.1, VERTIV_VAL_OID ".4204", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("output.frequency", 0, 0.1, VERTIV_VAL_OID ".4207", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("output.power", 0, 1.0, VERTIV_VAL_OID ".4208", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("output.power.apparent", 0, 1.0, VERTIV_VAL_OID ".4209", "", SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL), + snmp_info_default("output.voltage.nominal", 0, 1.0, VERTIV_VAL_OID ".4260", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + snmp_info_default("output.power.nominal", 0, 1.0, VERTIV_VAL_OID ".4264", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL), + + /* UPS Status */ + snmp_info_default("ups.status", ST_FLAG_STRING, SU_INFOSIZE, VERTIV_VAL_OID ".4872", "", SU_STATUS_PWR | SU_FLAG_OK, vertiv_power_source_info), + + /* Beeper status and commands */ + snmp_info_default("ups.beeper.status", ST_FLAG_STRING, SU_INFOSIZE, VERTIV_BEEPER_OID, "", SU_FLAG_UNIQUE, vertiv_beeper_status_info), + + snmp_info_default("beeper.disable", 0, 1, VERTIV_BEEPER_OID, "2", SU_TYPE_CMD, NULL), + snmp_info_default("beeper.enable", 0, 1, VERTIV_BEEPER_OID, "1", SU_TYPE_CMD, NULL), + +#ifdef VERTIV_WITH_IETF_BEEPER_FALLBACK + /* IETF MIB fallback */ + snmp_info_default("ups.beeper.status", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.2.1.33.1.9.8.0", "", SU_FLAG_UNIQUE, ietf_beeper_status_info), +#if 0 + snmp_info_default("beeper.disable", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "1", SU_TYPE_CMD, NULL), + snmp_info_default("beeper.enable", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "2", SU_TYPE_CMD, NULL), +#endif + snmp_info_default("beeper.mute", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "3", SU_TYPE_CMD, NULL), +#endif /* VERTIV_WITH_IETF_BEEPER_FALLBACK */ + + /* Shutdown / Restart Control + * NOTE: Other sources suggest + * "ups.delay.shutdown" => VERTIV_BASEOID ".3.3.5.1.0" + * "ups.delay.start" => VERTIV_BASEOID ".3.3.5.2.0" + */ + snmp_info_default("ups.delay.shutdown", ST_FLAG_RW, 1.0, VERTIV_VAL_OID ".5814", "", SU_TYPE_TIME | SU_FLAG_OK, NULL), + snmp_info_default("ups.delay.start", ST_FLAG_RW, 1.0, VERTIV_VAL_OID ".5816", "", SU_TYPE_TIME | SU_FLAG_OK, NULL), + + /* end of structure. */ + snmp_info_sentinel +}; + +static alarms_info_t vertiv_alarms[] = { + { VERTIV_ALM_OID ".4168", "OB", "Battery Discharging" }, + { VERTIV_ALM_OID ".4162", "LB", "Battery Low" }, + { VERTIV_ALM_OID ".5806", "OVER", "Output Overload" }, + { VERTIV_ALM_OID ".6182", "RB", "Replace Battery" }, + { VERTIV_ALM_OID ".4233", "FAULT", "Inverter Failure" }, + { VERTIV_ALM_OID ".4310", "OT", "Over Temperature" }, + { VERTIV_ALM_OID ".4215", "OFF", "UPS Output Off" }, + { NULL, NULL, NULL } +}; + +mib2nut_info_t vertiv = { + "vertiv", + VERTIV_MIB_VERSION, + VERTIV_PWRSTATUS_OID,/* Optional Power Status OID */ + VERTIV_ID_OID, /* Model Name OID */ + vertiv_mib, + VERTIV_BASEOID, /* SysOID fingerprint */ + vertiv_alarms +}; diff --git a/drivers/vertiv-mib.h b/drivers/vertiv-mib.h new file mode 100644 index 0000000000..b48d293238 --- /dev/null +++ b/drivers/vertiv-mib.h @@ -0,0 +1,30 @@ +/* vertiv-psi5-mib.h - Driver for Vertiv Liebert PSI5 UPS + * + * Copyright (C) + * 2026 jawz101 + Gemini + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef VERTIV_PSI5_MIB_H +#define VERTIV_PSI5_MIB_H + +#include "main.h" +#include "snmp-ups.h" + +extern mib2nut_info_t vertiv; + +#endif /* VERTIV_PSI5_MIB_H */ diff --git a/drivers/ydn23.h b/drivers/ydn23.h index 5006bb5111..ec6ba02a59 100644 --- a/drivers/ydn23.h +++ b/drivers/ydn23.h @@ -60,6 +60,7 @@ #define YDN23_H_SEEN 1 #include "serial.h" +#include "nut_stdint.h" #ifndef htole16 # ifdef WORDS_BIGENDIAN @@ -238,7 +239,7 @@ static inline void ydn23_frame_init( { if (dlen > YDN23_FRAME_INFO_SIZE) { upslogx(LOG_WARNING, - "frame not big enough, required %d got %zu, truncated", + "frame not big enough, required %d got %" PRIuSIZE ", truncated", YDN23_FRAME_INFO_SIZE, dlen); dlen = YDN23_FRAME_INFO_SIZE; } @@ -280,8 +281,9 @@ static inline int ydn23_frame_send(TYPE_FD_SER fd, struct ydn23_frame *frame) } } - ret = ser_send_buf(fd, frame->CHKSUM, - ((char *) &frame->infolen) - frame->CHKSUM); + ret = ser_send_buf( + fd, frame->CHKSUM, + ((char *) &frame->infolen) - frame->CHKSUM); if (ret <= 0) { upslogx(LOG_WARNING, "ydn23_frame_send: %s", ret ? strerror(errno) : "timeout"); return ret; diff --git a/include/common.h b/include/common.h index 502c1eabdf..a83001b7e9 100644 --- a/include/common.h +++ b/include/common.h @@ -396,9 +396,12 @@ int str_contains_token(const char *string, const char *token); * checking for uniqueness and going to add a newly seen token. * If such callback returns 0, abort the addition of token and return -3. */ -int str_add_unique_token(char *tgt, size_t tgtsize, const char *token, - int (*callback_always)(char *, size_t, const char *), - int (*callback_unique)(char *, size_t, const char *) +int str_add_unique_token( + char *tgt, + size_t tgtsize, + const char *token, + int (*callback_always)(char *, size_t, const char *), + int (*callback_unique)(char *, size_t, const char *) ); /* Report maximum platform value for the pid_t */ @@ -443,6 +446,11 @@ int sendsignalfnaliases(const char *pidfn, const char * sig, const char **progna * caller should strdup() a copy to retain beyond the lifetime of "file" */ const char *xbasename(const char *file); +/* enable writing upslog_with_errno() and upslogx() type messages to + * the stdout instead of stderr, and end them with HTML
tag, + * to help troubleshoot NUT CGI programs specifically */ +void cgilogbit_set(void); + /* enable writing upslog_with_errno() and upslogx() type messages to the syslog */ void syslogbit_set(void); @@ -752,6 +760,12 @@ extern int optind; #define UPSLOG_STDERR_ON_FATAL 0x0004 #define UPSLOG_SYSLOG_ON_FATAL 0x0008 +/* Special cases, primarily for NUT CGI programs to dump logs + * in a way better usable when troubleshooting with a browser: + */ +#define UPSLOG_STDOUT 0x0010 +#define UPSLOG_CGI_BR 0x0020 + #ifndef HAVE_SETEUID # define seteuid(x) setresuid(-1,x,-1) /* Works for HP-UX 10.20 */ # define setegid(x) setresgid(-1,x,-1) /* Works for HP-UX 10.20 */ @@ -803,6 +817,9 @@ double difftimeval(struct timeval x, struct timeval y); double difftimespec(struct timespec x, struct timespec y); #endif +/* count the time elapsed since start in milliseconds */ +long elapsed_since_timeval(struct timeval *start); + #ifndef HAVE_USLEEP /* int __cdecl usleep(unsigned int useconds); */ /* Note: if we'd need to define an useconds_t for obscure systems, diff --git a/include/nut_stdint.h b/include/nut_stdint.h index 9d64a061b4..65b5b17e3d 100644 --- a/include/nut_stdint.h +++ b/include/nut_stdint.h @@ -57,7 +57,11 @@ #define SSIZE_MAX ((ssize_t)(-1LL)) #endif -/* Printing format for size_t and ssize_t */ +/* Printing format for size_t and ssize_t + * FIXME? Historically we essentially hard-coded it for MINGW builds + * but should we, now that we detect support for printf("%zu", size_t) + * in the configure script?.. + */ #ifndef PRIuSIZE # ifdef PRIsize # define PRIuSIZE PRIsize @@ -65,17 +69,53 @@ # if defined(__MINGW32__) || defined (WIN32) # define PRIuSIZE "llu" # else -# define PRIuSIZE "zu" +# if (defined HAVE_PRINTF_ZU) && HAVE_PRINTF_ZU +# define PRIuSIZE "zu" +# else +# if (SIZE_MAX - 0 == UINT_MAX - 0) +# define PRIuSIZE "u" +# else +# if (SIZE_MAX - 0 == ULONG_MAX - 0) +# define PRIuSIZE "lu" +# else +# if (SIZE_MAX - 0 == ULLONG_MAX - 0) +# define PRIuSIZE "llu" +# else +/* Code may fail on systems where this feature is lacking + * and not considered a format string part, but hopefully + * we do not get here */ +# define PRIuSIZE "zu" +# endif +# endif +# endif +# endif # endif # endif #endif #ifndef PRIxSIZE -# if defined(__MINGW32__) || defined (WIN32) -# define PRIxSIZE "llx" -# else +# if defined(__MINGW32__) || defined (WIN32) +# define PRIxSIZE "llx" +# else +# if (defined HAVE_PRINTF_ZU) && HAVE_PRINTF_ZU # define PRIxSIZE "zx" +# else +# if (SIZE_MAX - 0 == UINT_MAX - 0) +# define PRIxSIZE "x" +# else +# if (SIZE_MAX - 0 == ULONG_MAX - 0) +# define PRIxSIZE "lx" +# else +# if (SIZE_MAX - 0 == ULLONG_MAX - 0) +# define PRIxSIZE "llx" +# else +/* See warning comment above */ +# define PRIxSIZE "zx" +# endif +# endif +# endif # endif +# endif #endif /* Note: Windows headers are known to define at least "d" values, @@ -90,7 +130,24 @@ # if defined(__MINGW32__) || defined (WIN32) # define PRIiSIZE "lld" # else -# define PRIiSIZE "zd" +# if (defined HAVE_PRINTF_ZU) && HAVE_PRINTF_ZU +# define PRIiSIZE "zd" +# else +# if (SIZE_MAX - 0 == UINT_MAX - 0) +# define PRIiSIZE "d" +# else +# if (SIZE_MAX - 0 == ULONG_MAX - 0) +# define PRIiSIZE "ld" +# else +# if (SIZE_MAX - 0 == ULLONG_MAX - 0) +# define PRIiSIZE "lld" +# else +/* See warning comment above */ +# define PRIiSIZE "zd" +# endif +# endif +# endif +# endif # endif # define PRIdSIZE PRIiSIZE # endif diff --git a/m4/ax_realpath_lib.m4 b/m4/ax_realpath_lib.m4 index 8ed8775a48..f4e2b3abb5 100644 --- a/m4/ax_realpath_lib.m4 +++ b/m4/ax_realpath_lib.m4 @@ -75,6 +75,26 @@ AC_DEFUN([AX_REALPATH_LIB], ], [myLIBNAME_LD="-l$myLIBNAME"] dnl best-effort... ) + # Colon-separated search path for libraries specified + # in compiler/linker flags we have discovered; used by + # gcc at least in linker mode + myLIBRARY_PATH="" + for TOKEN in $CFLAGS $LDFLAGS $LIBS ; do + D="" + case "$TOKEN" in + -R*|-L*) D="`echo \"$TOKEN\" | sed 's,^-@<:@RL@:>@,,'`" ;; + -Wl,-R*) D="`echo \"$TOKEN\" | sed 's,^-Wl\,-R,,'`" ;; + -Wl,-rpath,*) D="`echo \"$TOKEN\" | sed 's,^-Wl\,-rpath\,,,'`" ;; + esac + if test -z "$D" || test ! -d "$D" ; then continue ; fi + case "${myLIBRARY_PATH}" in + "") myLIBRARY_PATH="$D" ;; + "$D"|*":$D"|*":$D:"*|"$D:"*) ;; + *) myLIBRARY_PATH="${myLIBRARY_PATH}:${D}" ;; + esac + done + unset D + AC_MSG_CHECKING([for real path to $1 (re-parsed as ${myLIBNAME} likely file name / ${myLIBNAME_LD} linker arg)]) myLIBPATH="" AS_CASE(["${target_os}"], @@ -112,7 +132,7 @@ AC_DEFUN([AX_REALPATH_LIB], "${MSYSTEM_PREFIX}/lib" \ "${MINGW_PREFIX}/bin" \ "${MINGW_PREFIX}/lib" \ - `${CC} --print-search-dirs 2>/dev/null | ${GREP} libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ + `LIBRARY_PATH="${myLIBRARY_PATH}" ${CC} --print-search-dirs 2>/dev/null | ${GREP} libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ ; do dnl NOTE: Here we check myLIBPATH detected above, dnl in fallback below we would retry with a myLIBNAME @@ -126,22 +146,15 @@ AC_DEFUN([AX_REALPATH_LIB], ) ]) ], [ dnl # POSIX/MacOS builds - { myLIBPATH="`${CC} --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${CC} $CFLAGS --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${CC} $CFLAGS $LDFLAGS $LIBS --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${CC} --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${CC} $CFLAGS --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${CC} $CFLAGS $LDFLAGS $LIBS --print-file-name=\"$myLIBNAME\"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || myLIBPATH="" ] ) - AS_IF([test -z "${myLIBPATH}"], [ - for TOKEN in $CFLAGS $LDFLAGS $LIBS ; do - D="" - case "$TOKEN" in - -R*|-L*) D="`echo \"$TOKEN\" | sed 's,^-[RL],,'`" ;; - -Wl,-R*) D="`echo \"$TOKEN\" | sed 's,^-Wl\,-R,,'`" ;; - -Wl,-rpath,*) D="`echo \"$TOKEN\" | sed 's,^-Wl\,-rpath\,,,'`" ;; - esac - if test -z "$D" || test ! -d "$D" ; then continue ; fi + AS_IF([test -z "${myLIBPATH}" -a -n "${myLIBRARY_PATH}"], [ + for D in `echo "${myLIBRARY_PATH}" | tr ':' ' '` ; do if test -s "$D/${myLIBNAME}" 2>/dev/null ; then myLIBPATH="$D/${myLIBNAME}" break @@ -154,7 +167,7 @@ AC_DEFUN([AX_REALPATH_LIB], for D in \ "/usr/${target}/bin" \ "/usr/${target}/lib" \ - `${CC} --print-search-dirs 2>/dev/null | ${GREP} libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ + `LIBRARY_PATH="${myLIBRARY_PATH}" ${CC} --print-search-dirs 2>/dev/null | ${GREP} libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ ; do if test -s "$D/${myLIBNAME}" 2>/dev/null ; then myLIBPATH="$D/${myLIBNAME}" @@ -164,29 +177,57 @@ AC_DEFUN([AX_REALPATH_LIB], unset D ]) - AS_IF([test -z "${myLIBPATH}" && test x"${LD}" != x -a x"${LD}" != xfalse], [ + AS_IF([test -z "${myLIBPATH}" && test x"${LD}" != x -a x"${LD}" != xfalse && test -n "${myLIBNAME_LD}"], [ AS_CASE(["${target_os}"], [*darwin*], [ dnl Try MacOS-style LD as fallback; expecting strings like dnl ld: warning: /usr/local/lib/libneon.dylib, ignoring unexpected dylib file my_uname_m="`uname -m`" - { myLIBPATH="`${LD} -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${LD} $LDFLAGS -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${LD} $LDFLAGS $LIBS -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} $LDFLAGS -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} $LDFLAGS $LIBS -dynamic -r -arch \"${target_cpu}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || if test x"${target_cpu}" != x"${my_uname_m}" ; then - { myLIBPATH="`${LD} -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${LD} $LDFLAGS -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ - || { myLIBPATH="`${LD} $LDFLAGS $LIBS -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} $LDFLAGS -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ + || { myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} $LDFLAGS $LIBS -dynamic -r -arch \"${my_uname_m}\" -search_dylibs_first \"${myLIBNAME_LD}\" 2>&1 | ${GREP} -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || myLIBPATH="" else myLIBPATH="" fi rm -f a.out 2>/dev/null || true unset my_uname_m + ], [ + dnl Try our luck with any linker that would complain in + dnl a way that we recognize (e.g. listing some path name + dnl including the expected name as a base part of longer + dnl filename)? + myLDFLAGS="" + if test -n "${myLIBRARY_PATH}" ; then + myLDFLAGS="`echo -L\"${myLIBRARY_PATH}\" | sed 's/:/ -L/g'`" + fi + dnl NOTE: We should not get more than one hit here; + dnl but if we do -- it is probably safer to fail + dnl existence checks below and bail out... + myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${LD} -r $myLDFLAGS \"${myLIBNAME_LD}\" -o a.out 2>&1 | tr ' ' '\n' | ${EGREP} \"@<:@/\\@:>@${myLIBNAME}\"`" + if test -n "${myLIBPATH}" && test -s "${myLIBPATH}" ; then : ; else myLIBPATH="" ; fi + rm -f a.out + unset myLDFLAGS ] ) ]) + AS_IF([test -z "${myLIBPATH}" && test x"${CC}" != x -a x"${CC}" != xfalse && test -n "${myLIBNAME_LD}"], [ + dnl Like above, but try CC instead of LD + myLDFLAGS="" + if test -n "${myLIBRARY_PATH}" ; then + myLDFLAGS="`echo -L\"${myLIBRARY_PATH}\" | sed 's/:/ -L/g'`" + fi + myLIBPATH="`LIBRARY_PATH=\"${myLIBRARY_PATH}\" ${CC} -r $myLDFLAGS \"${myLIBNAME_LD}\" -o a.out 2>&1 | tr ' ' '\n' | ${EGREP} \"@<:@/\\@:>@${myLIBNAME}\"`" + if test -n "${myLIBPATH}" && test -s "${myLIBPATH}" ; then : ; else myLIBPATH="" ; fi + rm -f a.out + unset myLDFLAGS + ]) + AS_IF([test -n "${myLIBPATH}" && test -s "${myLIBPATH}"], [ AC_MSG_RESULT([initially '${myLIBPATH}']) @@ -213,6 +254,7 @@ AC_DEFUN([AX_REALPATH_LIB], myLIBPATH_REAL="${myLIBPATH}" AX_REALPATH([${myLIBPATH}], [myLIBPATH_REAL]) ]) + unset myLIBPATH_LDSCRIPT ],[ AC_MSG_RESULT([no, seems like a normal binary]) @@ -230,6 +272,12 @@ AC_DEFUN([AX_REALPATH_LIB], AC_MSG_RESULT(${myLIBPATH_REAL}) $2="${myLIBPATH_REAL}" + + unset myLIBRARY_PATH + unset myLIBPATH_REAL + unset myLIBPATH + unset myLIBNAME + unset myLIBNAME_LD ],[ AC_MSG_RESULT([not found]) $2="$3" diff --git a/m4/nut_check_libglib.m4 b/m4/nut_check_libglib.m4 new file mode 100644 index 0000000000..e1f348b336 --- /dev/null +++ b/m4/nut_check_libglib.m4 @@ -0,0 +1,249 @@ +dnl Check for LIBGLIB (used by nut-upower driver) and related LIBGIO (optionally +dnl used by nut-scanner) compiler and linker flags. +dnl On success, set nut_have_libglib="yes" and set LIBGLIB_CFLAGS and LIBGLIB_LIBS. +dnl On failure, set nut_have_libglib="no". +dnl Similarly for LIBGIO_FLAGS, LIBGIO_LIBS and nut_have_libgio. +dnl This macro can be run multiple times, but will do the checking only once. + +AC_DEFUN([NUT_CHECK_LIBGLIB], +[ +if test -z "${nut_have_libglib_seen}"; then + nut_have_libglib_seen=yes + AC_REQUIRE([NUT_CHECK_PKGCONFIG]) + + dnl save CFLAGS and LIBS + CFLAGS_ORIG="${CFLAGS}" + LIBS_ORIG="${LIBS}" + CFLAGS="" + LIBS="" + depCFLAGS="" + depCFLAGS_SOURCE="" + depLIBS="" + depLIBS_SOURCE="" + + AS_IF([test x"$have_PKG_CONFIG" = xyes], + [dnl See which version of the glib/gio library (if any) is installed + AC_MSG_CHECKING(for glib-2.0 version via pkg-config (2.26.0 minimum required)) + LIBGLIB_VERSION="`$PKG_CONFIG --silence-errors --modversion glib-2.0 2>/dev/null`" + if test "$?" != "0" -o -z "${LIBGLIB_VERSION}"; then + LIBGLIB_VERSION="none" + fi + AC_MSG_RESULT(${LIBGLIB_VERSION} found) + ], [AC_MSG_NOTICE([can not check glib-2.0 settings via pkg-config])] + ) + + AC_MSG_CHECKING(for glib-2.0 cflags) + NUT_ARG_WITH_LIBOPTS_INCLUDES([glib], [auto]) + AS_CASE([${nut_with_glib_includes}], + [auto], [AS_IF([test x"$have_PKG_CONFIG" = xyes], + [ { depCFLAGS="`$PKG_CONFIG --silence-errors --cflags glib-2.0 2>/dev/null`" \ + && depCFLAGS_SOURCE="pkg-config" ; } \ + || { depCFLAGS="-I/usr/local/include/glib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include" \ + && depCFLAGS_SOURCE="default" ; }], + [depCFLAGS="-I/usr/local/include/glib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include" + depCFLAGS_SOURCE="default"] + )], + [depCFLAGS="${nut_with_glib_includes}" + depCFLAGS_SOURCE="confarg"] + ) + AC_MSG_RESULT([${depCFLAGS} (source: ${depCFLAGS_SOURCE})]) + + AC_MSG_CHECKING(for glib-2.0 ldflags) + NUT_ARG_WITH_LIBOPTS_LIBS([glib], [auto]) + AS_CASE([${nut_with_glib_libs}], + [auto], [AS_IF([test x"$have_PKG_CONFIG" = xyes], + [ { depLIBS="`$PKG_CONFIG --silence-errors --libs glib-2.0 2>/dev/null`" \ + && depLIBS_SOURCE="pkg-config" ; } \ + || { depLIBS="-lgobject-2.0 -lglib-2.0" \ + && depLIBS_SOURCE="default" ; }], + [depLIBS="-lgobject-2.0 -lglib-2.0" + depLIBS_SOURCE="default"] + )], + [depLIBS="${nut_with_glib_libs}" + depLIBS_SOURCE="confarg"] + ) + AC_MSG_RESULT([${depLIBS} (source: ${depLIBS_SOURCE})]) + + dnl check if glib-2.0 is usable + CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" + LIBS="${LIBS_ORIG} ${depLIBS}" + AC_CHECK_HEADERS(glib.h, [nut_have_libglib=yes], [nut_have_libglib=no], [AC_INCLUDES_DEFAULT]) + + if test "${nut_have_libglib}" = "yes"; then + dnl GLib headers seem incorrect and offensive to many compilers + dnl (starting names with underscores and capital characters, + dnl varying support for attributes, method pointer mismatches). + dnl There is nothing NUT can do about it, except telling the + dnl compiler that we take these headers from the system as they + dnl are, so strict checks should not apply to them. + dnl On newer releases (2025+) the headers and CLANG seem to work + dnl together out of the box, but during the decade before this is + dnl troublesome. + AS_IF([test "${CLANGCC}" = "yes" || test "${GCC}" = "yes"], [ + myGLIB_CFLAGS="" + for TOKEN in ${depCFLAGS} ; do + AS_CASE(["${TOKEN}"], + [-I/*], [ + _IDIR="`echo \"${TOKEN}\" | sed 's/^-I//'`" + AS_IF([echo " ${depCFLAGS}" | ${EGREP} " -isystem *${_IDIR}" >/dev/null], + [myGLIB_CFLAGS="${myGLIB_CFLAGS} ${TOKEN}"], + [myGLIB_CFLAGS="${myGLIB_CFLAGS} -isystem ${_IDIR} ${TOKEN}"] + )], + [myGLIB_CFLAGS="${myGLIB_CFLAGS} ${TOKEN}"] + ) + done + unset TOKEN + unset _IDIR + myGLIB_CFLAGS="`echo \"${myGLIB_CFLAGS}\" | sed 's/^ *//'`" + + AS_IF([test x"${depCFLAGS}" != x -a x"${depCFLAGS}" != x"${myGLIB_CFLAGS}"], [ + AC_MSG_NOTICE([Patched libglib CFLAGS to declare -isystem]) + AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ + AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) old: ${depCFLAGS}]) + AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) new: ${myGLIB_CFLAGS}]) + ]) + depCFLAGS="${myGLIB_CFLAGS}" + ]) + unset myGLIB_CFLAGS + ]) + + LIBGLIB_CFLAGS="${depCFLAGS}" + LIBGLIB_LIBS="${depLIBS}" + + dnl Help ltdl if we can (nut-scanner etc.) + for TOKEN in $depLIBS ; do + AS_CASE(["${TOKEN}"], + [-l*glib*], [ + AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBGLIB], []) + AS_IF([test -n "${SOPATH_LIBGLIB}" && test -s "${SOPATH_LIBGLIB}"], [ + AC_DEFINE_UNQUOTED([SOPATH_LIBGLIB],["${SOPATH_LIBGLIB}"],[Path to dynamic library on build system]) + SOFILE_LIBGLIB="`basename \"$SOPATH_LIBGLIB\"`" + AC_DEFINE_UNQUOTED([SOFILE_LIBGLIB],["${SOFILE_LIBGLIB}"],[Base file name of dynamic library on build system]) + break + ]) + ] + ) + done + unset TOKEN + fi + + dnl /////////////////////////////////////// + dnl // Same for libgio // + dnl /////////////////////////////////////// + + AS_IF([test x"$have_PKG_CONFIG" = xyes], + [dnl See which version of the glib/gio library (if any) is installed + AC_MSG_CHECKING(for gio-2.0 version via pkg-config (2.26.0 minimum required)) + LIBGIO_VERSION="`$PKG_CONFIG --silence-errors --modversion gio-2.0 2>/dev/null`" + if test "$?" != "0" -o -z "${LIBGIO_VERSION}"; then + LIBGIO_VERSION="none" + fi + AC_MSG_RESULT(${LIBGIO_VERSION} found) + ], [AC_MSG_NOTICE([can not check gio-2.0 settings via pkg-config])] + ) + + AC_MSG_CHECKING(for gio-2.0 cflags) + NUT_ARG_WITH_LIBOPTS_INCLUDES([gio], [auto]) + AS_CASE([${nut_with_gio_includes}], + [auto], [AS_IF([test x"$have_PKG_CONFIG" = xyes], + [ { depCFLAGS="`$PKG_CONFIG --silence-errors --cflags gio-2.0 2>/dev/null`" \ + && depCFLAGS_SOURCE="pkg-config" ; } \ + || { depCFLAGS="-I/usr/local/include/glib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include" \ + && depCFLAGS_SOURCE="default" ; }], + [depCFLAGS="-I/usr/local/include/glib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include" + depCFLAGS_SOURCE="default"] + )], + [depCFLAGS="${nut_with_gio_includes}" + depCFLAGS_SOURCE="confarg"] + ) + AC_MSG_RESULT([${depCFLAGS} (source: ${depCFLAGS_SOURCE})]) + + AC_MSG_CHECKING(for gio-2.0 ldflags) + NUT_ARG_WITH_LIBOPTS_LIBS([gio], [auto]) + AS_CASE([${nut_with_gio_libs}], + [auto], [AS_IF([test x"$have_PKG_CONFIG" = xyes], + [ { depLIBS="`$PKG_CONFIG --silence-errors --libs gio-2.0 2>/dev/null`" \ + && depLIBS_SOURCE="pkg-config" ; } \ + || { depLIBS="-lgio-2.0 -lgobject-2.0 -lglib-2.0" \ + && depLIBS_SOURCE="default" ; }], + [depLIBS="-lgio-2.0 -lgobject-2.0 -lglib-2.0" + depLIBS_SOURCE="default"] + )], + [depLIBS="${nut_with_gio_libs}" + depLIBS_SOURCE="confarg"] + ) + AC_MSG_RESULT([${depLIBS} (source: ${depLIBS_SOURCE})]) + + dnl check if gio-2.0 is usable + CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" + LIBS="${LIBS_ORIG} ${depLIBS}" + AC_CHECK_HEADERS(gio/gio.h, [nut_have_libgio=yes], [nut_have_libgio=no], [AC_INCLUDES_DEFAULT]) + dnl AC_CHECK_FUNCS(g_bus_get_sync, [], [nut_have_libgio=no]) + + if test "${nut_have_libgio}" = "yes"; then + dnl GLib headers seem incorrect and offensive to many compilers + dnl (see details in big comment above). + AS_IF([test "${CLANGCC}" = "yes" || test "${GCC}" = "yes"], [ + myGIO_CFLAGS="" + for TOKEN in ${depCFLAGS} ; do + AS_CASE(["${TOKEN}"], + [-I/*], [ + _IDIR="`echo \"${TOKEN}\" | sed 's/^-I//'`" + AS_IF([echo " ${depCFLAGS}" | ${EGREP} " -isystem *${_IDIR}" >/dev/null], + [myGIO_CFLAGS="${myGIO_CFLAGS} ${TOKEN}"], + [myGIO_CFLAGS="${myGIO_CFLAGS} -isystem ${_IDIR} ${TOKEN}"] + )], + [myGIO_CFLAGS="${myGIO_CFLAGS} ${TOKEN}"] + ) + done + unset TOKEN + unset _IDIR + myGIO_CFLAGS="`echo \"${myGIO_CFLAGS}\" | sed 's/^ *//'`" + + AS_IF([test x"${depCFLAGS}" != x -a x"${depCFLAGS}" != x"${myGIO_CFLAGS}"], [ + AC_MSG_NOTICE([Patched libglib/libgio CFLAGS to declare -isystem]) + AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ + AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) old: ${depCFLAGS}]) + AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) new: ${myGIO_CFLAGS}]) + ]) + depCFLAGS="${myGIO_CFLAGS}" + ]) + unset myGIO_CFLAGS + ]) + + LIBGIO_CFLAGS="${depCFLAGS}" + LIBGIO_LIBS="${depLIBS}" + + dnl Help ltdl if we can (nut-scanner etc.) + for TOKEN in $depLIBS ; do + AS_CASE(["${TOKEN}"], + [-l*gio*], [ + AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBGIO], []) + AS_IF([test -n "${SOPATH_LIBGIO}" && test -s "${SOPATH_LIBGIO}"], [ + AC_DEFINE_UNQUOTED([SOPATH_LIBGIO],["${SOPATH_LIBGIO}"],[Path to dynamic library on build system]) + SOFILE_LIBGIO="`basename \"$SOPATH_LIBGIO\"`" + AC_DEFINE_UNQUOTED([SOFILE_LIBGIO],["${SOFILE_LIBGIO}"],[Base file name of dynamic library on build system]) + break + ]) + ] + ) + done + unset TOKEN + fi + + unset depCFLAGS + unset depLIBS + unset depCFLAGS_SOURCE + unset depLIBS_SOURCE + + dnl restore original CFLAGS and LIBS + CFLAGS="${CFLAGS_ORIG}" + LIBS="${LIBS_ORIG}" + + AC_SUBST([LIBGLIB_CFLAGS]) + AC_SUBST([LIBGLIB_LIBS]) + + AC_SUBST([LIBGIO_CFLAGS]) + AC_SUBST([LIBGIO_LIBS]) +fi +]) diff --git a/scripts/DMF/Makefile.am b/scripts/DMF/Makefile.am index 5ef48d9a98..4c1f7cc992 100644 --- a/scripts/DMF/Makefile.am +++ b/scripts/DMF/Makefile.am @@ -54,7 +54,7 @@ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonstr.la \ $(top_builddir)/drivers/dstate.o \ $(top_builddir)/common/libnutwincompat.la \ -$(top_builddir)/common/libnutdmfsnmp.la: +$(top_builddir)/common/libnutdmfsnmp.la: @dotMAKE@ +cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # A way to to relative symlinks, or hardlinks, or copies... depends on OS. @@ -100,7 +100,7 @@ include $(LEGACY_MIBFILES_LIST) EXTRA_DIST += legacy-mibfiles-list.mk.in # Support development experiments for lookup with functions -testdata-fun/eaton-pdu-marlin-mib_WITH_SNMP_LKP_FUN_DUMMY.dmf: +testdata-fun/eaton-pdu-marlin-mib_WITH_SNMP_LKP_FUN_DUMMY.dmf: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_top_builddir)/scripts/DMF/testdata-fun/eaton-pdu-marlin-mib_WITH_SNMP_LKP_FUN_DUMMY.dmf #$(abs_top_builddir)/scripts/DMF/testdata-fun/eaton-pdu-marlin-mib_WITH_SNMP_LKP_FUN_DUMMY.dmf: DEBUG=yes @@ -375,7 +375,7 @@ DMFLNK_CMD = ( \ .PHONY: $(DMFSNMP_SUBDIR)/.uptodate $(DMFNUTSCAN_SUBDIR)/.uptodate $(DMFSNMP_SUBDIR)/.validated $(DMFNUTSCAN_SUBDIR)/.validated \ $(DMFSNMP_RES_SUBDIR)/.uptodate $(DMFNUTSCAN_RES_SUBDIR)/.uptodate $(DMFSNMP_RES_SUBDIR)/.validated $(DMFNUTSCAN_RES_SUBDIR)/.validated -$(DMFSNMP_RES_SUBDIR)/.uptodate: +$(DMFSNMP_RES_SUBDIR)/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFSNMP_RES_SUBDIR)/.uptodate $(abs_builddir)/$(DMFSNMP_RES_SUBDIR)/.uptodate: $(dmfsnmpres_DMFS) @@ -401,7 +401,7 @@ $(abs_builddir)/$(DMFSNMP_RES_SUBDIR)/.uptodate: $(dmfsnmpres_DMFS) fi touch '$@' -$(DMFSNMP_SUBDIR)/.uptodate: +$(DMFSNMP_SUBDIR)/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFSNMP_SUBDIR)/.uptodate $(abs_builddir)/$(DMFSNMP_SUBDIR)/.uptodate: $(LEGACY_NUT_DMF_SYMLINKS) @@ -416,7 +416,7 @@ $(abs_builddir)/$(DMFSNMP_SUBDIR)/.uptodate: $(LEGACY_NUT_DMF_SYMLINKS) # so we add them in desired order explicitly... DMFNUTSCAN_DEPS = $(abs_builddir)/$(DMFSNMP_RES_SUBDIR)/.uptodate EXTRA_DIST += $(DMFNUTSCAN_RES_SUBDIR)/dmfnutscan-snmp.dmf -$(DMFNUTSCAN_RES_SUBDIR)/dmfnutscan-snmp.dmf: +$(DMFNUTSCAN_RES_SUBDIR)/dmfnutscan-snmp.dmf: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_top_builddir)/scripts/DMF/$(DMFNUTSCAN_RES_SUBDIR)/dmfnutscan-snmp.dmf if WITH_REGENERATE_DMF_NUTSCAN @@ -465,7 +465,7 @@ $(DMFNUTSCAN_SYMLINK): $(abs_top_builddir)/scripts/DMF/$(DMFNUTSCAN_RES_SUBDIR)/ $(INSTALL_NUT_DMFNUTSCAN_SYMLINK): $(INSTALL_NUT_DMFNUTSCAN_FILE) @DMFFILE="$(INSTALL_NUT_DMFNUTSCAN_FILE)"; DMFLINK='$@'; $(DMFLNK_CMD) -$(DMFNUTSCAN_RES_SUBDIR)/.uptodate: +$(DMFNUTSCAN_RES_SUBDIR)/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFNUTSCAN_RES_SUBDIR)/.uptodate $(abs_builddir)/$(DMFNUTSCAN_RES_SUBDIR)/.uptodate: $(abs_top_builddir)/scripts/DMF/$(DMFNUTSCAN_RES_SUBDIR)/dmfnutscan-snmp.dmf @@ -473,7 +473,7 @@ $(abs_builddir)/$(DMFNUTSCAN_RES_SUBDIR)/.uptodate: $(abs_top_builddir)/scripts/ @test -d "$(@D)" -a -w "$(@D)" || $(MKDIR_P) "$(@D)" touch '$@' -$(DMFNUTSCAN_SUBDIR)/.uptodate: +$(DMFNUTSCAN_SUBDIR)/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFNUTSCAN_SUBDIR)/.uptodate $(abs_builddir)/$(DMFNUTSCAN_SUBDIR)/.uptodate: $(DMFNUTSCAN_SYMLINK) @@ -483,16 +483,16 @@ $(abs_builddir)/$(DMFNUTSCAN_SUBDIR)/.uptodate: $(DMFNUTSCAN_SYMLINK) # Validation requires xmllint, which we have if we succeed with asciidoc usage # TODO: Maybe per-DMF *.dmf.validated files would be better? -$(DMFSNMP_RES_SUBDIR)/.validated: +$(DMFSNMP_RES_SUBDIR)/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFSNMP_RES_SUBDIR)/.validated -$(DMFSNMP_SUBDIR)/.validated: +$(DMFSNMP_SUBDIR)/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFSNMP_SUBDIR)/.validated -$(DMFNUTSCAN_RES_SUBDIR)/.validated: +$(DMFNUTSCAN_RES_SUBDIR)/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFNUTSCAN_RES_SUBDIR)/.validated -$(DMFNUTSCAN_SUBDIR)/.validated: +$(DMFNUTSCAN_SUBDIR)/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/$(DMFNUTSCAN_SUBDIR)/.validated # The DMFLINT_XSD and DMFLINT_OPTION are fed by caller @@ -646,7 +646,7 @@ endif WITH_DMF #else CLEANFILES += dmf-reindex$(EXEEXT) DMF_REINDEX = $(abs_top_builddir)/tools/nut-scanner/nut-scanner-reindex-dmfsnmp -dmf-reindex: +dmf-reindex: @dotMAKE@ +cd $(abs_top_builddir)/tools/nut-scanner/ && $(MAKE) $(AM_MAKEFLAGS) nut-scanner-reindex-dmfsnmp $(LN_S_R) $(abs_top_builddir)/tools/nut-scanner/nut-scanner-reindex-dmfsnmp dmf-reindex #endif @@ -713,17 +713,17 @@ if WITH_LIBXML2 dmf_fun_test_CFLAGS += $(LIBXML2_CFLAGS) endif WITH_LIBXML2 -testdata-lua/.validated: +testdata-lua/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/testdata-lua/.validated -testdata-fun/.validated: +testdata-fun/.validated: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/testdata-fun/.validated LUA_EXAMPLE_DMFS = $(abs_srcdir)/testdata-lua/lua-eaton-mib.dmf $(abs_srcdir)/testdata-lua/lua-mge-mib.dmf # LUA_EXAMPLE_DMFS += $(abs_srcdir)/testdata-lua/lua-example-mib.dmf FUN_EXAMPLE_DMFS = $(abs_srcdir)/testdata-fun/eaton-pdu-marlin-mib_WITH_SNMP_LKP_FUN_DUMMY.dmf -testdata-lua/.uptodate: +testdata-lua/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/testdata-lua/.uptodate $(abs_builddir)/testdata-lua/.uptodate: $(LUA_EXAMPLE_DMFS) @@ -731,7 +731,7 @@ $(abs_builddir)/testdata-lua/.uptodate: $(LUA_EXAMPLE_DMFS) @test -d "$(@D)" -a -w "$(@D)" || $(MKDIR_P) "$(@D)" touch '$@' -testdata-fun/.uptodate: +testdata-fun/.uptodate: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) $(abs_builddir)/testdata-fun/.uptodate $(abs_builddir)/testdata-fun/.uptodate: $(FUN_EXAMPLE_DMFS) @@ -821,13 +821,13 @@ EXTRA_DIST += $(SPELLCHECK_SRC) # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES += *-spellchecked diff --git a/scripts/DMF/dmfnutscan/dmfnutscan-snmp.dmf b/scripts/DMF/dmfnutscan/dmfnutscan-snmp.dmf index 9ad98f44b0..7094d16ea4 100644 --- a/scripts/DMF/dmfnutscan/dmfnutscan-snmp.dmf +++ b/scripts/DMF/dmfnutscan/dmfnutscan-snmp.dmf @@ -24,6 +24,7 @@ + diff --git a/scripts/DMF/dmfsnmp/vertiv-mib.dmf b/scripts/DMF/dmfsnmp/vertiv-mib.dmf new file mode 100644 index 0000000000..eded3d65f9 --- /dev/null +++ b/scripts/DMF/dmfsnmp/vertiv-mib.dmf @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/Makefile.am b/scripts/Makefile.am index b4d4e488e7..b267543686 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -44,20 +44,20 @@ SPELLCHECK_SRC = README.adoc RedHat/README.adoc usb_resetter/README.adoc valgrin # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked RedHat/*-spellchecked usb_resetter/*-spellchecked diff --git a/scripts/Solaris/Makefile.am b/scripts/Solaris/Makefile.am index e789c4b4ec..01c69ad864 100644 --- a/scripts/Solaris/Makefile.am +++ b/scripts/Solaris/Makefile.am @@ -119,20 +119,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/scripts/Windows/Installer/NUT-Installer.xml.in b/scripts/Windows/Installer/NUT-Installer.xml.in index 7348d6ac31..04beb98298 100644 --- a/scripts/Windows/Installer/NUT-Installer.xml.in +++ b/scripts/Windows/Installer/NUT-Installer.xml.in @@ -2075,4 +2075,5 @@ Public License instead of this License. LIBUSBINSTALL=1 - \ No newline at end of file + + diff --git a/scripts/Windows/Makefile.am b/scripts/Windows/Makefile.am index 3eff7e6783..263a684876 100644 --- a/scripts/Windows/Makefile.am +++ b/scripts/Windows/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include $(top_builddir)/include/nut_version.h \ $(top_builddir)/common/libcommonversion.la \ -$(top_builddir)/common/libcommon.la: FORCE +$(top_builddir)/common/libcommon.la: FORCE @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion.la: $(top_builddir)/include/nut_version.h @@ -12,7 +12,7 @@ $(top_builddir)/common/libcommonversion.la: $(top_builddir)/include/nut_version. if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: FORCE +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: FORCE @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h @@ -105,20 +105,20 @@ SPELLCHECK_SRC = README.adoc DriverInstaller/README.adoc Installer/README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp diff --git a/scripts/Windows/build-mingw-nut.sh b/scripts/Windows/build-mingw-nut.sh index b5bbb55443..aca64aa86b 100755 --- a/scripts/Windows/build-mingw-nut.sh +++ b/scripts/Windows/build-mingw-nut.sh @@ -4,6 +4,20 @@ # # script to cross compile NUT for Windows from Linux using MinGW-w64 # http://mingw-w64.sourceforge.net/ +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #set -x diff --git a/scripts/Windows/wininit.c b/scripts/Windows/wininit.c index 864c7ce05f..a1fc5577a1 100644 --- a/scripts/Windows/wininit.c +++ b/scripts/Windows/wininit.c @@ -38,6 +38,7 @@ typedef struct conn_s { struct conn_s *next; } conn_t; +static int exit_flag = 0; static DWORD upsd_pid = 0; static DWORD upsmon_pid = 0; static DWORD upsdrvctl_pid = 0; @@ -581,6 +582,54 @@ static void ReportSvcStatus( SetServiceStatus(SvcStatusHandle, &SvcStatus); } +/* For `nut.exe -N` runs + * https://learn.microsoft.com/en-us/windows/console/registering-a-control-handler-function + */ +static BOOL WINAPI ConsoleCtrlHandler(DWORD Ctrl) +{ + switch(Ctrl) + { + case CTRL_C_EVENT: + print_event(LOG_INFO, "Ctrl+C received on console"); + exit_flag = 1; /* Break SvcMain() infinite loop */ + if (upsmon_pid) { + print_event(LOG_INFO, "Stopping upsmon"); + stop_upsmon(); + } + if (upsd_pid) { + print_event(LOG_INFO, "Stopping upsd"); + stop_upsd(); + } + if (upsdrvctl_pid) { + print_event(LOG_INFO, "Stopping drivers"); + stop_drivers(); + } + exit_flag = 2; /* Allow to finish SvcMain() infinite loop and proceed to exit() */ + /* confirm that the user wants to exit */ + return TRUE; + + case CTRL_CLOSE_EVENT: + print_event(LOG_INFO, "Close event received on console, currently ignored"); + return FALSE; + + case CTRL_BREAK_EVENT: + print_event(LOG_INFO, "Ctrl+Break event received on console, currently ignored"); + return FALSE; + + /* TOTHINK: Do we in fact want these two handled specially? */ + case CTRL_LOGOFF_EVENT: + print_event(LOG_INFO, "Logoff event received on console, currently ignored"); + return FALSE; + + case CTRL_SHUTDOWN_EVENT: + print_event(LOG_INFO, "Shutdown event received on console, currently ignored"); + return FALSE; + + default: + return FALSE; + } +} + static void WINAPI SvcCtrlHandler(DWORD Ctrl) { switch(Ctrl) @@ -659,7 +708,7 @@ static void close_all(void) static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) { DWORD ret; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; /* 64 per current WinAPI sheaders */ + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; /* 64 per current WinAPI headers */ size_t maxhandle = 0; pipe_conn_t *conn; DWORD priority; @@ -697,7 +746,7 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) SvcReady(); } - while (1) { + while (!exit_flag) { maxhandle = 0; memset(&handles, 0, sizeof(handles)); @@ -766,6 +815,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) } } + /* Do not check on daemons nor revive them in vain if we are exiting */ + if (exit_flag) + break; + /* Check on each daemon: Was it supposed to run? Does it still? */ if (upsdrvctl_pid) { DWORD status = 0; @@ -785,6 +838,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) } } + /* Do not check on daemons nor revive them in vain if we are exiting */ + if (exit_flag) + break; + if (upsd_pid) { DWORD status = 0; BOOL res = FALSE; @@ -803,6 +860,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) } } + /* Do not check on daemons nor revive them in vain if we are exiting */ + if (exit_flag) + break; + if (upsmon_pid) { DWORD status = 0; BOOL res = FALSE; @@ -821,6 +882,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) } } } + + while (exit_flag < 2) { + Sleep(1000); + } } static void help(const char *arg_progname) @@ -1020,6 +1085,10 @@ int main(int argc, char **argv) } } else { + if (!SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE)) { + upslog_with_errno(LOG_ERR, "SetConsoleCtrlHandler failed, may ignore Ctrl+C"); + } + SvcMain(argc, argv); } diff --git a/scripts/augeas/gen-nutupsconf-aug.py.in b/scripts/augeas/gen-nutupsconf-aug.py.in index 07374ac940..5aa3c1c4e8 100755 --- a/scripts/augeas/gen-nutupsconf-aug.py.in +++ b/scripts/augeas/gen-nutupsconf-aug.py.in @@ -1,7 +1,7 @@ #!@PYTHON_DEFAULT@ # Copyright (C) # 2010 - Arnaud Quette -# 2020 - 2024 Jim Klimov +# 2020 - 2026 Jim Klimov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,9 +23,41 @@ from __future__ import print_function import sys +import os import re import glob -import codecs + +HAVE_WARNINGS = False +try: + import warnings + warnings.filterwarnings("error") + HAVE_WARNINGS = True +except Exception as x: + # sys.stderr.write("WARNING: failed to import warnings or configure them: %s" % str(x)) + pass + +try: + # NOTE: Deprecated as of python3.14 + import codecs + HAVE_CODECS = True + fd = None + try: + # Open self to test that it works + fd = codecs.open(os.path.abspath(__file__), mode="r", encoding='utf-8') + USE_CODECS = True + # sys.stderr.write("INFO: import codecs went well, and codecs.open() did not raise exceptions\n") + except DeprecationWarning as x: + USE_CODECS = False + # sys.stderr.write("WARNING: import codecs went well, but codecs.open() failed: %s\n" % str(x)) + if fd is not None: + fd.close() +except Exception as x: + # sys.stderr.write("WARNING: import codecs failed: %s\n" % str(x)) + HAVE_CODECS = False + USE_CODECS = False + +if HAVE_WARNINGS: + warnings.resetwarnings() # Return a sorted list of unique entries, based on the input 'list' def sortUnique(list): @@ -80,7 +112,10 @@ if __name__ == '__main__': for filename in glob.glob('../../drivers/*.c'): # 1.2/ Exclude main.c, which defines addvar() and skel.c (example driver) if filename not in Exceptionlist: - fd = codecs.open(filename, encoding='utf-8') + if USE_CODECS: + fd = codecs.open(filename, encoding='utf-8') + else: + fd = open(filename, encoding='utf-8') # 1.3/ Grep for the "addvar(..." pattern matchResults = grep (r'.*addvar[\ ]*\(.*(VAR_FLAG|VAR_VALUE)*,.*', fd) @@ -95,7 +130,10 @@ if __name__ == '__main__': # Let's grep in .ch related files if (row[1].find('"') == -1): for defFilename in glob.glob(filename.replace('.c', '.[ch]')): - defFd = codecs.open(defFilename, encoding='utf-8') + if USE_CODECS: + defFd = codecs.open(defFilename, encoding='utf-8') + else: + defFd = open(defFilename, encoding='utf-8') matchString = '^#define.*' + row[1].replace('"', '').lstrip() + '.*' matchResult = grep (matchString, defFd) for varDefine in matchResult: @@ -103,9 +141,11 @@ if __name__ == '__main__': defRow = re.findall(r'"([^"]*)",?', varDefine) if (len(defRow) == 1): variableNames.append(defRow[0]) + defFd.close() else: # Remove quotes variableNames.append(row[1].replace('"', '').lstrip()) + fd.close() # Filter multiply defined variables variableNames = sortUnique(variableNames) @@ -115,12 +155,20 @@ if __name__ == '__main__': specificVars += " | \"%s\"\n" %(name) # 2/ Load the template lens - tplFd = codecs.open(dirPrefix + templateFilename, encoding='utf-8') + if USE_CODECS: + tplFd = codecs.open(dirPrefix + templateFilename, encoding='utf-8') + else: + tplFd = open(dirPrefix + templateFilename, encoding='utf-8') # 2.1/ Search for the pattern to replace outputText = tplFd.read() + tplFd.close() outputText = outputText.replace('@SPECIFIC_DRV_VARS@', specificVars) # 3/ Output final lens - outFd = codecs.open(outputFilename, mode='w', encoding='utf-8') + if USE_CODECS: + outFd = codecs.open(outputFilename, mode='w', encoding='utf-8') + else: + outFd = open(outputFilename, mode='w', encoding='utf-8') outFd.write(outputText) + outFd.close() diff --git a/scripts/devd/Makefile.am b/scripts/devd/Makefile.am index b9d9401ad3..47c437c851 100644 --- a/scripts/devd/Makefile.am +++ b/scripts/devd/Makefile.am @@ -37,20 +37,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/scripts/external_apis/Makefile.am b/scripts/external_apis/Makefile.am index 1647190d28..c4b412a6de 100644 --- a/scripts/external_apis/Makefile.am +++ b/scripts/external_apis/Makefile.am @@ -30,20 +30,20 @@ endif ENABLE_EXTAPI_ENPHASE # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked enphase/*-spellchecked diff --git a/scripts/hotplug/Makefile.am b/scripts/hotplug/Makefile.am index 5fa7809f86..4a6490ec39 100644 --- a/scripts/hotplug/Makefile.am +++ b/scripts/hotplug/Makefile.am @@ -29,20 +29,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/scripts/installer/Makefile.am b/scripts/installer/Makefile.am index 134ba00ecd..2ce880e2d2 100644 --- a/scripts/installer/Makefile.am +++ b/scripts/installer/Makefile.am @@ -46,20 +46,20 @@ nut: # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked */*-spellchecked common_EN/license.txt diff --git a/scripts/obs/Makefile.am b/scripts/obs/Makefile.am index 3394091eb4..f4e86e6258 100644 --- a/scripts/obs/Makefile.am +++ b/scripts/obs/Makefile.am @@ -52,6 +52,8 @@ EXTRA_DIST += \ debian.nut-doc.doc-base.nut-packager-guide \ debian.nut-doc.doc-base.nut-user-manual \ debian.nut-doc.install \ + debian.nut-gpio.install \ + debian.nut-gpio.manpages \ debian.nut-ipmi.install \ debian.nut-ipmi.manpages \ debian.nut-linux-i2c.install \ @@ -74,6 +76,8 @@ EXTRA_DIST += \ debian.nut-snmp.docs \ debian.nut-snmp.install \ debian.nut-snmp.manpages \ + debian.nut-upower.install \ + debian.nut-upower.manpages \ debian.nut-xml.install \ debian.nut-xml.manpages \ debian.nut.README.Debian \ @@ -150,20 +154,20 @@ _preinstallimage: nut.spec nut.dsc Makefile # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/scripts/obs/_config b/scripts/obs/_config index 139af5ab1d..4d6a97fba5 100644 --- a/scripts/obs/_config +++ b/scripts/obs/_config @@ -4,6 +4,7 @@ # Unambiguous preference if "Requires: (A or B)" offered both hits: Prefer: libusbx-devel Prefer: libusb-1.0-dev +Prefer: libselinux-dev Prefer: neon-devel Prefer: util-linux diff --git a/scripts/obs/_service b/scripts/obs/_service index 81a37d0ecf..7c5c2b88bb 100644 --- a/scripts/obs/_service +++ b/scripts/obs/_service @@ -7,7 +7,21 @@ @PARENT_TAG@.@TAG_OFFSET@ - v(.*) + + v([^-]*)-*(.*) + \1\2 + + v?.?.? + .git nut diff --git a/scripts/obs/debian.cdbs-autotools.mk b/scripts/obs/debian.cdbs-autotools.mk new file mode 100644 index 0000000000..73f7be0d4b --- /dev/null +++ b/scripts/obs/debian.cdbs-autotools.mk @@ -0,0 +1,440 @@ +# In 2026, Debian obsoletes and removes CDBS and its scripts +# Stashing https://salsa.debian.org/debian/cdbs/-/blob/a110afb99997b94de6acb1e0758210cdfd8ec3dd/1/class/autotools.mk.in +# and neighbors + +# -*- mode: makefile; coding: utf-8 -*- +# Copyright © 2002,2003 Colin Walters +# Copyright © 2008-2010, 2014, 2016 Jonas Smedegaard +# Description: A class to configure and build GNU autoconf+automake packages +# +# 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 +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#PATH_RULES# + +ifndef _cdbs_class_autotools +_cdbs_class_autotools = 1 + +# BEGIN # include $(_cdbs_class_path)/autotools-files.mk$(_cdbs_makefile_suffix) + +ifndef _cdbs_class_autotools_files +_cdbs_class_autotools_files = 1 + +# BEGIN # include $(_cdbs_class_path)/autotools-vars.mk$(_cdbs_makefile_suffix) + +ifndef _cdbs_class_autotools_vars +_cdbs_class_autotools_vars = 1 + +# BEGIN # include $(_cdbs_class_path)/makefile.mk$(_cdbs_makefile_suffix) + +ifndef _cdbs_class_makefile +_cdbs_class_makefile = 1 + +# Included by caller # include $(_cdbs_rules_path)/buildcore.mk$(_cdbs_makefile_suffix) +# BEGIN # include $(_cdbs_class_path)/makefile-vars.mk$(_cdbs_makefile_suffix) + +ifndef _cdbs_class_makefile_vars +_cdbs_class_makefile_vars = 1 + +# BEGIN # include $(_cdbs_class_path)/langcore.mk$(_cdbs_makefile_suffix) + +ifndef _cdbs_class_langcore +_cdbs_class_langcore = 1 + +include $(_cdbs_rules_path)/buildvars.mk$(_cdbs_makefile_suffix) + +# Resolve our defaults +# GNU Make doesn't export current environment in $(shell ..) function. +# We need at least some of the DEB_* flags for dpkg-buildflags, so +# extract them from the defined variables. Sadly there seems to be no +# way to just get all exported variables. +# +# massage dpkg-buildflag output: +# * filter to include only lines matching expected format +# * transform prefix, e.g. "export LDFLAGS := ..." -> "LDFLAGS ?= ..." +$(shell \ + $(call cdbs_set_nondefaultvars,\ + $(foreach flag,$(shell dpkg-buildflags --list),\ + $(foreach op,SET STRIP APPEND PREPEND,\ + DEB_$(flag)_$(op) DEB_$(flag)_MAINT_$(op)))\ + DEB_BUILD_OPTIONS DEB_BUILD_MAINT_OPTIONS) \ + dpkg-buildflags --export=make \ + | perl -pe 's/^export\s+//; s/:=/?=/' \ + > debian/_cdbs_buildflags.mk ) +-include debian/_cdbs_buildflags.mk +$(shell rm -f debian/_cdbs_buildflags.mk) + +$(eval $(and $(cdbs_crossbuild),$(filter default,$(origin CC)),\ + CC := $(DEB_HOST_GNU_TYPE)-gcc)) +$(eval $(and $(cdbs_crossbuild),$(filter default,$(origin CXX)),\ + CXX := $(DEB_HOST_GNU_TYPE)-g++)) + +ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + DEB_PARALLEL_JOBS ?= $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) +endif + +endif + +# END # include $(_cdbs_class_path)/langcore.mk$(_cdbs_makefile_suffix) + +#DEB_MAKE_MAKEFILE = +DEB_MAKE_ENVVARS ?= $(if $(cdbs_crossbuild),\ + CC="$(CC)" CXX="$(CXX)" PKG_CONFIG="$(DEB_HOST_GNU_TYPE)-pkg-config") +DEB_MAKE_PARALLEL ?= $(and $(DEB_BUILD_PARALLEL),$(DEB_PARALLEL_JOBS),\ + -j$(DEB_PARALLEL_JOBS)) + +# Derived classes that supply the flags some other way (e.g., configure) +# should set this variable to empty. +DEB_MAKE_EXTRA_ARGS ?= \ + CFLAGS="$(or $(CFLAGS_$(cdbs_curpkg)),$(CFLAGS))" \ + CXXFLAGS="$(or $(CXXFLAGS_$(cdbs_curpkg)),$(CXXFLAGS))" \ + CPPFLAGS="$(or $(CPPFLAGS_$(cdbs_curpkg)),$(CPPFLAGS))" \ + LDFLAGS="$(or $(LDFLAGS_$(cdbs_curpkg)),$(LDFLAGS))" \ + $(DEB_MAKE_PARALLEL) + +DEB_MAKE_INVOKE ?= $(strip \ + $(DEB_MAKE_ENVVARS) $(MAKE) \ + $(if $(DEB_MAKE_MAKEFILE),\ + -f $(DEB_MAKE_MAKEFILE)) \ + -C $(or $(cdbs_make_curbuilddir),$(cdbs_curbuilddir)) \ + $(DEB_MAKE_EXTRA_ARGS)) + +#DEB_MAKE_BUILD_TARGET = + +# If your Makefile provides an "install" target, you need to give the requisite commands +# here to install it into the staging directory. For automake-using programs, this +# looks like: install DESTDIR=$(cdbs_make_curdestdir) +# (which expands to either DEB_DESTDIR_xxx or DEB_DESTDIR) +# If you're using automake though, you likely want to be including autotools.mk instead +# of this file. + +DEB_MAKE_CLEAN_TARGET ?= clean + +#DEB_MAKE_CHECK_TARGET = test + +# If DEB_MAKE_FLAVORS is set compilation is done once per flavor. +# NB! This must be declared _before_ including makefile.mk +#DEB_MAKE_FLAVORS = light normal enhanced + +# If building multiple flavors, skeleton strings are used for +# DEB_BUILDDIR and DEB_DESTDIR, with @FLAVOR@ expanding to actual +# flavor. +DEB_MAKE_BUILDDIRSKEL ?= $(cdbs_curbuilddir)/@FLAVOR@ +DEB_MAKE_DESTDIRSKEL ?= $(cdbs_curdestdir)/@FLAVOR@ + +endif + +# END # include $(_cdbs_class_path)/makefile-vars.mk$(_cdbs_makefile_suffix) + +cdbs_make_flavors = $(sort $(DEB_MAKE_FLAVORS)) +cdbs_make_builddir_check = $(if $(call cdbs_streq,$(DEB_BUILDDIR),$(DEB_SRCDIR)),\ + $(error DEB_MAKE_FLAVORS in use: \ + DEB_BUILDDIR must be different from DEB_SRCDIR$(comma) \ + and needs to be declared before including makefile.mk)) +cdbs_make_build_stamps = $(if $(cdbs_make_flavors),\ + $(cdbs_make_builddir_check)\ + $(patsubst %,debian/stamp-makefile-build/%,\ + $(cdbs_make_flavors)),\ + debian/stamp-makefile-build) +cdbs_make_install_stamps = $(if $(cdbs_make_flavors),\ + $(cdbs_make_builddir_check)\ + $(patsubst %,debian/stamp-makefile-install/%,\ + $(cdbs_make_flavors)),\ + debian/stamp-makefile-install) +cdbs_make_check_stamps = $(if $(cdbs_make_flavors),\ + $(cdbs_make_builddir_check)\ + $(patsubst %,debian/stamp-makefile-check/%,\ + $(cdbs_make_flavors)),\ + debian/stamp-makefile-check) +cdbs_make_clean_nonstamps = $(if $(cdbs_make_flavors),\ + $(patsubst %,makefile-clean/%,$(cdbs_make_flavors)),\ + makefile-clean) +cdbs_make_curflavor = $(strip $(if $(cdbs_make_flavors),\ + $(filter-out %/,$(subst /,/ ,$@)))) +cdbs_make_curbuilddir = $(strip $(if $(cdbs_make_flavors),\ + $(subst @FLAVOR@,$(cdbs_make_curflavor),$(or $(strip \ + $(DEB_MAKE_BUILDDIRSKEL_$(cdbs_make_curflavor))),$(strip \ + $(DEB_MAKE_BUILDDIRSKEL)))),\ + $(cdbs_curbuilddir))) +cdbs_make_curdestdir = $(strip $(if $(cdbs_make_flavors),\ + $(subst @FLAVOR@,$(cdbs_make_curflavor),$(or $(strip \ + $(DEB_MAKE_DESTDIRSKEL_$(cdbs_make_curflavor))),$(strip \ + $(DEB_MAKE_DESTDIRSKEL)))),\ + $(cdbs_curdestdir))) + +DEB_PHONY_RULES += makefile-clean $(cdbs_make_clean_nonstamps) + +pre-build:: + $(if $(cdbs_make_flavors),\ + mkdir -p \ + debian/stamp-makefile-build \ + debian/stamp-makefile-install) + $(and $(cdbs_make_flavors),$(DEB_MAKE_CHECK_TARGET),\ + mkdir -p debian/stamp-makefile-check) + +common-build-arch common-build-indep:: $(cdbs_make_build_stamps) +$(cdbs_make_build_stamps): + +$(DEB_MAKE_INVOKE) $(DEB_MAKE_BUILD_TARGET) + touch $@ + +cleanbuilddir:: makefile-clean +makefile-clean:: $(if $(cdbs_make_flavors),$(cdbs_make_clean_nonstamps)) + $(if $(cdbs_make_flavors),\ + -rmdir --ignore-fail-on-non-empty \ + debian/stamp-makefile-build \ + debian/stamp-makefile-install,\ + rm -f \ + debian/stamp-makefile-build \ + debian/stamp-makefile-install) + +$(cdbs_make_clean_nonstamps):: + $(if $(DEB_MAKE_CLEAN_TARGET),\ + +-$(DEB_MAKE_INVOKE) -k $(DEB_MAKE_CLEAN_TARGET),\ + $(call cdbs_warn,DEB_MAKE_CLEAN_TARGET unset$(comma) \ + not running clean)) + $(if $(cdbs_make_flavors),\ + rm -f \ + $(@:makefile-clean%=debian/stamp-makefile-build%) \ + $(@:makefile-clean%=debian/stamp-makefile-install%)) + +common-install-arch common-install-indep:: common-install-impl +common-install-impl:: $(cdbs_make_install_stamps) +$(cdbs_make_install_stamps):: + $(if $(DEB_MAKE_INSTALL_TARGET),\ + +$(DEB_MAKE_INVOKE) $(DEB_MAKE_INSTALL_TARGET),\ + $(call cdbs_warn,DEB_MAKE_INSTALL_TARGET unset$(comma) \ + skipping default makefile.mk common-install target)) + $(if $(DEB_MAKE_INSTALL_TARGET),\ + touch $@) + +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) +common-build-arch common-build-indep:: $(cdbs_make_check_stamps) +$(cdbs_make_check_stamps) : debian/stamp-makefile-check% : debian/stamp-makefile-build% + $(if $(DEB_MAKE_CHECK_TARGET),\ + +$(DEB_MAKE_INVOKE) $(DEB_MAKE_CHECK_TARGET),\ + $(call cdbs_warn,DEB_MAKE_CHECK_TARGET unset$(comma) \ + not running checks)) + $(if $(DEB_MAKE_CHECK_TARGET),\ + touch $@) + +makefile-clean:: + $(if $(DEB_MAKE_CHECK_TARGET),\ + $(if $(cdbs_make_flavors),\ + -rmdir --ignore-fail-on-non-empty \ + debian/stamp-makefile-check,\ + rm -f debian/stamp-makefile-check)) + +$(cdbs_make_clean_nonstamps):: + $(if $(cdbs_make_flavors),\ + rm -f $(@:makefile-clean%=debian/stamp-makefile-check%)) +endif + +endif + + +# END # include $(_cdbs_class_path)/makefile.mk$(_cdbs_makefile_suffix) + +DEB_MAKE_INSTALL_TARGET ?= install DESTDIR=$(cdbs_make_curdestdir) +# FIXME: Restructure to allow early override +DEB_MAKE_CLEAN_TARGET = distclean +#DEB_MAKE_CHECK_TARGET = check + +DEB_AC_AUX_DIR ?= $(DEB_SRCDIR) + +# Declare CC and CXX only if explicitly set in environment or makefile +# (i.e. skip if builtin make default would have been used) +# This is needed for proper cross-compilation - see bug#450483) +DEB_CONFIGURE_SCRIPT_ENV ?= \ + $(call cdbs_set_nondefaultvars,CC CXX) \ + CFLAGS="$(CFLAGS)" \ + CXXFLAGS="$(CXXFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" \ + LDFLAGS="$(LDFLAGS)" + +DEB_CONFIGURE_SCRIPT ?= $(CURDIR)/$(DEB_SRCDIR)/configure + +# Provide --host only if different from --build, to support cross- +# compiling with autotools 2.52+ without slowing down normal builds. +# Cross-compiling with autotools 2.13 is unsupported, as it needs +# other tweaks (more info at autotools-dev README.Debian) +DEB_CONFIGURE_CROSSBUILD_ARGS ?= \ + --build=$(DEB_BUILD_GNU_TYPE) \ + $(if $(cdbs_crossbuild),\ + --host=$(DEB_HOST_GNU_TYPE)) + +DEB_CONFIGURE_PREFIX ?=/usr +DEB_CONFIGURE_INCLUDEDIR ?= "\$${prefix}/include" +DEB_CONFIGURE_MANDIR ?= "\$${prefix}/share/man" +DEB_CONFIGURE_INFODIR ?= "\$${prefix}/share/info" +DEB_CONFIGURE_SYSCONFDIR ?= /etc +DEB_CONFIGURE_LOCALSTATEDIR ?= /var +DEB_CONFIGURE_LIBEXECDIR ?= "\$${prefix}/lib/$(DEB_SOURCE_PACKAGE)" +# --srcdir=. is required because otherwise configure wants to analyse +# $0 to see whether a VPATH build is needed. This tells it with +# absolute certainly that this is NOT a VPATH build. +DEB_CONFIGURE_PATH_ARGS ?= \ + --prefix=$(DEB_CONFIGURE_PREFIX) \ + --includedir=$(DEB_CONFIGURE_INCLUDEDIR) \ + --mandir=$(DEB_CONFIGURE_MANDIR) \ + --infodir=$(DEB_CONFIGURE_INFODIR) \ + --sysconfdir=$(DEB_CONFIGURE_SYSCONFDIR) \ + --localstatedir=$(DEB_CONFIGURE_LOCALSTATEDIR) \ + --libexecdir=$(DEB_CONFIGURE_LIBEXECDIR) \ + $(if $(subst $(DEB_SRCDIR),,$(cdbs_make_curbuilddir)),\ + ,\ + --srcdir=.) + +DEB_CONFIGURE_NORMAL_ARGS ?= \ + $(DEB_CONFIGURE_CROSSBUILD_ARGS) \ + $(DEB_CONFIGURE_PATH_ARGS) \ + --disable-maintainer-mode \ + --disable-dependency-tracking \ + --disable-silent-rules + +# all environment settings for autotools configure execution +# (potentially extended by other snippets) +cdbs_autotools_configure_env = $(DEB_CONFIGURE_SCRIPT_ENV) + +DEB_CONFIGURE_INVOKE ?= cd $(cdbs_make_curbuilddir) && \ + $(cdbs_autotools_configure_env) \ + $(DEB_CONFIGURE_SCRIPT) \ + $(DEB_CONFIGURE_NORMAL_ARGS) \ + $(DEB_CONFIGURE_DEBUG_ARGS) + +#DEB_CONFIGURE_EXTRA_FLAGS = + +endif + + +# END # include $(_cdbs_class_path)/autotools-vars.mk$(_cdbs_makefile_suffix) + +# Compatibility blurb, will be eventualy removed +ifneq (,$(DEB_AUTO_UPDATE_AUTOMAKE)) +ifeq (,$(DEB_AUTO_UPDATE_ACLOCAL)) +$(call cdbs_warn,DEB_AUTO_UPDATE_AUTOMAKE will eventually stop implying \ + DEB_AUTO_UPDATE_ACLOCAL. If you meant aclocal.m4 to be \ + regenerated, please use DEB_AUTO_UPDATE_ACLOCAL.) +DEB_AUTO_UPDATE_ACLOCAL ?= $(DEB_AUTO_UPDATE_AUTOMAKE) +endif +endif + +# Some update rules are useless on their own +ifeq (pre,$(DEB_AUTO_UPDATE_LIBTOOL)) +ifeq (,$(DEB_AUTO_UPDATE_ACLOCAL)) +$(call cdbs_warn,DEB_AUTO_UPDATE_LIBTOOL requires DEB_AUTO_UPDATE_ACLOCAL.) +endif +endif +ifneq (,$(DEB_AUTO_UPDATE_ACLOCAL)) +ifeq (,$(DEB_AUTO_UPDATE_AUTOCONF)) +$(call cdbs_warn,DEB_AUTO_UPDATE_ACLOCAL requires DEB_AUTO_UPDATE_AUTOCONF.) +endif +endif + +DEB_ACLOCAL_ARGS ?= $(if $(wildcard $(DEB_SRCDIR)/m4),\ + -I m4) + +# resolve make rule from autotools command version hints +# usage: $(call _cdbs_autotools_invoke,$(VERSION),$(VERSIONEDBINARY),$(BINARY),$(LEGACY)) +# * when VERSION contains comma: return "$(BINARY)" +# * else, when LEGACY exist: return $$(which "$(VERSIONEDBINARY)$(VERSION)" || which "$(BINARY)") +# * else: return "$(VERSIONEDBINARY)$(VERSION)" +# see also autotools-vars.mk +_cdbs_autotools_invoke = $(if $(findstring $(comma),$1),\ + $3,\ + $(if $4,\ + $$(which "$2$1" || which "$3"),\ + $2$1)) + +common-configure-arch common-configure-indep:: debian/stamp-autotools-files +debian/stamp-autotools-files: + $(if $(filter pre,$(DEB_AUTO_UPDATE_LIBTOOL)),\ + cd $(DEB_SRCDIR) && \ + libtoolize -c -f) + $(if $(DEB_AUTO_UPDATE_AUTOPOINT),\ + cd $(DEB_SRCDIR) && \ + $(call _cdbs_autotools_invoke,$(DEB_AUTO_UPDATE_AUTOPOINT),autopoint,autopoint) \ + $(DEB_AUTOPOINT_ARGS)) + $(if $(DEB_AUTO_UPDATE_ACLOCAL),\ + cd $(DEB_SRCDIR) && \ + $(call _cdbs_autotools_invoke,$(DEB_AUTO_UPDATE_ACLOCAL),aclocal-,aclocal) \ + $(DEB_ACLOCAL_ARGS)) + $(if $(DEB_AUTO_UPDATE_AUTOCONF),\ + $(if $(wildcard $(DEB_SRCDIR)/configure.ac $(DEB_SRCDIR)/configure.in),\ + cd $(DEB_SRCDIR) && \ + $(call _cdbs_autotools_invoke,$(DEB_AUTO_UPDATE_AUTOCONF),autoconf,autoconf,legacy) \ + $(DEB_AUTOCONF_ARGS))) + $(if $(DEB_AUTO_UPDATE_AUTOHEADER),\ + $(if $(wildcard $(DEB_SRCDIR)/configure.ac $(DEB_SRCDIR)/configure.in),\ + cd $(DEB_SRCDIR) && \ + $(call _cdbs_autotools_invoke,$(DEB_AUTO_UPDATE_AUTOHEADER),autoheader,autoheader,legacy) \ + $(DEB_AUTOHEADER_ARGS))) + $(if $(DEB_AUTO_UPDATE_AUTOMAKE),\ + $(if $(wildcard $(DEB_SRCDIR)/Makefile.am),\ + cd $(DEB_SRCDIR) && \ + $(call _cdbs_autotools_invoke,$(DEB_AUTO_UPDATE_AUTOMAKE),automake-,automake) \ + $(DEB_AUTOMAKE_ARGS))) + touch debian/stamp-autotools-files + +clean:: + rm -f debian/stamp-autotools-files + +endif + +# END # include $(_cdbs_class_path)/autotools-files.mk$(_cdbs_makefile_suffix) + + +cdbs_autotools_configure_stamps = $(if $(cdbs_make_flavors),\ + $(cdbs_make_builddir_check)$(patsubst %,debian/stamp-autotools/%,$(cdbs_make_flavors)),\ + debian/stamp-autotools) + +cdbs_configure_flags += $(DEB_CONFIGURE_FLAGS_$(cdbs_make_curflavor)) + +# Overriden from makefile-vars.mk. We pass CFLAGS and friends to +# ./configure, so no need to pass them to make. +# FIXME: Restructure to allow early override +DEB_MAKE_EXTRA_ARGS = $(DEB_MAKE_PARALLEL) + +pre-build:: + $(if $(cdbs_make_flavors),mkdir -p debian/stamp-autotools) + +common-configure-arch common-configure-indep:: common-configure-impl +common-configure-impl:: $(cdbs_autotools_configure_stamps) +$(cdbs_autotools_configure_stamps): + chmod a+x $(DEB_CONFIGURE_SCRIPT) + $(if $(call cdbs_streq,$(cdbs_make_curbuilddir),$(DEB_BUILDDIR_$(cdbs_curpkg))),\ + ,\ + mkdir -p $(cdbs_make_curbuilddir)) + $(strip $(DEB_CONFIGURE_INVOKE) \ + $(cdbs_configure_flags) \ + $(DEB_CONFIGURE_EXTRA_FLAGS) \ + $(DEB_CONFIGURE_USER_FLAGS)) + $(if $(filter post,$(DEB_AUTO_UPDATE_LIBTOOL)),\ + $(if $(wildcard $(cdbs_make_curbuilddir)/libtool),\ + cp -f /usr/bin/libtool $(cdbs_make_curbuilddir)/libtool)) + touch $@ + +makefile-clean:: + $(if $(cdbs_make_flavors),\ + -rmdir --ignore-fail-on-non-empty \ + debian/stamp-autotools,\ + rm -f debian/stamp-autotools) + +$(cdbs_make_clean_nonstamps):: + $(if $(call cdbs_streq,$(cdbs_make_curbuilddir),$(DEB_BUILDDIR_$(cdbs_curpkg))),\ + ,\ + -rmdir --ignore-fail-on-non-empty \ + $(cdbs_make_curbuilddir)) + $(if $(cdbs_make_flavors),\ + rm -f $(@:makefile-clean%=debian/stamp-autotools%)) + +endif diff --git a/scripts/obs/debian.control b/scripts/obs/debian.control index e14a9b93a3..d3dcd6e775 100644 --- a/scripts/obs/debian.control +++ b/scripts/obs/debian.control @@ -10,6 +10,8 @@ Build-Depends: debhelper (>= 8.1.3), libsystemd-dev, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libjpeg-dev, + libglib2.0-dev, + libgpiod-dev, libsnmp-dev | libsnmp9-dev, libssl1.0-dev | libssl-dev, libusb-1.0-dev | libusb-0.1-dev | libusb-dev (>= 0.1.8), diff --git a/scripts/obs/debian.nut-gpio.install b/scripts/obs/debian.nut-gpio.install new file mode 100644 index 0000000000..664b078cc5 --- /dev/null +++ b/scripts/obs/debian.nut-gpio.install @@ -0,0 +1 @@ +debian/tmp/lib/nut/generic_gpio_libgpiod diff --git a/scripts/obs/debian.nut-gpio.manpages b/scripts/obs/debian.nut-gpio.manpages new file mode 100644 index 0000000000..b8878c4fb7 --- /dev/null +++ b/scripts/obs/debian.nut-gpio.manpages @@ -0,0 +1 @@ +debian/tmp/usr/share/man/man8/generic_gpio.8 diff --git a/scripts/obs/debian.nut-upower.install b/scripts/obs/debian.nut-upower.install new file mode 100644 index 0000000000..2dc08ba546 --- /dev/null +++ b/scripts/obs/debian.nut-upower.install @@ -0,0 +1 @@ +debian/tmp/lib/nut/nut-upower diff --git a/scripts/obs/debian.nut-upower.manpages b/scripts/obs/debian.nut-upower.manpages new file mode 100644 index 0000000000..b84266209f --- /dev/null +++ b/scripts/obs/debian.nut-upower.manpages @@ -0,0 +1 @@ +debian/tmp/usr/share/man/man8/nut-upower.8 diff --git a/scripts/obs/debian.rules b/scripts/obs/debian.rules index 6dc354450c..6fdfec1154 100755 --- a/scripts/obs/debian.rules +++ b/scripts/obs/debian.rules @@ -1,7 +1,26 @@ #!/usr/bin/make -f include /usr/share/cdbs/1/rules/debhelper.mk + +ifneq (,$(shell ls -1 /usr/share/cdbs/1/class/autotools.mk || true)) include /usr/share/cdbs/1/class/autotools.mk +else +# In 2026, Debian obsoletes and removes CDBS and its scripts +# Stashing https://salsa.debian.org/debian/cdbs/-/blob/a110afb99997b94de6acb1e0758210cdfd8ec3dd/1/class/autotools.mk.in +# and neighbors +ifneq (,$(shell ls -1 debian/cdbs-autotools.mk || true)) +include debian/cdbs-autotools.mk +else +ifneq (,$(shell ls -1 debian.cdbs-autotools.mk || true)) +include debian.cdbs-autotools.mk +else +ifneq (,$(shell ls -1 cdbs-autotools.mk || true)) +include cdbs-autotools.mk +endif +endif +endif +endif + -include /usr/share/cdbs/1/class/python-module.mk -include /usr/share/cdbs/1/rules/autoreconf.mk diff --git a/scripts/obs/nut.dsc b/scripts/obs/nut.dsc index 8c910131a3..c6ed1a52d5 100644 --- a/scripts/obs/nut.dsc +++ b/scripts/obs/nut.dsc @@ -1,6 +1,6 @@ Format: 1.0 Source: nut -Binary: nut, nut-server, nut-client, nut-cgi, nut-snmp, nut-ipmi, nut-modbus, nut-linux-i2c, nut-xml, nut-powerman-pdu, nut-doc, libupsclient4, libupsclient-dev, libnutclient1, libnutclient-dev, python-nut, nut-monitor, libups-nut-perl +Binary: nut, nut-server, nut-client, nut-cgi, nut-snmp, nut-ipmi, nut-modbus, nut-linux-i2c, nut-xml, nut-powerman-pdu, nut-gpio, nut-upower, nut-doc, libupsclient4, libupsclient-dev, libnutclient1, libnutclient-dev, python-nut, nut-monitor, libups-nut-perl Architecture: any all Version: 2.8.4-1 Maintainer: Arnaud Quette @@ -10,7 +10,7 @@ Standards-Version: 3.9.6 Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/nut.git;a=summary Vcs-Git: git://anonscm.debian.org/collab-maint/nut.git Testsuite: autopkgtest -Build-Depends: debhelper (>= 8.1.3), cdbs (>= 0.4.122~), autotools-dev, dh-autoreconf, libsystemd-dev, libjpeg-dev, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libssl1.0-dev | libssl-dev, libsnmp-dev | libsnmp9-dev, libusb-dev (>= 0.1.8), libneon27-gnutls-dev | libneon27-dev, libpowerman0-dev (>= 2.3.3), libwrap0-dev (>= 7.6), python2 | python3, libfreeipmi-dev (>= 0.8.5) [!hurd-i386], libipmimonitoring-dev (>= 1.1.5-2) [!hurd-i386], libnss3-dev, libtool, libltdl-dev, liblua5.1-0-dev, lua5.1, pkg-config, dh-python | dh-python2 | dh-python3 | dh-pypy, libmodbus-dev, libi2c-dev +Build-Depends: debhelper (>= 8.1.3), cdbs (>= 0.4.122~), autotools-dev, dh-autoreconf, libsystemd-dev, libjpeg-dev, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libssl1.0-dev | libssl-dev, libsnmp-dev | libsnmp9-dev, libusb-dev (>= 0.1.8), libneon27-gnutls-dev | libneon27-dev, libglib2.0-dev, libgpiod-dev, libpowerman0-dev (>= 2.3.3), libwrap0-dev (>= 7.6), python2 | python3, libfreeipmi-dev (>= 0.8.5) [!hurd-i386], libipmimonitoring-dev (>= 1.1.5-2) [!hurd-i386], libnss3-dev, libtool, libltdl-dev, liblua5.1-0-dev, lua5.1, pkg-config, dh-python | dh-python2 | dh-python3 | dh-pypy, libmodbus-dev, libi2c-dev # , python (>= 2.6.6-3~) | python-is-python2 | python-is-python3 #+++ python-pycparser # The pycparser is required to rebuild DMF files, but those pre-built @@ -30,6 +30,7 @@ Package-List: nut-cgi deb admin optional arch=any nut-client deb admin optional arch=any nut-doc deb doc optional arch=all + nut-gpio deb admin optional arch=any nut-ipmi deb admin optional arch=linux-any,kfreebsd-any nut-linux-i2c deb admin optional arch=linux-any nut-modbus deb admin optional arch=any @@ -37,6 +38,7 @@ Package-List: nut-powerman-pdu deb admin extra arch=any nut-server deb admin optional arch=any nut-snmp deb admin optional arch=any + nut-upower deb admin optional arch=any nut-xml deb admin optional arch=any python-nut deb python optional arch=all # DEBTRANSFORM-TAR: nut-2.7.4-DMF+daisychain-cb7c7ea8b0d.tar.gz diff --git a/scripts/python/Makefile.am b/scripts/python/Makefile.am index e70abffd34..40a0d8e04d 100644 --- a/scripts/python/Makefile.am +++ b/scripts/python/Makefile.am @@ -281,20 +281,20 @@ SPELLCHECK_SRC = \ # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked */*-spellchecked diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index b8f1553dc9..b01ab00672 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -60,7 +60,7 @@ MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* PyNUTClient: .pypi-src # Tagged releases should only have three blocks of digits separated by dots -upload publish: +upload publish: @dotMAKE@ +@echo " PYPI Checking upload type for module version '$(NUT_SOURCE_GITREV_NUMERIC)'" ; \ case x"`echo '$(NUT_SOURCE_GITREV_NUMERIC)' | tr -d '[0-9]'`" in \ x..) echo " PYPI ...release"; $(MAKE) $(AM_MAKEFLAGS) upload-pypi ;; \ @@ -122,10 +122,10 @@ upload publish: @touch '$@' # Using pypa/setuptools -.pypi-dist: .pypi-src +.pypi-dist: .pypi-src @dotMAKE@ +@$(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-build || \ - $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-obsolete || \ - $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-wheel + $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-obsolete || \ + $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-wheel @touch '$@' # The most modern approach as of 2023 diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in index d520c960f9..51383d1593 100644 --- a/scripts/python/module/setup.py.in +++ b/scripts/python/module/setup.py.in @@ -5,14 +5,50 @@ The setup.py file for PyNUTClient # See also .github/workflows/PyNUTClient.yml for active packaging steps from setuptools import setup, find_packages -import codecs import os +import sys here = os.path.abspath(os.path.dirname(__file__)) +HAVE_WARNINGS = False +try: + import warnings + warnings.filterwarnings("error") + HAVE_WARNINGS = True +except Exception as x: + # sys.stderr.write("WARNING: failed to import warnings or configure them: %s" % str(x)) + pass + +try: + # NOTE: Deprecated as of python3.14 + import codecs + HAVE_CODECS = True + fd = None + try: + # Open self to test that it works + fd = codecs.open(os.path.abspath(__file__), mode="r", encoding='utf-8') + USE_CODECS = True + # sys.stderr.write("INFO: import codecs went well, and codecs.open() did not raise exceptions\n") + except DeprecationWarning as x: + USE_CODECS = False + # sys.stderr.write("WARNING: import codecs went well, but codecs.open() failed: %s\n" % str(x)) + if fd is not None: + fd.close() +except Exception as x: + # sys.stderr.write("WARNING: import codecs failed: %s\n" % str(x)) + HAVE_CODECS = False + USE_CODECS = False + +if HAVE_WARNINGS: + warnings.resetwarnings() + # README.txt appears from README.adoc during package or CI build -with codecs.open(os.path.join(here, "README.txt"), encoding="utf-8") as fh: - long_description = "\n" + fh.read() +if USE_CODECS: + with codecs.open(os.path.join(here, "README.txt"), encoding="utf-8") as fh: + long_description = "\n" + fh.read() +else: + with open(os.path.join(here, "README.txt"), encoding="utf-8") as fh: + long_description = "\n" + fh.read() setup( name = "pynutclient", ### "PyNUTClient" lower-cased due to PEP-0625 diff --git a/scripts/subdriver/gen-snmp-subdriver.sh b/scripts/subdriver/gen-snmp-subdriver.sh index b2fb87294e..cb19ec32dc 100755 --- a/scripts/subdriver/gen-snmp-subdriver.sh +++ b/scripts/subdriver/gen-snmp-subdriver.sh @@ -600,8 +600,8 @@ done # remove blank and "End of MIB" lines TABCHAR="`printf '\t'`" -${EGREP} "^[ ${TABCHAR}]?\$" | ${GREP} "End of MIB" | ${GREP} -v "${NUMWALKFILE}" > "${TMP_NUMWALKFILE}" -${EGREP} "^[ ${TABCHAR}]?\$" | ${GREP} "End of MIB" | ${GREP} -v "${STRWALKFILE}" > "${TMP_STRWALKFILE}" +${EGREP} -v "^[ ${TABCHAR}]?\$" "${NUMWALKFILE}" | ${GREP} -v "End of MIB" > "${TMP_NUMWALKFILE}" +${EGREP} -v "^[ ${TABCHAR}]?\$" "${STRWALKFILE}" | ${GREP} -v "End of MIB" > "${TMP_STRWALKFILE}" NUMWALKFILE="${TMP_NUMWALKFILE}" STRWALKFILE="${TMP_STRWALKFILE}" diff --git a/scripts/systemd/Makefile.am b/scripts/systemd/Makefile.am index ee9ef9f3f7..f648e5ce58 100644 --- a/scripts/systemd/Makefile.am +++ b/scripts/systemd/Makefile.am @@ -62,20 +62,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/scripts/udev/Makefile.am b/scripts/udev/Makefile.am index a63107d980..a876e83f78 100644 --- a/scripts/udev/Makefile.am +++ b/scripts/udev/Makefile.am @@ -42,20 +42,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES += *-spellchecked diff --git a/scripts/upsdrvsvcctl/Makefile.am b/scripts/upsdrvsvcctl/Makefile.am index 03adf8e1c4..ca9c4cafb6 100644 --- a/scripts/upsdrvsvcctl/Makefile.am +++ b/scripts/upsdrvsvcctl/Makefile.am @@ -18,20 +18,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/server/Makefile.am b/server/Makefile.am index e7c7b7272b..2b8ff838e9 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -13,7 +13,7 @@ $(top_builddir)/include/nut_version.h \ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonversion.la \ -$(top_builddir)/common/libparseconf.la: dummy +$(top_builddir)/common/libparseconf.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Builds from root dir arrange stuff decently. Make sure parallel builds @@ -25,7 +25,7 @@ $(top_builddir)/common/libcommonversion.la: $(top_builddir)/include/nut_version. if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h diff --git a/server/conf.c b/server/conf.c index 18f7bc89f2..b2edf311b6 100644 --- a/server/conf.c +++ b/server/conf.c @@ -54,7 +54,7 @@ static void ups_create(const char *fn, const char *name, const char *desc) } /* grab some memory and add the info */ - temp = xcalloc(1, sizeof(*temp)); + temp = (upstype_t*)xcalloc(1, sizeof(*temp)); temp->fn = xstrdup(fn); temp->name = xstrdup(name); @@ -475,7 +475,7 @@ void do_upsconf_args(char *upsname, char *var, char *val) /* if not listed, create a new entry and prepend it to the list */ if (temp == NULL) { - temp = xcalloc(1, sizeof(*temp)); + temp = (ups_t*)xcalloc(1, sizeof(*temp)); temp->upsname = xstrdup(upsname); temp->next = upstable; upstable = temp; diff --git a/server/desc.c b/server/desc.c index bdc9924e72..edbc01eda3 100644 --- a/server/desc.c +++ b/server/desc.c @@ -76,7 +76,7 @@ static void desc_add(dlist_t **list, const char *name, const char *desc) } if (temp == NULL) { - temp = xcalloc(1, sizeof(*temp)); + temp = (dlist_t*)xcalloc(1, sizeof(*temp)); temp->name = xstrdup(name); temp->next = *list; *list = temp; diff --git a/server/netlist.c b/server/netlist.c index d480eb1fa3..0d3dc909e5 100644 --- a/server/netlist.c +++ b/server/netlist.c @@ -243,7 +243,7 @@ static void list_ups(nut_ctype_t *client) } else { ret = sendback(client, "UPS %s \"Description unavailable\"\n", - utmp->name); + utmp->name); } if (!ret) diff --git a/server/upsd.c b/server/upsd.c index d730d8d4af..fd82500f75 100644 --- a/server/upsd.c +++ b/server/upsd.c @@ -5,7 +5,7 @@ 2008 Arjen de Korte 2011 - 2012 Arnaud Quette 2019 Eaton (author: Arnaud Quette ) - 2020 - 2025 Jim Klimov + 2020 - 2026 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -94,8 +94,12 @@ int allow_no_device = 0; */ int allow_not_all_listeners = 0; -/* preloaded to {OPEN_MAX} in main, can be overridden via upsd.conf */ +/* preloaded to POSIX sysconf(_SC_OPEN_MAX) or WIN32 MAX_WAIT_OBJECTS in main + * and elsewhere, the run-time value can be overridden via upsd.conf `MAXCONN` + * option (may cause partial waits chunk by chunk, if sysmaxconn is smaller). + */ nfds_t maxconn = 0; +static nfds_t sysmaxconn = 0; /* preloaded to STATEPATH in main, can be overridden via upsd.conf */ char *statepath = NULL; @@ -112,7 +116,7 @@ nut_ctype_t *firstclient = NULL; /* default is to listen on all local interfaces */ static stype_t *firstaddr = NULL; -static int opt_af = AF_UNSPEC; +static int opt_af = AF_UNSPEC; typedef enum { DRIVER = 1, @@ -151,11 +155,13 @@ static tracking_t *tracking_list = NULL; #ifndef WIN32 /* pollfd */ -static struct pollfd *fds = NULL; +#define FTS_T struct pollfd #else /* WIN32 */ -static HANDLE *fds = NULL; +#define FTS_T HANDLE static HANDLE mutex = INVALID_HANDLE_VALUE; #endif /* WIN32 */ +/* Dynamic array of file descriptors (or WIN32 handles) that we poll */ +static FTS_T *fds = NULL; static handler_t *handler = NULL; /* pid file */ @@ -230,7 +236,7 @@ void listen_add(const char *addr, const char *port) } /* grab some memory and add the info */ - server = xcalloc(1, sizeof(*server)); + server = (stype_t*)xcalloc(1, sizeof(*server)); server->addr = xstrdup(addr); server->port = xstrdup(port); server->sock_fd = ERROR_FD_SOCK; @@ -326,7 +332,7 @@ static void setuptcp(stype_t *server) /* Not constrained to IPv6 */ upsdebugx(1, "%s: handling 'LISTEN * %s' with IPv4 any-address support", __func__, server->port); - serverAnyV4 = xcalloc(1, sizeof(*serverAnyV4)); + serverAnyV4 = (stype_t*)xcalloc(1, sizeof(*serverAnyV4)); serverAnyV4->addr = xstrdup("0.0.0.0"); serverAnyV4->port = xstrdup(server->port); serverAnyV4->sock_fd = ERROR_FD_SOCK; @@ -337,7 +343,7 @@ static void setuptcp(stype_t *server) /* Not constrained to IPv4 */ upsdebugx(1, "%s: handling 'LISTEN * %s' with IPv6 any-address support", __func__, server->port); - serverAnyV6 = xcalloc(1, sizeof(*serverAnyV6)); + serverAnyV6 = (stype_t*)xcalloc(1, sizeof(*serverAnyV6)); serverAnyV6->addr = xstrdup("::0"); serverAnyV6->port = xstrdup(server->port); serverAnyV6->sock_fd = ERROR_FD_SOCK; @@ -750,7 +756,7 @@ static void check_command(int cmdnum, nut_ctype_t *client, size_t numarg, && (nut_debug_level > 9 || strcmp(arg[0], "PASSWORD")) /* Do not log credentials by default */ ) { /* Not xcalloc() here, not too fatal if we fail */ - char *s = calloc(LARGEBUF, sizeof(char)); + char *s = (char*)calloc(LARGEBUF, sizeof(char)); if (s) { size_t i; @@ -856,7 +862,7 @@ static void client_connect(stype_t *server) return; } - client = xcalloc(1, sizeof(*client)); + client = (nut_ctype_t*)xcalloc(1, sizeof(*client)); client->sock_fd = fd; @@ -1085,8 +1091,8 @@ void server_load(void) return; /* check for edge cases we can let slide */ - if ( (listenersTotal - listenersValid) == - (listenersTotalLocalhost - listenersValidLocalhost) + if ( (listenersTotal - listenersValid) + == (listenersTotalLocalhost - listenersValidLocalhost) ) { /* Note that we can also get into this situation * when "dual-stack" IPv6 listener also handles @@ -1216,22 +1222,68 @@ static void upsd_cleanup(void) upsdebugx(1, "%s: finished", __func__); } -static void poll_reload(void) +static void update_sysmaxconn(void) { - long ret; - size_t maxalloc; + long l; + char *s = getenv("NUT_SYSMAXCONN_LIMIT"); #ifndef WIN32 - ret = sysconf(_SC_OPEN_MAX); + /* default to system limit (may be overridden in upsd.conf) */ + /* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */ + l = sysconf(_SC_OPEN_MAX); #else /* WIN32 */ - ret = (long)MAXIMUM_WAIT_OBJECTS; + /* hard-coded 64 (from ddk/wdm.h or winnt.h) */ + l = (long)MAXIMUM_WAIT_OBJECTS; #endif /* WIN32 */ - if ((intmax_t)ret < (intmax_t)maxconn) { + if (l < 1) { + /* TOTHINK: Not fail, but use a conservative fallback number? + * Can we trust the OS to support any? + */ fatalx(EXIT_FAILURE, - "Your system limits the maximum number of connections to %ld\n" - "but you requested %" PRIdMAX ". The server won't start until this\n" - "problem is resolved.\n", ret, (intmax_t)maxconn); + "System reported an absurd value %ld as maximum number of connections.\n" + "The server won't start until this problem is resolved.\n", + l); + } + + /* Note this historically also serves as + * the initial/default MAXCONN setting + * (so site/platform-dependent). + */ + sysmaxconn = (nfds_t)l; + if (maxconn < 1) { + upsdebugx(1, "%s: defaulting maxconn to sysmaxconn: %ld", + __func__, l); + maxconn = sysmaxconn; + } + + /* Support envvar for NIT or similar tests. + * Still do not exceed what the OS said. + */ + if (s && str_to_long(s, &l, 10)) { + if (l > 0 && (nfds_t)l < sysmaxconn) { + upslogx(LOG_INFO, "Adjusting sysmaxconn according to NUT_SYSMAXCONN_LIMIT envvar: %ld", l); + sysmaxconn = (nfds_t)l; + } else { + upslogx(LOG_WARNING, "Adjusting sysmaxconn according to NUT_SYSMAXCONN_LIMIT envvar failed: %ld is out of range. Keeping OS-provided %ld.", + l, (long)sysmaxconn); + } + } /* else nothing to bother about */ +} + +static void poll_reload(void) +{ + size_t maxalloc; + + /* Not likely this would change, but refresh just in case */ + update_sysmaxconn(); + + if ((intmax_t)sysmaxconn < (intmax_t)maxconn) { + upslogx(LOG_WARNING, + "Your system limits the maximum number of connections to %" PRIdMAX "\n" + "but you requested %" PRIdMAX ". The server may handle connections\n" + "in smaller groups, maybe affecting efficiency and response time.\n", + (intmax_t)sysmaxconn, (intmax_t)maxconn); } if (1 > maxconn) { @@ -1240,12 +1292,8 @@ static void poll_reload(void) "The server won't start until this problem is resolved.\n", (intmax_t)maxconn); } -#ifndef WIN32 /* How many items can we stuff into the array? */ maxalloc = SIZE_MAX / sizeof(void *); -#else /* WIN32 */ - maxalloc = MAXIMUM_WAIT_OBJECTS; -#endif /* WIN32 */ if ((uintmax_t)maxalloc < (uintmax_t)maxconn) { fatalx(EXIT_FAILURE, "You requested %" PRIdMAX " as maximum number of connections, but we can only allocate %" PRIuSIZE ".\n" @@ -1256,8 +1304,8 @@ static void poll_reload(void) upsdebugx(1, "%s: (p)re-allocate %" PRIuMAX " entries for polling FDs and handlers", __func__, (uintmax_t)maxconn); - fds = xrealloc(fds, (size_t)maxconn * sizeof(*fds)); - handler = xrealloc(handler, (size_t)maxconn * sizeof(*handler)); + fds = (FTS_T*)xrealloc(fds, (size_t)maxconn * sizeof(*fds)); + handler = (handler_t*)xrealloc(handler, (size_t)maxconn * sizeof(*handler)); } /* instant command and setvar status tracking */ @@ -1270,7 +1318,7 @@ int tracking_add(const char *id) if ((!tracking_enabled) || (!id)) return 0; - item = xcalloc(1, sizeof(*item)); + item = (tracking_t*)xcalloc(1, sizeof(*item)); item->id = xstrdup(id); item->status = STAT_PENDING; @@ -1495,14 +1543,15 @@ static void mainloop(void) nfds_t i; #else /* WIN32 */ DWORD ret; - pipe_conn_t * conn; + pipe_conn_t *conn; + size_t chunk = 0; #endif /* WIN32 */ size_t nfds_wanted = 0, /* Connections we looked at (some may be invalid) */ nfds_considered = 0; /* Connections we wanted to poll (but might be over maxconn limit) */ nfds_t nfds = 0; upstype_t *ups; - nut_ctype_t *client, *cnext; + nut_ctype_t *client, *cnext; stype_t *server; time_t now; @@ -1642,18 +1691,58 @@ static void mainloop(void) upsdebugx(2, "%s: polling %" PRIdMAX " filedescriptors; some stats: " "considered %" PRIdMAX " connections, " "wanted to actually poll %" PRIdMAX - " and was constrained by maxconn=%" PRIdMAX, + " and was constrained by maxconn=%" PRIdMAX + " and chunked by sysmaxconn=%" PRIdMAX, __func__, (intmax_t)nfds, (intmax_t)nfds_considered, - (intmax_t)nfds_wanted, (intmax_t)maxconn); + (intmax_t)nfds_wanted, (intmax_t)maxconn, (intmax_t)sysmaxconn); - if (nfds_wanted != nfds || nfds_wanted >= maxconn) { + if (nfds_wanted != nfds || nfds_wanted > maxconn) { upslogx(LOG_ERR, "upsd polling %" PRIdMAX " filedescriptors," " but wanted to poll %" PRIdMAX - " and was constrained by maxconn=%" PRIdMAX, + " and was constrained by maxconn=%" PRIdMAX + " (see upsd.conf MAXCONN setting to adjust)", (intmax_t)nfds, (intmax_t)nfds_wanted, (intmax_t)maxconn); } - ret = poll(fds, nfds, 2000); + if (nfds <= sysmaxconn) { + ret = poll(fds, nfds, 2000); + } else { + /* Chunk it all; try to fit into same 2 sec as above. + * Note that nfds at the moment may be smaller than + * maxconn (allocated array size). + */ + size_t last_chunk = nfds % sysmaxconn, chunk, + chunks = nfds / sysmaxconn + (last_chunk ? 1 : 0); + int poll_TO = 2000 / chunks, tmpret; + + if (poll_TO < 10) + poll_TO = 10; + + upsdebugx(4, "%s: chunked filedescriptor polling via %" PRIuSIZE + " chunks, last one sized %" PRIuSIZE + ", with timeout of %d msec per chunk", + __func__, chunks, last_chunk, poll_TO); + + ret = 0; + for (chunk = 0; chunk < chunks; chunk++) { + upsdebugx(5, + "%s: chunked filedescriptor polling #%" PRIuSIZE + " of %" PRIuSIZE " chunks, with %d hits so far", + __func__, chunk, chunks, ret); + tmpret = poll(&fds[chunk * sysmaxconn], + (last_chunk && chunk == chunks - 1 ? last_chunk : sysmaxconn), + poll_TO); + if (tmpret < 0) { + upsdebug_with_errno(2, + "%s: failed during chunked polling, handled %" PRIuSIZE + " of %" PRIuSIZE " chunks so far, with %d hits", + __func__, chunk, chunks, ret); + ret = tmpret; + break; + } + ret += tmpret; + } + } if (ret == 0) { upsdebugx(2, "%s: no data available", __func__); @@ -1940,19 +2029,58 @@ static void mainloop(void) upsdebugx(2, "%s: wait for %" PRIdMAX " filedescriptors; some stats: " "considered %" PRIdMAX " connections, " "wanted to actually poll %" PRIdMAX - " and was constrained by maxconn=%" PRIdMAX, + " and was constrained by maxconn=%" PRIdMAX + " and chunked by sysmaxconn=%" PRIdMAX, __func__, (intmax_t)nfds, (intmax_t)nfds_considered, - (intmax_t)nfds_wanted, (intmax_t)maxconn); + (intmax_t)nfds_wanted, (intmax_t)maxconn, (intmax_t)sysmaxconn); - if (nfds_wanted != nfds || nfds_wanted >= maxconn) { + if (nfds_wanted != nfds || nfds_wanted > maxconn) { upslogx(LOG_ERR, "upsd polling %" PRIuMAX " filedescriptors," " but wanted to poll %" PRIuMAX - " and was constrained by maxconn=%" PRIuMAX, + " and was constrained by maxconn=%" PRIuMAX + " (see upsd.conf MAXCONN setting to adjust)", (uintmax_t)nfds, (uintmax_t)nfds_wanted, (uintmax_t)maxconn); } - /* https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects */ - ret = WaitForMultipleObjects(nfds,fds,FALSE,2000); + /* https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects + * We handle whoever lights up first, one per loop cycle. + */ + chunk = 0; + if (nfds <= sysmaxconn) { + ret = WaitForMultipleObjects(nfds, fds, FALSE, 2000); + } else { + /* Chunk it all; try to fit into same 2 sec as above. + * Note that nfds at the moment may be smaller than + * maxconn (allocated array size). + */ + size_t last_chunk = nfds % sysmaxconn, + chunks = nfds / sysmaxconn + (last_chunk ? 1 : 0); + DWORD poll_TO = 2000 / chunks, tmpret; + + if (poll_TO < 10) + poll_TO = 10; + + upsdebugx(4, "%s: chunked filedescriptor polling via %" PRIuSIZE + " chunks, last one sized %" PRIuSIZE + ", with timeout of %" PRIi64 " msec per chunk", + __func__, chunks, last_chunk, poll_TO); + + ret = WAIT_TIMEOUT; + for (chunk = 0; chunk < chunks; chunk++) { + upsdebugx(5, + "%s: chunked filedescriptor polling #%" PRIuSIZE + " of %" PRIuSIZE " chunks, with %" PRIu64 " hits so far", + __func__, chunk, chunks, ret); + tmpret = WaitForMultipleObjects( + (last_chunk && chunk == chunks - 1 ? last_chunk : sysmaxconn), + &fds[chunk * sysmaxconn], + FALSE, poll_TO); + if (tmpret != WAIT_TIMEOUT) { + ret = tmpret; + break; + } + } + } upsdebugx(6, "%s: wait for filedescriptors done: %" PRIu64, __func__, ret); @@ -1979,7 +2107,7 @@ static void mainloop(void) #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif - if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + nfds - 1) { + if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + (nfds < sysmaxconn ? nfds : sysmaxconn) - 1) { /* One abandoned mutex object that satisfied the wait? */ ret = ret - WAIT_ABANDONED_0; upsdebugx(5, "%s: got abandoned FD array item: %" PRIu64, __func__, nfds, ret); @@ -1989,7 +2117,7 @@ static void mainloop(void) /* Which one handle was triggered this time? */ /* Note: WAIT_OBJECT_0 may be currently defined as 0, * but docs insist on checking and shifting the range */ - ret = ret - WAIT_OBJECT_0; + ret = ret - WAIT_OBJECT_0 + chunk * sysmaxconn; upsdebugx(5, "%s: got event on FD array item: %" PRIu64, __func__, nfds, ret); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) @@ -2282,14 +2410,14 @@ int main(int argc, char **argv) } { /* scoping */ - char *s = getenv("NUT_DEBUG_LEVEL"); - int l; - if (s && str_to_int(s, &l, 10)) { - if (l > 0 && nut_debug_level_args < 1) { + char *s = getenv("NUT_DEBUG_LEVEL"); + int lvl; + if (s && str_to_int(s, &lvl, 10)) { + if (lvl > 0 && nut_debug_level_args < 1) { upslogx(LOG_INFO, "Defaulting debug verbosity to NUT_DEBUG_LEVEL=%d " - "since none was requested by command-line options", l); - nut_debug_level = l; - nut_debug_level_args = l; + "since none was requested by command-line options", lvl); + nut_debug_level = lvl; + nut_debug_level_args = lvl; } /* else follow -D settings */ } /* else nothing to bother about */ } @@ -2442,14 +2570,8 @@ int main(int argc, char **argv) chroot_start(chroot_path); } -#ifndef WIN32 - /* default to system limit (may be overridden in upsd.conf) */ - /* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */ - maxconn = (nfds_t)sysconf(_SC_OPEN_MAX); -#else /* WIN32 */ - /* hard-coded 64 (from ddk/wdm.h or winnt.h) */ - maxconn = MAXIMUM_WAIT_OBJECTS; -#endif /* WIN32 */ + /* Also initializes maxconn to what the OS says */ + update_sysmaxconn(); /* handle upsd.conf */ load_upsdconf(0); /* 0 = initial */ diff --git a/server/user.c b/server/user.c index 7bf29445c9..e8a76f7f97 100644 --- a/server/user.c +++ b/server/user.c @@ -45,7 +45,7 @@ static void user_add(const char *un) return; } - for (tmp = users; tmp != NULL; tmp = tmp->next) { + for (tmp = users; tmp != NULL; tmp = (ulist_t*)tmp->next) { last = tmp; @@ -55,7 +55,7 @@ static void user_add(const char *un) } } - tmp = xcalloc(1, sizeof(*tmp)); + tmp = (ulist_t*)xcalloc(1, sizeof(*tmp)); tmp->username = xstrdup(un); if (last) { @@ -105,7 +105,7 @@ static void user_add_instcmd(const char *cmd) return; } - for (tmp = curr_user->firstcmd; tmp != NULL; tmp = tmp->next) { + for (tmp = curr_user->firstcmd; tmp != NULL; tmp = (instcmdlist_t*)tmp->next) { last = tmp; @@ -118,7 +118,7 @@ static void user_add_instcmd(const char *cmd) upsdebugx(2, "user_add_instcmd: adding '%s' for %s", cmd, curr_user->username); - tmp = xcalloc(1, sizeof(*tmp)); + tmp = (instcmdlist_t*)xcalloc(1, sizeof(*tmp)); tmp->cmd = xstrdup(cmd); @@ -137,12 +137,12 @@ static actionlist_t *addaction(actionlist_t *base, const char *action) return base; } - for (tmp = base; tmp != NULL; tmp = tmp->next) { + for (tmp = base; tmp != NULL; tmp = (actionlist_t*)tmp->next) { last = tmp; } - tmp = xcalloc(1, sizeof(*tmp)); + tmp = (actionlist_t*)xcalloc(1, sizeof(*tmp)); tmp->action = xstrdup(action); if (last) { @@ -174,7 +174,7 @@ static void flushcmd(instcmdlist_t *ptr) return; } - flushcmd(ptr->next); + flushcmd((instcmdlist_t*)ptr->next); free(ptr->cmd); free(ptr); @@ -186,7 +186,7 @@ static void flushaction(actionlist_t *ptr) return; } - flushaction(ptr->next); + flushaction((actionlist_t*)ptr->next); free(ptr->action); free(ptr); @@ -198,7 +198,7 @@ static void flushuser(ulist_t *ptr) return; } - flushuser(ptr->next); + flushuser((ulist_t*)ptr->next); flushcmd(ptr->firstcmd); flushaction(ptr->firstaction); @@ -218,7 +218,7 @@ static int user_matchinstcmd(ulist_t *user, const char * cmd) { instcmdlist_t *tmp; - for (tmp = user->firstcmd; tmp != NULL; tmp = tmp->next) { + for (tmp = user->firstcmd; tmp != NULL; tmp = (instcmdlist_t*)tmp->next) { if (!strcasecmp(tmp->cmd, cmd)) { return 1; /* good */ @@ -240,7 +240,7 @@ int user_checkinstcmd(const char *un, const char *pw, const char *cmd) return 0; /* failed */ } - for (tmp = users; tmp != NULL; tmp = tmp->next) { + for (tmp = users; tmp != NULL; tmp = (ulist_t*)tmp->next) { /* let's be paranoid before we call strcmp */ @@ -274,7 +274,7 @@ static int user_matchaction(ulist_t *user, const char *action) { actionlist_t *tmp; - for (tmp = user->firstaction; tmp != NULL; tmp = tmp->next) { + for (tmp = user->firstaction; tmp != NULL; tmp = (actionlist_t*)tmp->next) { if (!strcasecmp(tmp->action, action)) { return 1; /* good */ @@ -291,7 +291,7 @@ int user_checkaction(const char *un, const char *pw, const char *action) if ((!un) || (!pw) || (!action)) return 0; /* failed */ - for (tmp = users; tmp != NULL; tmp = tmp->next) { + for (tmp = users; tmp != NULL; tmp = (ulist_t*)tmp->next) { /* let's be paranoid before we call strcmp */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3042e6ea99..b4b5fe5240 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -31,7 +31,7 @@ check_PROGRAMS = $(TESTS) check_SCRIPTS = # NUT Integration Testing suite -check-NIT check-NIT-devel: +check-NIT check-NIT-devel: @dotMAKE@ +cd "$(builddir)/NIT" && $(MAKE) $(AM_MAKEFLAGS) $@ # Make sure out-of-dir dependencies exist (especially when dev-building @@ -45,32 +45,41 @@ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la \ $(top_builddir)/clients/libnutclient.la \ -$(top_builddir)/clients/libnutclientstub.la: dummy +$(top_builddir)/clients/libnutclientstub.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Builds from root dir arrange stuff decently. Make sure parallel builds # started from scratch right in this dir get dependencies in proper order # (sub-makes are independent as far as trying to write into same files): $(top_builddir)/common/libcommon.la $(top_builddir)/common/libcommonclient.la: $(top_builddir)/common/libparseconf.la -$(top_builddir)/common/libnutconf.la: $(top_builddir)/common/libcommonclient.la -$(top_builddir)/drivers/libdummy_mockdrv.la: $(top_builddir)/common/libcommon.la $(top_builddir)/common/libcommonversion.la $(top_builddir)/common/libparseconf.la -$(top_builddir)/clients/libnutclient.la: $(top_builddir)/common/libcommonclient.la -$(top_builddir)/clients/libnutclientstub.la: $(top_builddir)/clients/libnutclient.la $(top_builddir)/common/libcommonversion.la: $(top_builddir)/include/nut_version.h +$(top_builddir)/clients/libnutclientstub.la: $(top_builddir)/clients/libnutclient.la if ENABLE_SHARED_PRIVATE_LIBS + $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la: $(top_builddir)/common/libcommon.la $(top_builddir)/common/libcommonversion-private.la $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: $(top_builddir)/common/libcommonclient.la $(top_builddir)/common/libcommonversion-private.la +$(top_builddir)/drivers/libdummy_mockdrv.la: $(top_builddir)/common/libcommonversion.la $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la +$(top_builddir)/common/libnutconf.la: $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la +$(top_builddir)/clients/libnutclient.la: $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la + NUT_LIBCOMMON = $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la + else !ENABLE_SHARED_PRIVATE_LIBS + +$(top_builddir)/drivers/libdummy_mockdrv.la: $(top_builddir)/common/libcommon.la $(top_builddir)/common/libcommonversion.la $(top_builddir)/common/libparseconf.la +$(top_builddir)/common/libnutconf.la: $(top_builddir)/common/libcommonclient.la +$(top_builddir)/clients/libnutclient.la: $(top_builddir)/common/libcommonclient.la + NUT_LIBCOMMON = $(top_builddir)/common/libcommon.la + endif !ENABLE_SHARED_PRIVATE_LIBS nutlogtest_SOURCES = nutlogtest.c diff --git a/tests/NIT/Makefile.am b/tests/NIT/Makefile.am index 8332bac658..b6c929b2bd 100644 --- a/tests/NIT/Makefile.am +++ b/tests/NIT/Makefile.am @@ -13,10 +13,16 @@ EXTRA_DIST = nit.sh README.adoc if WITH_CHECK_NIT check: check-NIT -else +else !WITH_CHECK_NIT check: @echo "NO-OP: $@ in `pwd` is inactive by default. Run 'configure --enable-check-NIT' or 'make check-NIT' explicitly" >&2 -endif +endif !WITH_CHECK_NIT + +# Paths possibly different from what automake provides (POSIXish) +# when building on/for e.g. Windows. Matters where system() is used, +# such as NIT suite using/testing upsdrvctl: +ABS_TOP_SRCDIR = @ABS_TOP_SRCDIR@ +ABS_TOP_BUILDDIR = @ABS_TOP_BUILDDIR@ # Run in builddir, use script from srcdir # Avoid running "$<" - not all make implementations handle that @@ -25,11 +31,12 @@ check-NIT: $(abs_srcdir)/nit.sh BUILTIN_RUN_AS_USER='$(RUN_AS_USER)' BUILTIN_RUN_AS_GROUP='$(RUN_AS_GROUP)' \ abs_srcdir='$(abs_srcdir)' abs_builddir='$(abs_builddir)' \ abs_top_srcdir='$(abs_top_srcdir)' abs_top_builddir='$(abs_top_builddir)' \ + ABS_TOP_SRCDIR='$(ABS_TOP_SRCDIR)' ABS_TOP_BUILDDIR='$(ABS_TOP_BUILDDIR)' \ EXEEXT='$(EXEEXT)' \ "$(abs_srcdir)/nit.sh" # Make sure pre-requisites for NIT are fresh as we iterate -check-NIT-devel: $(abs_srcdir)/nit.sh +check-NIT-devel: $(abs_srcdir)/nit.sh @dotMAKE@ +@cd .. && ( $(MAKE) $(AM_MAKEFLAGS) -s cppnit$(EXEEXT) || echo "OPTIONAL C++ test client test will be skipped" ) +@cd "$(top_builddir)/clients" && $(MAKE) $(AM_MAKEFLAGS) -s upsc$(EXEEXT) upscmd$(EXEEXT) upsrw$(EXEEXT) upsmon$(EXEEXT) +@cd "$(top_builddir)/server" && $(MAKE) $(AM_MAKEFLAGS) -s upsd$(EXEEXT) sockdebug$(EXEEXT) @@ -48,10 +55,11 @@ check-NIT-sandbox: $(abs_srcdir)/nit.sh BUILTIN_RUN_AS_USER='$(RUN_AS_USER)' BUILTIN_RUN_AS_GROUP='$(RUN_AS_GROUP)' \ abs_srcdir='$(abs_srcdir)' abs_builddir='$(abs_builddir)' \ abs_top_srcdir='$(abs_top_srcdir)' abs_top_builddir='$(abs_top_builddir)' \ + ABS_TOP_SRCDIR='$(ABS_TOP_SRCDIR)' ABS_TOP_BUILDDIR='$(ABS_TOP_BUILDDIR)' \ EXEEXT='$(EXEEXT)' \ "$(abs_srcdir)/nit.sh" -check-NIT-sandbox-devel: $(abs_srcdir)/nit.sh +check-NIT-sandbox-devel: $(abs_srcdir)/nit.sh @dotMAKE@ +[ -n "$${DEBUG_SLEEP-}" ] && [ "$${DEBUG_SLEEP-}" -gt 0 ] || DEBUG_SLEEP=600 ; export DEBUG_SLEEP ; \ GREP="$(GREP)"; EGREP="$(EGREP)"; export GREP; export EGREP; \ LANG=C LC_ALL=C TZ=UTC \ @@ -65,20 +73,20 @@ SPELLCHECK_SRC = README.adoc # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): -#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) +#%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @dotMAKE@ # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) -.sample.sample-spellchecked: +.sample.sample-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -.in.in-spellchecked: +.in.in-spellchecked: @dotMAKE@ +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ -spellcheck spellcheck-interactive spellcheck-sortdict: +spellcheck spellcheck-interactive spellcheck-sortdict: @dotMAKE@ +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked diff --git a/tests/NIT/nit.sh b/tests/NIT/nit.sh index 0db5378c85..43df6e47fc 100755 --- a/tests/NIT/nit.sh +++ b/tests/NIT/nit.sh @@ -53,7 +53,7 @@ # different value like "nobody" or "nogroup" would be defaulted for test. # # Copyright -# 2022-2025 Jim Klimov +# 2022-2026 Jim Klimov # # License: GPLv2+ @@ -427,7 +427,7 @@ else fi log_info "Locating NUT programs to test:" -for PROG in upsd upsc dummy-ups upsmon upslog upssched ; do +for PROG in upsd upsc dummy-ups upsdrvctl upsmon upslog upssched ; do (command -v ${PROG}) || (command -v ${PROG}${EXEEXT-}) || die "Useless setup: ${PROG} not found in PATH: ${PATH}" done @@ -1000,9 +1000,24 @@ generatecfg_upsmon_secondary() { generatecfg_ups_trivial() { # Populate the configs for the run ( echo 'maxretry = 3' > "$NUT_CONFPATH/ups.conf" || exit - if [ x"${TOP_BUILDDIR}" != x ]; then - echo "driverpath = \"${TOP_BUILDDIR}/drivers\"" >> "$NUT_CONFPATH/ups.conf" || exit + if [ x"${ABS_TOP_BUILDDIR}" != x ]; then + # NOTE: Windows backslashes are pre-escaped in the configure-generated value + case "${ABS_TOP_BUILDDIR}" in + ?":\\"*) PATHSEP='\\' ;; + *) PATHSEP="/" ;; + esac + echo "driverpath = \"${ABS_TOP_BUILDDIR}${PATHSEP}drivers\"" >> "$NUT_CONFPATH/ups.conf" || exit + else + # NOTE: Escaping presumed needed below, so for PATHSEP too + if [ x"${TOP_BUILDDIR}" != x ]; then + case "${TOP_BUILDDIR}" in + ?":\\"*) PATHSEP='\' ;; + *) PATHSEP="/" ;; + esac + echo "driverpath = \"${TOP_BUILDDIR}${PATHSEP}drivers\"" | sed 's,\\,\\\\,g' >> "$NUT_CONFPATH/ups.conf" || exit + fi fi + unset PATHSEP if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "debug_min = ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/ups.conf" || exit fi @@ -1359,8 +1374,9 @@ sandbox_start_drivers() { if [ -n "${NUT_DEBUG_LEVEL_DRIVERS-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_DRIVERS}" fi - #execcmd upsdrvctl ${ARG_FG} ${ARG_USER} start dummy & - execcmd dummy-ups -a dummy ${ARG_USER} ${ARG_FG} & + # Run one driver instance indirectly, to test the upsdrvctl tool too: + execcmd upsdrvctl ${ARG_FG} ${ARG_USER} start dummy & + #execcmd dummy-ups -a dummy ${ARG_USER} ${ARG_FG} & PID_DUMMYUPS="$!" log_debug "Tried to start dummy-ups driver for 'dummy' as PID $PID_DUMMYUPS" diff --git a/tests/generic_gpio_liblocal.c b/tests/generic_gpio_liblocal.c index 471052d734..6fd1d24570 100644 --- a/tests/generic_gpio_liblocal.c +++ b/tests/generic_gpio_liblocal.c @@ -35,17 +35,20 @@ static unsigned int num_lines=0; static int gStatus = 0; static int errReqFor_line_get_value_bulk=0; -void setNextLinesReadToFail(void) { +void setNextLinesReadToFail(void) +{ errReqFor_line_get_value_bulk=1; } -void gpiod_chip_close(struct gpiod_chip *chip) { +void gpiod_chip_close(struct gpiod_chip *chip) +{ NUT_UNUSED_VARIABLE(chip); } #if WITH_LIBGPIO_VERSION < 0x00020000 -struct gpiod_chip *gpiod_chip_open_by_name(const char *name) { +struct gpiod_chip *gpiod_chip_open_by_name(const char *name) +{ snprintf(chipName, sizeof(chipName), "%s", name); if (strcmp(name, "gpiochip1")) return (struct gpiod_chip *)1; @@ -55,16 +58,18 @@ struct gpiod_chip *gpiod_chip_open_by_name(const char *name) { } } -unsigned int gpiod_chip_num_lines(struct gpiod_chip *chip) { +unsigned int gpiod_chip_num_lines(struct gpiod_chip *chip) +{ NUT_UNUSED_VARIABLE(chip); if (!strcmp(chipName, "gpiochip2")) return 2; return 32; } -int gpiod_chip_get_lines(struct gpiod_chip *chip, - unsigned int *offsets, unsigned int num_offsets, - struct gpiod_line_bulk *bulk) +int gpiod_chip_get_lines( + struct gpiod_chip *chip, + unsigned int *offsets, unsigned int num_offsets, + struct gpiod_line_bulk *bulk) { NUT_UNUSED_VARIABLE(chip); NUT_UNUSED_VARIABLE(offsets); @@ -73,9 +78,10 @@ int gpiod_chip_get_lines(struct gpiod_chip *chip, return 0; } -int gpiod_line_request_bulk(struct gpiod_line_bulk *bulk, - const struct gpiod_line_request_config *config, - const int *default_vals) +int gpiod_line_request_bulk( + struct gpiod_line_bulk *bulk, + const struct gpiod_line_request_config *config, + const int *default_vals) { NUT_UNUSED_VARIABLE(bulk); NUT_UNUSED_VARIABLE(config); @@ -83,8 +89,9 @@ int gpiod_line_request_bulk(struct gpiod_line_bulk *bulk, return 0; } -int gpiod_line_get_value_bulk(struct gpiod_line_bulk *bulk, - int *values) +int gpiod_line_get_value_bulk( + struct gpiod_line_bulk *bulk, + int *values) { unsigned int i; int pinPos = 1; @@ -104,9 +111,10 @@ int gpiod_line_get_value_bulk(struct gpiod_line_bulk *bulk, return 0; } -int gpiod_line_event_wait_bulk(struct gpiod_line_bulk *bulk, - const struct timespec *timeout, - struct gpiod_line_bulk *event_bulk) +int gpiod_line_event_wait_bulk( + struct gpiod_line_bulk *bulk, + const struct timespec *timeout, + struct gpiod_line_bulk *event_bulk) { NUT_UNUSED_VARIABLE(bulk); NUT_UNUSED_VARIABLE(timeout); @@ -131,35 +139,42 @@ int gpiod_line_event_wait_bulk(struct gpiod_line_bulk *bulk, return 0; } -int gpiod_line_event_read(struct gpiod_line *line, - struct gpiod_line_event *event) { +int gpiod_line_event_read( + struct gpiod_line *line, + struct gpiod_line_event *event) +{ NUT_UNUSED_VARIABLE(line); NUT_UNUSED_VARIABLE(event); return 0; } -unsigned int gpiod_line_offset(struct gpiod_line *line) { +unsigned int gpiod_line_offset(struct gpiod_line *line) +{ NUT_UNUSED_VARIABLE(line); return 0; } -void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) { +void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) +{ NUT_UNUSED_VARIABLE(bulk); } #else /* #if WITH_LIBGPIO_VERSION >= 0x00020000 */ struct gpiod_line_request * -gpiod_chip_request_lines(struct gpiod_chip *chip, - struct gpiod_request_config *req_cfg, - struct gpiod_line_config *line_cfg) { +gpiod_chip_request_lines( + struct gpiod_chip *chip, + struct gpiod_request_config *req_cfg, + struct gpiod_line_config *line_cfg) +{ NUT_UNUSED_VARIABLE(chip); NUT_UNUSED_VARIABLE(req_cfg); NUT_UNUSED_VARIABLE(line_cfg); return (struct gpiod_line_request *)1; } -struct gpiod_chip *gpiod_chip_open(const char *path) { +struct gpiod_chip *gpiod_chip_open(const char *path) +{ snprintf(chipName, sizeof(chipName), "%s", path); if (!strstr(path, "gpiochip1")) return (struct gpiod_chip *)1; @@ -169,48 +184,59 @@ struct gpiod_chip *gpiod_chip_open(const char *path) { } } -struct gpiod_chip_info *gpiod_chip_get_info(struct gpiod_chip *chip) { +struct gpiod_chip_info *gpiod_chip_get_info(struct gpiod_chip *chip) +{ NUT_UNUSED_VARIABLE(chip); return (struct gpiod_chip_info *)1; } -size_t gpiod_chip_info_get_num_lines(struct gpiod_chip_info *info) { +size_t gpiod_chip_info_get_num_lines(struct gpiod_chip_info *info) +{ NUT_UNUSED_VARIABLE(info); if(strstr(chipName, "gpiochip2")) return 2; return 32; } -void gpiod_chip_info_free(struct gpiod_chip_info *info) { +void gpiod_chip_info_free(struct gpiod_chip_info *info) +{ NUT_UNUSED_VARIABLE(info); } -struct gpiod_line_settings *gpiod_line_settings_new(void) { +struct gpiod_line_settings *gpiod_line_settings_new(void) +{ return (struct gpiod_line_settings *)1; } -int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings, - enum gpiod_line_direction direction) { +int gpiod_line_settings_set_direction( + struct gpiod_line_settings *settings, + enum gpiod_line_direction direction) +{ NUT_UNUSED_VARIABLE(settings); NUT_UNUSED_VARIABLE(direction); return 0; } -int gpiod_line_settings_set_edge_detection(struct gpiod_line_settings *settings, - enum gpiod_line_edge edge) { +int gpiod_line_settings_set_edge_detection( + struct gpiod_line_settings *settings, + enum gpiod_line_edge edge) +{ NUT_UNUSED_VARIABLE(settings); NUT_UNUSED_VARIABLE(edge); return 0; } -struct gpiod_line_config *gpiod_line_config_new(void) { +struct gpiod_line_config *gpiod_line_config_new(void) +{ return (struct gpiod_line_config *)1; } -int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, - const unsigned int *offsets, - size_t num_offsets, - struct gpiod_line_settings *settings) { +int gpiod_line_config_add_line_settings( + struct gpiod_line_config *config, + const unsigned int *offsets, + size_t num_offsets, + struct gpiod_line_settings *settings) +{ NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(offsets); NUT_UNUSED_VARIABLE(num_offsets); @@ -218,18 +244,23 @@ int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, return 0; } -struct gpiod_request_config *gpiod_request_config_new(void) { +struct gpiod_request_config *gpiod_request_config_new(void) +{ return (struct gpiod_request_config *)1; } -void gpiod_request_config_set_consumer(struct gpiod_request_config *config, - const char *consumer) { +void gpiod_request_config_set_consumer( + struct gpiod_request_config *config, + const char *consumer) +{ NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(consumer); } -int gpiod_line_request_get_values(struct gpiod_line_request *request, - enum gpiod_line_value *values) { +int gpiod_line_request_get_values( + struct gpiod_line_request *request, + enum gpiod_line_value *values) +{ unsigned int i; int pinPos = 1; NUT_UNUSED_VARIABLE(request); @@ -240,7 +271,7 @@ int gpiod_line_request_get_values(struct gpiod_line_request *request, return -1; } for(i=0; iupsLinesStates = xcalloc(upsfdtest->upsLinesCount, sizeof(int)); + upsfdtest->upsLinesStates = (int *)xcalloc(upsfdtest->upsLinesCount, sizeof(int)); for (j=0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } @@ -283,7 +283,7 @@ int main(int argc, char **argv) { char chargeStatus[256]; char chargeLow[256]; char charge[256]; - struct gpioups_t *upsfdtest = xcalloc(1, sizeof(*upsfdtest)); + struct gpioups_t *upsfdtest = (struct gpioups_t *)xcalloc(1, sizeof(*upsfdtest)); int j; /* "volatile" trickery to avoid the likes of: @@ -296,7 +296,7 @@ int main(int argc, char **argv) { const char * volatile currCharge = NULL; get_ups_rules(upsfdtest, (unsigned char *)rules); - upsfdtest->upsLinesStates = xcalloc(upsfdtest->upsLinesCount, sizeof(int)); + upsfdtest->upsLinesStates = (int *)xcalloc(upsfdtest->upsLinesCount, sizeof(int)); for (j = 0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } diff --git a/tests/nut-driver-enumerator-test.sh b/tests/nut-driver-enumerator-test.sh index 93007d7144..10f477c22e 100755 --- a/tests/nut-driver-enumerator-test.sh +++ b/tests/nut-driver-enumerator-test.sh @@ -612,9 +612,11 @@ testcase_semver_compare() { "SEMVER comparison helper: shell-style maths: equality with added trailing zeroed components (and different leading zero pads)" 0 "" \ test 01.02.03 = 1.002.0003.0 + # Note: escaping the double-equals token to keep shell checkers quiet + # about what they can think of as unportable bashism run_testcase_generic callSEMVERCMP \ "SEMVER comparison helper: shell-style maths: (non-)equality with added trailing zero value e.g. 3 vs 30" 1 "" \ - test 01.02.03 == 1.002.00030 + test 01.02.03 \=\= 1.002.00030 run_testcase_generic callSEMVERCMP \ "SEMVER comparison helper: shell-style maths: non-equality with added trailing zeroed components (and different leading zero pads)" 1 "" \ diff --git a/tools/gitlog2version.sh b/tools/gitlog2version.sh index 31cef0deac..01fc08be00 100755 --- a/tools/gitlog2version.sh +++ b/tools/gitlog2version.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (C) 2016-2025 by Jim Klimov +# Copyright (C) 2016-2026 by Jim Klimov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -241,9 +241,13 @@ getver_git() { # Praises to old gits and the new, who may --exclude; # NOTE: match/exclude by shell glob expressions, not regex! - DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null`" \ + DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG --match 'v[0123456789]*.[0123456789]*.[0123456789]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null`" \ && [ -n "${DESC}" ] \ - || DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG | ${EGREP} -v '(rc|-signed|alpha|beta|Windows|IPM)' | ${EGREP} 'v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*'`" + || { # Try our luck with versions before --exclude + DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG --match 'v[0123456789]*.[0123456789]*.[0123456789]' 2>/dev/null`" \ + && [ -n "${DESC}" ] \ + || DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG | ${EGREP} -v '(rc|-signed|alpha|beta|Windows|IPM)' | ${EGREP} 'v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*'`" + } # Old stripper (also for possible refspec parts like "tags/"): # echo "${DESC}" | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,' # Follow https://semver.org/#spec-item-10 about build metadata: diff --git a/tools/nut-scanner/Makefile.am b/tools/nut-scanner/Makefile.am index 628712d3dc..6dd4d4d073 100644 --- a/tools/nut-scanner/Makefile.am +++ b/tools/nut-scanner/Makefile.am @@ -31,7 +31,7 @@ nutscan-usb.h: nutscan-snmp.c # 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 +$(NUT_SCANNER_DEPS): dummy @dotMAKE@ +@cd .. && $(MAKE) $(AM_MAKEFLAGS) nut-scanner-deps # Make sure out-of-dir dependencies exist (especially when dev-building parts): @@ -42,10 +42,10 @@ $(top_builddir)/common/libnutwincompat.la \ $(top_builddir)/drivers/libserial-nutscan.la \ $(top_builddir)/common/libcommonstr.la \ $(top_builddir)/common/libcommonversion.la \ -$(top_builddir)/common/libcommon.la: dummy +$(top_builddir)/common/libcommon.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) -$(top_builddir)/include/nut_version.h: +$(top_builddir)/include/nut_version.h: @dotMAKE@ +@if [ -s '$@' ] && ( [ x"$(NUT_VERSION_H_GENERATED)" = xtrue ] || [ x"$${NUT_VERSION_H_GENERATED}" = xtrue ] ) ; then \ if [ x"$(MAINTAINER_GENERATE_HEADER_DEBUG)" = xyes ] ; then \ echo "=== SKIP (nut-scanner) $@ (NUT_VERSION_H_GENERATED makevar=$(NUT_VERSION_H_GENERATED) shellvar=$${NUT_VERSION_H_GENERATED})" >&2; \ @@ -78,7 +78,7 @@ if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h @@ -137,7 +137,8 @@ libnutscan_la_SOURCES = scan_nut.c scan_nut_simulation.c scan_ipmi.c \ nutscan-snmp.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 + scan_avahi.c scan_eaton_serial.c nutscan-serial.c \ + scan_upower.c libnutscan_la_LIBADD = $(NETLIBS) libnutscan_la_LIBADD += $(top_builddir)/drivers/libserial-nutscan.la @@ -149,10 +150,12 @@ if WITH_LIBLTDL libnutscan_la_LIBADD += $(LIBLTDL_LIBS) endif WITH_LIBLTDL +if WITH_THREADING if HAVE_SEMAPHORE_LIBS # Are additional libraries needed for semaphore support? libnutscan_la_LIBADD += $(SEMLIBS) endif HAVE_SEMAPHORE_LIBS +endif WITH_THREADING libnutscan_la_LIBADD += $(SERLIBS) @@ -172,7 +175,7 @@ libnutscan_la_LDFLAGS += @NETLIBS_GETADDRS@ # object .so names would differ) # # libnutscan version information -libnutscan_la_LDFLAGS += -version-info 4:0:0 +libnutscan_la_LDFLAGS += -version-info 5:0:1 # libnutscan exported symbols regex # WARNING: Since the library includes parts of libcommon (as much as needed @@ -304,6 +307,9 @@ endif WITH_AVAHI if WITH_IPMI libnutscan_la_CFLAGS += $(LIBIPMI_CFLAGS) endif WITH_IPMI +if WITH_UPOWER + libnutscan_la_CFLAGS += $(LIBGIO_CFLAGS) +endif WITH_UPOWER # C is not a header, but there is no dist_noinst_SOURCES dist_noinst_HEADERS += $(NUT_SCANNER_DEPS_H) $(NUT_SCANNER_DEPS_C) diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index 4d481b24d5..1619325e99 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -4,7 +4,7 @@ * 2012 - 2024 Arnaud Quette * 2016 - EATON - IP addressed XML scan * 2016 - 2021 - EATON - Various threads-related improvements - * 2023 - 2024 - Jim Klimov + * 2023 - 2026 - Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,8 +63,25 @@ #include "nutscan-device.h" #include "nutscan-ip.h" -#ifdef WITH_IPMI -#include +#if (defined WITH_IPMI) && WITH_IPMI +# include +#endif + +#ifndef WITH_THREADING +# define WITH_THREADING 0 +#endif + +#if !WITH_THREADING +/* Not detected or actively disabled in configure script */ +# ifdef HAVE_PTHREAD +# undef HAVE_PTHREAD +# endif +# ifdef HAVE_SEMAPHORE_UNNAMED +# undef HAVE_SEMAPHORE_UNNAMED +# endif +# ifdef HAVE_SEMAPHORE_NAMED +# undef HAVE_SEMAPHORE_NAMED +# endif #endif #ifdef HAVE_PTHREAD @@ -208,6 +225,8 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); +nutscan_device_t * nutscan_scan_upower(void); + #ifdef HAVE_PTHREAD # if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Expose shared libnutscan semaphore for overall thread count diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index 3919265b0f..1b2bdf7819 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -2,7 +2,7 @@ * Copyright (C) 2011 - 2024 Arnaud Quette * Copyright (C) 2016 Michal Vyskocil * Copyright (C) 2016 - 2021 Jim Klimov - * Copyright (C) 2022 - 2024 Jim Klimov + * Copyright (C) 2022 - 2026 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -128,7 +128,7 @@ * regardless of WITH_DMFMIB value in the current build; we just handle * them differently. */ -static const char optstring[] = "?ht:T:s:e:E:c:l:u:W:X:w:x:p:b:B:d:L:CUSMOAm:QnNPqIVaDzZ:"; +static const char optstring[] = "?ht:T:s:e:E:c:l:u:W:X:w:x:p:b:B:d:L:CUSMOAm:QnNPqIVaDJzZ:"; #ifdef HAVE_GETOPT_LONG static const struct option longopts[] = { @@ -158,6 +158,7 @@ static const struct option longopts[] = { { "avahi_scan", no_argument, NULL, 'A' }, /* "new" NUT scan where deployed */ { "nut_simulation_scan", no_argument, NULL, 'n' }, { "ipmi_scan", no_argument, NULL, 'I' }, + { "upower_scan", no_argument, NULL, 'J' }, { "disp_nut_conf_with_sanity_check", no_argument, NULL, 'Q' }, { "disp_nut_conf", no_argument, NULL, 'N' }, { "disp_parsable", no_argument, NULL, 'P' }, @@ -186,6 +187,7 @@ static nutscan_ip_range_list_t ip_ranges_list; #ifdef HAVE_PTHREAD static pthread_t thread[TYPE_END]; +#endif /* HAVE_PTHREAD */ static void * run_usb(void *arg) { @@ -240,7 +242,6 @@ static void * run_usb(void *arg) dev[TYPE_USB] = nutscan_scan_usb(scanopts_ptr); return NULL; } -#endif /* HAVE_PTHREAD */ static void * run_snmp(void * arg) { @@ -300,7 +301,7 @@ static void * run_avahi(void *arg) static void * run_ipmi(void * arg) { nutscan_ipmi_t * sec = (nutscan_ipmi_t *)arg; - + upsdebugx(2, "Entering %s for %" PRIuSIZE " IP address range(s)", __func__, ip_ranges_list.ip_ranges_count); @@ -318,6 +319,14 @@ static void * run_eaton_serial(void *arg) return NULL; } +static void * run_upower(void *arg) +{ + NUT_UNUSED_VARIABLE(arg); + + dev[TYPE_UPOWER] = nutscan_scan_upower(); + return NULL; +} + static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) { char *start_ip = NULL, *end_ip = NULL; @@ -1058,6 +1067,11 @@ static void show_usage(const char *arg_progname) } else { printf("* Options for IPMI devices scan not enabled: library not detected.\n"); } + if (nutscan_avail_upower) { + printf(" -J, --upower_scan: Scan UPower devices.\n"); + } else { + printf("* Options for UPower devices scan not enabled: library not detected.\n"); + } printf(" -E, --eaton_serial : Scan serial Eaton devices (XCP, SHUT and Q1).\n"); @@ -1226,6 +1240,7 @@ int main(int argc, char *argv[]) int allow_nut_simulation = 0; int allow_avahi = 0; int allow_ipmi = 0; + int allow_upower = 0; int allow_eaton_serial = 0; /* MUST be requested explicitly! */ int quiet = 0; /* The debugging level for certain upsdebugx() progress messages; 0 = print always, quiet==1 is to require at least one -D */ void (*display_func)(nutscan_device_t * device); @@ -1325,8 +1340,8 @@ int main(int argc, char *argv[]) * max(useconds_t)/1000000 ? */ upsdebugx(0, "Illegal timeout value, using default %ds", - DEFAULT_NETWORK_TIMEOUT); - timeout = DEFAULT_NETWORK_TIMEOUT * 1000 * 1000; + DEFAULT_NETWORK_TIMEOUT); + timeout = DEFAULT_NETWORK_TIMEOUT * 1000 * 1000; } else { timeout = (useconds_t)l * 1000 * 1000; /*in usec*/ } @@ -1346,7 +1361,7 @@ int main(int argc, char *argv[]) start_ip = strdup(optarg + 1); start_ip[strlen(start_ip) - 1] = '\0'; } else { - start_ip = strdup(optarg); + start_ip = strdup(optarg); } if (end_ip != NULL) { @@ -1370,7 +1385,7 @@ int main(int argc, char *argv[]) end_ip = strdup(optarg + 1); end_ip[strlen(end_ip) - 1] = '\0'; } else { - end_ip = strdup(optarg); + end_ip = strdup(optarg); } if (start_ip != NULL) { @@ -1608,6 +1623,12 @@ int main(int argc, char *argv[]) } allow_ipmi = 1; break; + case 'J': + if (!nutscan_avail_upower) { + goto display_help; + } + allow_upower = 1; + break; case 'Q': display_func = nutscan_display_ups_conf_with_sanity_check; break; @@ -1646,6 +1667,9 @@ int main(int argc, char *argv[]) if (nutscan_avail_ipmi) { printf("IPMI\n"); } + if (nutscan_avail_upower) { + printf("UPOWER\n"); + } printf("EATON_SERIAL\n"); exit(EXIT_SUCCESS); case '?': @@ -1688,8 +1712,8 @@ int main(int argc, char *argv[]) # if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* FIXME: Currently sem_init already done on nutscan-init for lib need. - We need to destroy it before re-init. We currently can't change "sem value" - on lib (need to be thread safe). */ + * We need to destroy it before re-init. We currently can't change "sem value" + * on lib (need to be thread safe). */ current_sem = nutscan_semaphore(); # ifdef HAVE_SEMAPHORE_UNNAMED sem_destroy(current_sem); @@ -1752,7 +1776,7 @@ int main(int argc, char *argv[]) } if (!allow_usb && !allow_snmp && !allow_xml && !allow_oldnut && !allow_nut_simulation && - !allow_avahi && !allow_ipmi && !allow_eaton_serial + !allow_avahi && !allow_ipmi && !allow_eaton_serial && !allow_upower ) { allow_all = 1; } @@ -1770,6 +1794,7 @@ int main(int argc, char *argv[]) allow_nut_simulation = 1; allow_avahi = 1; allow_ipmi = 1; + allow_upower = 1; /* BEWARE: allow_all does not include allow_eaton_serial! */ } @@ -1785,8 +1810,7 @@ int main(int argc, char *argv[]) } #else upsdebugx(1, "USB SCAN: no pthread support, starting nutscan_scan_usb..."); - /* Not calling run_usb() here, as it re-processes the arg */ - dev[TYPE_USB] = nutscan_scan_usb(&cli_link_detail_level); + dev[TYPE_USB] = run_usb(&cli_link_detail_level); #endif /* HAVE_PTHREAD */ } else { upsdebugx(1, "USB SCAN: not requested or supported, SKIPPED"); @@ -1846,7 +1870,6 @@ int main(int argc, char *argv[]) upsdebugx(1, "XML/HTTP SCAN: no pthread support, starting nutscan_scan_xml_http_range()..."); /* dev[TYPE_XML] = nutscan_scan_xml_http_range(start_ip, end_ip, timeout, &xml_sec); */ run_xml(&xml_sec); - } #endif /* HAVE_PTHREAD */ } else { upsdebugx(1, "XML/HTTP SCAN: not requested or supported, SKIPPED"); @@ -1884,7 +1907,7 @@ int main(int argc, char *argv[]) nutscan_avail_nut_simulation = 0; } #else - upsdebugx(1, "NUT simulation devices SCAN: no pthread support, starting nutscan_scan_nut_simulation..."); + upsdebugx(1, "NUT simulation devices SCAN: no pthread support, starting nutscan_scan_nut_simulation..."); /* dev[TYPE_NUT_SIMULATION] = nutscan_scan_nut_simulation(); */ run_nut_simulation(NULL); #endif /* HAVE_PTHREAD */ @@ -1931,6 +1954,22 @@ int main(int argc, char *argv[]) upsdebugx(1, "IPMI SCAN: not requested or supported, SKIPPED"); } + if (allow_upower && nutscan_avail_upower) { + upsdebugx(quiet, "Scanning UPower bus."); +#ifdef HAVE_PTHREAD + upsdebugx(1, "UPOWER SCAN: starting pthread_create with run_upower..."); + if (pthread_create(&thread[TYPE_UPOWER], NULL, run_upower, NULL)) { + upsdebugx(1, "pthread_create returned an error; disabling this scan mode"); + nutscan_avail_upower = 0; + } +#else + upsdebugx(1, "UPOWER SCAN: no pthread support, starting nutscan_scan_upower..."); + run_upower(NULL); +#endif /* HAVE_PTHREAD */ + } else { + upsdebugx(1, "UPOWER SCAN: not requested or supported, SKIPPED"); + } + /* Eaton serial scan */ if (allow_eaton_serial) { upsdebugx(quiet, "Scanning serial bus for Eaton devices."); @@ -1978,6 +2017,10 @@ int main(int argc, char *argv[]) upsdebugx(1, "IPMI SCAN: join back the pthread"); pthread_join(thread[TYPE_IPMI], NULL); } + if (allow_upower && nutscan_avail_upower && thread[TYPE_UPOWER]) { + upsdebugx(1, "UPOWER SCAN: join back the pthread"); + pthread_join(thread[TYPE_UPOWER], NULL); + } if (allow_eaton_serial && thread[TYPE_EATON_SERIAL]) { upsdebugx(1, "SERIAL SCAN: join back the pthread"); pthread_join(thread[TYPE_EATON_SERIAL], NULL); @@ -2021,6 +2064,11 @@ int main(int argc, char *argv[]) upsdebugx(1, "SCANS DONE: free resources: IPMI"); nutscan_free_device(dev[TYPE_IPMI]); + upsdebugx(1, "SCANS DONE: display results: UPOWER"); + display_func(dev[TYPE_UPOWER]); + upsdebugx(1, "SCANS DONE: free resources: UPOWER"); + nutscan_free_device(dev[TYPE_UPOWER]); + upsdebugx(1, "SCANS DONE: display results: SERIAL"); display_func(dev[TYPE_EATON_SERIAL]); upsdebugx(1, "SCANS DONE: free resources: SERIAL"); diff --git a/tools/nut-scanner/nutscan-device.c b/tools/nut-scanner/nutscan-device.c index 47b1f6a7fa..b0b9cf6f32 100644 --- a/tools/nut-scanner/nutscan-device.c +++ b/tools/nut-scanner/nutscan-device.c @@ -41,6 +41,7 @@ const char * nutscan_device_type_strings[TYPE_END] = { "IPMI", "Avahi", "serial", + "UPOWER", }; /* lower strings, used for device names */ @@ -54,13 +55,14 @@ const char * nutscan_device_type_lstrings[TYPE_END] = { "ipmi", "avahi", "serial", + "upower", }; nutscan_device_t * nutscan_new_device(void) { nutscan_device_t * device; - device = malloc(sizeof(nutscan_device_t)); + device = (nutscan_device_t*)malloc(sizeof(nutscan_device_t)); if (device == NULL) { return NULL; } diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index 26f47d2ac6..c969f1f755 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -55,7 +55,8 @@ typedef enum nutscan_device_type { TYPE_IPMI, TYPE_AVAHI, TYPE_EATON_SERIAL, - TYPE_END + TYPE_UPOWER, + TYPE_END /* Sentinel; numeric value serves as array size at compile time */ } nutscan_device_type_t; /** Device type -> string mapping */ diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index f486b99198..fdd537859a 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -261,7 +261,7 @@ void nutscan_display_sanity_check_serial(nutscan_device_t * device) */ /* Reserve enough slots for all-unique serials */ - map = calloc(listlen, sizeof(keyval_strings_t)); + map = (keyval_strings_t*)calloc(listlen, sizeof(keyval_strings_t)); if (map == NULL) { upsdebugx(0, "%s: Memory allocation error, skipped", __func__); return; diff --git a/tools/nut-scanner/nutscan-init.c b/tools/nut-scanner/nutscan-init.c index a577bb7496..cdbd2a611e 100644 --- a/tools/nut-scanner/nutscan-init.c +++ b/tools/nut-scanner/nutscan-init.c @@ -58,6 +58,7 @@ int nutscan_avail_nut_simulation = 0; int nutscan_avail_snmp = 0; int nutscan_avail_usb = 0; int nutscan_avail_xml_http = 0; +int nutscan_avail_upower = 0; /* Methods defined in scan_*.c source files */ int nutscan_load_usb_library(const char *libname_path); @@ -72,6 +73,8 @@ int nutscan_load_ipmi_library(const char *libname_path); int nutscan_unload_ipmi_library(void); int nutscan_load_upsclient_library(const char *libname_path); int nutscan_unload_upsclient_library(void); +int nutscan_load_upower_library(const char *libname_path); +int nutscan_unload_upower_library(void); #ifdef HAVE_PTHREAD # ifdef HAVE_SEMAPHORE_UNNAMED @@ -138,7 +141,7 @@ size_t max_threads_ipmi = 0; /* limits not yet known */ #endif /* HAVE_PTHREAD */ #ifdef WIN32 -/* Stub for libupsclient */ +/* Stub for libupsclient, no need to register a callback for ENABLE_SHARED_PRIVATE_LIBS builds */ void do_upsconf_args(char *confupsname, char *var, char *val) { NUT_UNUSED_VARIABLE(confupsname); NUT_UNUSED_VARIABLE(var); @@ -239,7 +242,7 @@ void nutscan_init(void) * known-compatible SOFILE_LIB first. */ -#ifdef WITH_USB +#if (defined WITH_USB) && WITH_USB # if WITH_LIBUSB_1_0 # ifdef SOFILE_LIBUSB1 @@ -347,8 +350,8 @@ void nutscan_init(void) __func__, "LibUSB"); #endif /* WITH_USB */ -#ifdef WITH_SNMP -# ifdef WITH_SNMP_STATIC +#if (defined WITH_SNMP) && WITH_SNMP +# if (defined WITH_SNMP_STATIC) && WITH_SNMP_STATIC /* This is a rare situation, reserved for platforms where libnetsnmp or * equivalent (some other ucd-snmp descendants) was not packaged, and * thus was custom-built for NUT (so linked statically to avoid potential @@ -416,7 +419,7 @@ void nutscan_init(void) __func__, "LibSNMP"); #endif /* WITH_SNMP */ -#ifdef WITH_NEON +#if (defined WITH_NEON) && WITH_NEON # ifdef SOFILE_LIBNEON if (!libname) { libname = get_libname(SOFILE_LIBNEON); @@ -485,7 +488,7 @@ void nutscan_init(void) __func__, "LibNeon"); #endif /* WITH_NEON */ -#ifdef WITH_AVAHI +#if (defined WITH_AVAHI) && WITH_AVAHI # ifdef SOFILE_LIBAVAHI if (!libname) { libname = get_libname(SOFILE_LIBAVAHI); @@ -532,7 +535,57 @@ void nutscan_init(void) __func__, "LibAvahi"); #endif /* WITH_AVAHI */ -#ifdef WITH_FREEIPMI +#if (defined WITH_UPOWER) && WITH_UPOWER +/* NOTE: There may be a stack of libraries involved (libgio, libglib2, + * libmount...) in driver programs, but one entry point suffices + * (and/or dynamically pulls in the others) for just the scan itself */ +# ifdef SOFILE_LIBGIO + if (!libname) { + libname = get_libname(SOFILE_LIBGIO); + } +# endif /* SOFILE_LIBGIO */ + if (!libname) { + libname = get_libname("libgio-2.0" SOEXT); + } +# ifdef SOPATH_LIBGIO + if (!libname) { + libname = get_libname(SOPATH_LIBGIO); + } +# endif /* SOPATH_LIBGIO */ + + if (libname) { + upsdebugx(1, "%s: get_libname() resolved '%s' for %s, loading it", + __func__, libname, "LibGIO"); + nutscan_avail_upower = nutscan_load_upower_library(libname); + free(libname); + libname = NULL; + } else { + /* let libtool (lt_dlopen) do its default magic maybe better */ + upsdebugx(1, "%s: get_libname() did not resolve libname for %s, " + "trying to load it with libtool default resolver", + __func__, "LibGIO"); +# ifdef SOFILE_LIBGIO + if (!nutscan_avail_upower) { + nutscan_avail_upower = nutscan_load_upower_library(SOFILE_LIBGIO); + } +# endif /* SOFILE_LIBGIO */ + if (!nutscan_avail_upower) { + nutscan_avail_upower = nutscan_load_upower_library("libgio-2.0" SOEXT); + } +# ifdef SOPATH_LIBGIO + if (!nutscan_avail_upower) { + nutscan_avail_upower = nutscan_load_upower_library(SOPATH_LIBGIO); + } +# endif /* SOPATH_LIBGIO */ + } + upsdebugx(1, "%s: %s to load the library for %s", + __func__, nutscan_avail_upower ? "succeeded" : "failed", "LibGIO"); +#else /* not WITH_UPOWER */ + upsdebugx(1, "%s: skipped loading the library for %s: was absent during NUT build", + __func__, "LibGIO"); +#endif /* WITH_UPOWER */ + +#if (defined WITH_FREEIPMI) && WITH_FREEIPMI # ifdef SOFILE_LIBFREEIPMI if (!libname) { libname = get_libname(SOFILE_LIBFREEIPMI); @@ -662,7 +715,7 @@ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath) } /* if previous init failed */ - if (*pdl_handle == (void *)1) { + if (*pdl_handle == (lt_dlhandle)1) { goto end; } @@ -703,6 +756,7 @@ void nutscan_free(void) nutscan_unload_avahi_library(); nutscan_unload_ipmi_library(); nutscan_unload_upsclient_library(); + nutscan_unload_upower_library(); #ifdef HAVE_PTHREAD /* TOTHINK: See comments near mutex/semaphore init code above */ diff --git a/tools/nut-scanner/nutscan-init.h b/tools/nut-scanner/nutscan-init.h index b9531b1cdc..b8306c50f8 100644 --- a/tools/nut-scanner/nutscan-init.h +++ b/tools/nut-scanner/nutscan-init.h @@ -39,6 +39,7 @@ extern int nutscan_avail_nut_simulation; extern int nutscan_avail_snmp; extern int nutscan_avail_usb; extern int nutscan_avail_xml_http; +extern int nutscan_avail_upower; void nutscan_init(void); void nutscan_free(void); diff --git a/tools/nut-scanner/nutscan-ip.c b/tools/nut-scanner/nutscan-ip.c index 60ee7b5c8b..a4439bdbdc 100644 --- a/tools/nut-scanner/nutscan-ip.c +++ b/tools/nut-scanner/nutscan-ip.c @@ -149,16 +149,16 @@ size_t nutscan_add_ip_range(nutscan_ip_range_list_t *irl, char * start_ip, char if (start_ip == NULL) { upsdebugx(5, "%s: only end address was provided, setting start to same: %s", - __func__, end_ip); + __func__, end_ip); start_ip = end_ip; } if (end_ip == NULL) { upsdebugx(5, "%s: only start address was provided, setting end to same: %s", - __func__, start_ip); + __func__, start_ip); end_ip = start_ip; } - p = xcalloc(1, sizeof(nutscan_ip_range_t)); + p = (nutscan_ip_range_t*)xcalloc(1, sizeof(nutscan_ip_range_t)); if (start_ip == end_ip || strcmp(start_ip, end_ip) <= 0) { p->start_ip = start_ip; @@ -465,7 +465,7 @@ char * nutscan_ip_iter_inc(nutscan_ip_iter_t * ip) return NULL; } /* increment the address (need to pass address in host - byte order, then pass back in network byte order */ + * byte order, then pass back in network byte order */ ip->start.s_addr = htonl((ntohl(ip->start.s_addr) + 1)); if (ntop(&ip->start, host, sizeof(host)) != 0) { diff --git a/tools/nut-scanner/nutscan-serial.c b/tools/nut-scanner/nutscan-serial.c index 2aa8739a08..aeadc68903 100644 --- a/tools/nut-scanner/nutscan-serial.c +++ b/tools/nut-scanner/nutscan-serial.c @@ -115,7 +115,7 @@ static char ** add_port(char ** list, char * port) /*+1 to get the number of port from the index nb_ports*/ /*+1 for the terminal NULL */ - res = realloc(list, sizeof(char*) * (count + 1 + 1)); + res = (char**)realloc(list, sizeof(char*) * (count + 1 + 1)); if (res == NULL) { upsdebugx(0, "%s: Failed to realloc port list", __func__); return list; diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index 4760368c15..66f9b6f16c 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2011-2024 Arnaud Quette (Design and part of implementation) * Copyright (C) 2011 - EATON - * Copyright (C) 2020-2024 - Jim Klimov - support and modernization of codebase + * Copyright (C) 2020-2026 - Jim Klimov - support and modernization of codebase * * 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 @@ -30,7 +30,7 @@ /* externally visible to nutscan-init */ int nutscan_unload_avahi_library(void); -#ifdef WITH_AVAHI +#if (defined WITH_AVAHI) && WITH_AVAHI #include #include @@ -108,9 +108,11 @@ int nutscan_unload_avahi_library(void) int nutscan_load_avahi_library(const char *libname_path); int nutscan_load_avahi_library(const char *libname_path) { + char *symbol = NULL; + if (dl_handle != NULL) { /* if previous init failed */ - if (dl_handle == (void *)1) { + if (dl_handle == (lt_dlhandle)1) { return 0; } /* init has already been done */ @@ -133,99 +135,122 @@ int nutscan_load_avahi_library(const char *libname_path) goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); - *(void **) (&nut_avahi_service_browser_get_client) = lt_dlsym(dl_handle, "avahi_service_browser_get_client"); + *(void **) (&nut_avahi_service_browser_get_client) = lt_dlsym(dl_handle, + symbol = "avahi_service_browser_get_client"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_simple_poll_loop) = lt_dlsym(dl_handle, "avahi_simple_poll_loop"); + *(void **) (&nut_avahi_simple_poll_loop) = lt_dlsym(dl_handle, + symbol = "avahi_simple_poll_loop"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_client_free) = lt_dlsym(dl_handle, "avahi_client_free"); + *(void **) (&nut_avahi_client_free) = lt_dlsym(dl_handle, + symbol = "avahi_client_free"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_client_errno) = lt_dlsym(dl_handle, "avahi_client_errno"); + *(void **) (&nut_avahi_client_errno) = lt_dlsym(dl_handle, + symbol = "avahi_client_errno"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_free) = lt_dlsym(dl_handle, "avahi_free"); + *(void **) (&nut_avahi_free) = lt_dlsym(dl_handle, + symbol = "avahi_free"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_simple_poll_quit) = lt_dlsym(dl_handle, "avahi_simple_poll_quit"); + *(void **) (&nut_avahi_simple_poll_quit) = lt_dlsym(dl_handle, + symbol = "avahi_simple_poll_quit"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_client_new) = lt_dlsym(dl_handle, "avahi_client_new"); + *(void **) (&nut_avahi_client_new) = lt_dlsym(dl_handle, + symbol = "avahi_client_new"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_simple_poll_free) = lt_dlsym(dl_handle, "avahi_simple_poll_free"); + *(void **) (&nut_avahi_simple_poll_free) = lt_dlsym(dl_handle, + symbol = "avahi_simple_poll_free"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_service_resolver_new) = lt_dlsym(dl_handle, "avahi_service_resolver_new"); + *(void **) (&nut_avahi_service_resolver_new) = lt_dlsym(dl_handle, + symbol = "avahi_service_resolver_new"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_strerror) = lt_dlsym(dl_handle, "avahi_strerror"); + *(void **) (&nut_avahi_strerror) = lt_dlsym(dl_handle, + symbol = "avahi_strerror"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_service_resolver_get_client) = lt_dlsym(dl_handle, "avahi_service_resolver_get_client"); + *(void **) (&nut_avahi_service_resolver_get_client) = lt_dlsym(dl_handle, + symbol = "avahi_service_resolver_get_client"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_service_browser_new) = lt_dlsym(dl_handle, "avahi_service_browser_new"); + *(void **) (&nut_avahi_service_browser_new) = lt_dlsym(dl_handle, + symbol = "avahi_service_browser_new"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_service_resolver_free) = lt_dlsym(dl_handle, "avahi_service_resolver_free"); + *(void **) (&nut_avahi_service_resolver_free) = lt_dlsym(dl_handle, + symbol = "avahi_service_resolver_free"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_simple_poll_new) = lt_dlsym(dl_handle, "avahi_simple_poll_new"); + *(void **) (&nut_avahi_simple_poll_new) = lt_dlsym(dl_handle, + symbol = "avahi_simple_poll_new"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_string_list_to_string) = lt_dlsym(dl_handle, "avahi_string_list_to_string"); + *(void **) (&nut_avahi_string_list_to_string) = lt_dlsym(dl_handle, + symbol = "avahi_string_list_to_string"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_service_browser_free) = lt_dlsym(dl_handle, "avahi_service_browser_free"); + *(void **) (&nut_avahi_service_browser_free) = lt_dlsym(dl_handle, + symbol = "avahi_service_browser_free"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_address_snprint) = lt_dlsym(dl_handle, "avahi_address_snprint"); + *(void **) (&nut_avahi_address_snprint) = lt_dlsym(dl_handle, + symbol = "avahi_address_snprint"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_avahi_simple_poll_get) = lt_dlsym(dl_handle, "avahi_simple_poll_get"); + *(void **) (&nut_avahi_simple_poll_get) = lt_dlsym(dl_handle, + symbol = "avahi_simple_poll_get"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -234,9 +259,13 @@ int nutscan_load_avahi_library(const char *libname_path) err: upsdebugx(0, - "Cannot load AVAHI library (%s) : %s. AVAHI search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load AVAHI library (%s) : %s%s%s%s. AVAHI search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -312,7 +341,7 @@ static void update_device(const char * host_name, const char *ip, uint16_t port, buf_size = strlen(device) + strlen(host_name) + 5 + 1 + 1 + 1; - dev->port = malloc(buf_size); + dev->port = (char*)malloc(buf_size); if (dev->port) { snprintf(dev->port, buf_size, "%s@%s:%" PRIu16, device, host_name, port); @@ -321,7 +350,7 @@ static void update_device(const char * host_name, const char *ip, uint16_t port, else { /*+1+1 is for '@' character and terminating 0 */ buf_size = strlen(device) + strlen(host_name) + 1 + 1; - dev->port = malloc(buf_size); + dev->port = (char*)malloc(buf_size); if (dev->port) { snprintf(dev->port, buf_size, "%s@%s", device, host_name); @@ -363,7 +392,7 @@ static void update_device(const char * host_name, const char *ip, uint16_t 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); + dev->port = (char*)malloc(buf_size); if (dev->port) { snprintf(dev->port, buf_size, "%s:%s", host_name, buf); @@ -488,7 +517,7 @@ static void browse_callback( void* userdata) { - AvahiClient *c = userdata; + AvahiClient *c = (AvahiClient*)userdata; assert(b); NUT_UNUSED_VARIABLE(flags); @@ -508,9 +537,9 @@ static void browse_callback( /* upsdebugx(1, "%s: "(Browser) NEW: service '%s' of type '%s' in domain '%s'", __func__, name, type, domain); */ /* We ignore the returned resolver object. In the callback - function we free it. If the server is terminated before - the callback function is called the server will free - the resolver for us. */ + * function we free it. If the server is terminated before + * 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 @@ -521,7 +550,7 @@ static void browse_callback( * 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))) + if (!((*nut_avahi_service_resolver_new)(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, resolve_callback, c))) #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) # pragma GCC diagnostic pop #endif @@ -599,7 +628,7 @@ static AvahiClient* wrap_nut_avahi_client_new(int *error) * but lacks a value in that enum for lack of flags (unconstrained * lookup). So we have to silence a warning here... */ - return (*nut_avahi_client_new)((*nut_avahi_simple_poll_get)(simple_poll), 0, client_callback, NULL, error); + return (*nut_avahi_client_new)((*nut_avahi_simple_poll_get)(simple_poll), (AvahiClientFlags)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 @@ -646,7 +675,8 @@ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout) /* 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)) + "_upsd._tcp", NULL, (AvahiLookupFlags)0, + browse_callback, client)) ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM) # pragma GCC diagnostic pop diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c index 1401dd42ac..bd39453e25 100644 --- a/tools/nut-scanner/scan_eaton_serial.c +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -135,7 +135,7 @@ unsigned char calc_checksum(const unsigned char *buf) * return 1 if OK, 0 otherwise */ static int shut_synchronise(TYPE_FD_SER arg_upsfd) { - int try; + int try_num; unsigned char reply = '\0'; /* FIXME? Should we save "arg_upsfd" into global "upsfd" variable? * This was previously shadowed by function argument named "upsfd"... @@ -143,7 +143,7 @@ static int shut_synchronise(TYPE_FD_SER arg_upsfd) /* upsfd = arg_upsfd; */ /* Sync with the UPS according to notification */ - for (try = 0; try < MAX_TRY; try++) { + for (try_num = 0; try_num < MAX_TRY; try_num++) { if ((ser_send_char(arg_upsfd, SHUT_SYNC)) == -1) { continue; } @@ -417,6 +417,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) char *current_port_name = NULL; char **serial_ports_list; int current_port_nb; + size_t i; #ifdef HAVE_PTHREAD # if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) @@ -428,7 +429,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) # endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; - size_t thread_count = 0, i; + size_t thread_count = 0; pthread_mutex_init(&dev_mutex, NULL); #endif /* HAVE_PTHREAD */ @@ -477,7 +478,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) sem_wait(semaphore); pass = TRUE; } else { - pass = (sem_trywait(semaphore) == 0); + pass = (sem_trywait(semaphore) == 0) ? TRUE : FALSE; } # else # ifdef HAVE_PTHREAD_TRYJOIN @@ -562,7 +563,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) # endif /* HAVE_PTHREAD_TRYJOIN */ thread_count++; - new_thread_array = realloc(thread_array, + new_thread_array = (nutscan_thread_t*)realloc(thread_array, thread_count * sizeof(nutscan_thread_t)); if (new_thread_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread array", __func__); diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 9764be8a6d..c7afdb4268 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -2,7 +2,7 @@ * Copyright (C) * 2011 - 2012 Arnaud Quette * 2016 - 2021 EATON - Various threads-related improvements - * 2020 - 2024 Jim Klimov + * 2020 - 2026 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ /* externally visible to nutscan-init */ int nutscan_unload_ipmi_library(void); -#ifdef WITH_IPMI +#if (defined WITH_IPMI) && WITH_IPMI #include #include @@ -150,9 +150,11 @@ int nutscan_unload_ipmi_library(void) int nutscan_load_ipmi_library(const char *libname_path); int nutscan_load_ipmi_library(const char *libname_path) { + char *symbol = NULL; + if (dl_handle != NULL) { /* if previous init failed */ - if (dl_handle == (void *)1) { + if (dl_handle == (lt_dlhandle)1) { return 0; } /* init has already been done */ @@ -175,104 +177,127 @@ int nutscan_load_ipmi_library(const char *libname_path) goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); - *(void **) (&nut_ipmi_fru_close_device_id) = lt_dlsym(dl_handle, IPMI_FRU_CLOSE_DEVICE_ID); + *(void **) (&nut_ipmi_fru_close_device_id) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_CLOSE_DEVICE_ID); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_ctx_destroy) = lt_dlsym(dl_handle, IPMI_FRU_CTX_DESTROY); + *(void **) (&nut_ipmi_fru_ctx_destroy) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_CTX_DESTROY); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } #ifdef HAVE_FREEIPMI_11X_12X - *(void **) (&nut_ipmi_sdr_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_ctx_destroy"); + *(void **) (&nut_ipmi_sdr_ctx_destroy) = lt_dlsym(dl_handle, + symbol = "ipmi_sdr_ctx_destroy"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } #else /* HAVE_FREEIPMI_11X_12X */ - *(void **) (&nut_ipmi_sdr_cache_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_cache_ctx_destroy"); + *(void **) (&nut_ipmi_sdr_cache_ctx_destroy) = lt_dlsym(dl_handle, + symbol = "ipmi_sdr_cache_ctx_destroy"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_sdr_parse_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_sdr_parse_ctx_destroy"); + *(void **) (&nut_ipmi_sdr_parse_ctx_destroy) = lt_dlsym(dl_handle, + symbol = "ipmi_sdr_parse_ctx_destroy"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } #endif /* HAVE_FREEIPMI_11X_12X */ - *(void **) (&nut_ipmi_fru_ctx_create) = lt_dlsym(dl_handle, IPMI_FRU_CTX_CREATE); + *(void **) (&nut_ipmi_fru_ctx_create) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_CTX_CREATE); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_ctx_set_flags) = lt_dlsym(dl_handle, IPMI_FRU_CTX_SET_FLAGS); + *(void **) (&nut_ipmi_fru_ctx_set_flags) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_CTX_SET_FLAGS); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_open_device_id) = lt_dlsym(dl_handle, IPMI_FRU_OPEN_DEVICE_ID); + *(void **) (&nut_ipmi_fru_open_device_id) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_OPEN_DEVICE_ID); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_ctx_errormsg) = lt_dlsym(dl_handle, IPMI_FRU_CTX_ERRORMSG); + *(void **) (&nut_ipmi_fru_ctx_errormsg) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_CTX_ERRORMSG); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_read_data_area) = lt_dlsym(dl_handle, IPMI_FRU_READ_DATA_AREA); + *(void **) (&nut_ipmi_fru_read_data_area) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_READ_DATA_AREA); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_fru_next) = lt_dlsym(dl_handle, IPMI_FRU_PARSE_NEXT); + *(void **) (&nut_ipmi_fru_next) = lt_dlsym(dl_handle, + symbol = IPMI_FRU_PARSE_NEXT); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_create) = lt_dlsym(dl_handle, "ipmi_ctx_create"); + *(void **) (&nut_ipmi_ctx_create) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_create"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_find_inband) = lt_dlsym(dl_handle, "ipmi_ctx_find_inband"); + *(void **) (&nut_ipmi_ctx_find_inband) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_find_inband"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_open_outofband) = lt_dlsym(dl_handle, "ipmi_ctx_open_outofband"); + *(void **) (&nut_ipmi_ctx_open_outofband) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_open_outofband"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_errnum) = lt_dlsym(dl_handle, "ipmi_ctx_errnum"); + *(void **) (&nut_ipmi_ctx_errnum) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_errnum"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_ctx_errormsg"); + *(void **) (&nut_ipmi_ctx_errormsg) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_errormsg"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_close) = lt_dlsym(dl_handle, "ipmi_ctx_close"); + *(void **) (&nut_ipmi_ctx_close) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_close"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_ipmi_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_ctx_destroy"); + *(void **) (&nut_ipmi_ctx_destroy) = lt_dlsym(dl_handle, + symbol = "ipmi_ctx_destroy"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -281,9 +306,13 @@ int nutscan_load_ipmi_library(const char *libname_path) err: upsdebugx(0, - "Cannot load IPMI library (%s) : %s. IPMI search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load IPMI library (%s) : %s%s%s%s. IPMI search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -295,33 +324,39 @@ int nutscan_load_ipmi_library(const char *libname_path) /* Cleanup IPMI contexts */ #ifdef HAVE_FREEIPMI_11X_12X -static void nut_freeipmi_cleanup(ipmi_fru_parse_ctx_t fru_parse_ctx, - ipmi_sdr_ctx_t sdr_ctx) +static void nut_freeipmi_cleanup( + ipmi_fru_parse_ctx_t fru_parse_ctx, + ipmi_sdr_ctx_t sdr_ctx) #else /* HAVE_FREEIPMI_11X_12X */ -static void nut_freeipmi_cleanup(ipmi_fru_parse_ctx_t fru_parse_ctx, - ipmi_sdr_cache_ctx_t sdr_cache_ctx, - ipmi_sdr_parse_ctx_t sdr_parse_ctx) +static void nut_freeipmi_cleanup( + ipmi_fru_parse_ctx_t fru_parse_ctx, + ipmi_sdr_cache_ctx_t sdr_cache_ctx, + ipmi_sdr_parse_ctx_t sdr_parse_ctx) #endif /* HAVE_FREEIPMI_11X_12X */ { if (fru_parse_ctx) { (*nut_ipmi_fru_close_device_id) (fru_parse_ctx); (*nut_ipmi_fru_ctx_destroy) (fru_parse_ctx); + fru_parse_ctx = NULL; } #ifdef HAVE_FREEIPMI_11X_12X if (sdr_ctx) { (*nut_ipmi_sdr_ctx_destroy) (sdr_ctx); + sdr_ctx = NULL; } #else /* HAVE_FREEIPMI_11X_12X */ if (sdr_cache_ctx) { (*nut_ipmi_sdr_cache_ctx_destroy) (sdr_cache_ctx); + sdr_cache_ctx = NULL; } if (sdr_parse_ctx) { (*nut_ipmi_sdr_parse_ctx_destroy) (sdr_parse_ctx); + sdr_parse_ctx = NULL; } #endif /* HAVE_FREEIPMI_11X_12X */ @@ -385,11 +420,13 @@ static int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); /* parse FRU buffer */ - if ((*nut_ipmi_fru_read_data_area) (fru_parse_ctx, - &area_type, - &area_length, - areabuf, - IPMI_FRU_AREA_SIZE_MAX) < 0) + if ((*nut_ipmi_fru_read_data_area) ( + fru_parse_ctx, + &area_type, + &area_length, + areabuf, + IPMI_FRU_AREA_SIZE_MAX + ) < 0) { #ifdef HAVE_FREEIPMI_11X_12X nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); @@ -461,15 +498,16 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t upsdebugx(0, "%s: IPMI scan: %s", __func__, ipmi_ctx_strerror (IPMI_ERR_PERMISSION)); } */ - if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, - NULL, - 0, /* don't disable auto-probe */ - 0, - 0, - NULL, - 0, /* workaround flags, none by default */ - 0 /* flags */ - )) < 0) + if ((ret = (*nut_ipmi_ctx_find_inband) ( + ipmi_ctx, + NULL, + 0, /* don't disable auto-probe */ + 0, + 0, + NULL, + 0, /* workaround flags, none by default */ + 0 /* flags */ + )) < 0) { upsdebugx(2, "ipmi_ctx_find_inband (local scan): %s", (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); @@ -495,18 +533,19 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * upsdebugx(0, "%s: Config File Error: k_g input formatted incorrectly", __func__); * exit (EXIT_FAILURE); * }*/ - if ((ret = (*nut_ipmi_ctx_open_outofband_2_0) (ipmi_ctx, - IPaddr, - 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->privilege_level, - ipmi_sec->cipher_suite_id, - IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, - IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, - ipmi_dev->workaround_flags, - flags) < 0) + if ((ret = (*nut_ipmi_ctx_open_outofband_2_0) ( + ipmi_ctx, + IPaddr, + 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->privilege_level, + ipmi_sec->cipher_suite_id, + IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, + IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, + ipmi_dev->workaround_flags, + flags) < 0) { upsdebugx(2, "nut_ipmi_ctx_open_outofband_2_0 (%s): %s", IPaddr, (*nut_ipmi_ctx_errormsg) (c->ipmi_ctx)); @@ -572,33 +611,37 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t IPaddr, ipmi_sec->privilege_level); return 0; } - if ((ret = (*nut_ipmi_ctx_open_outofband) (ipmi_ctx, - IPaddr, - ipmi_sec->username, - ipmi_sec->password, - (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, - IPMI_FLAGS_DEFAULT - )) < 0) + if ((ret = (*nut_ipmi_ctx_open_outofband) ( + ipmi_ctx, + IPaddr, + ipmi_sec->username, + ipmi_sec->password, + (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, + IPMI_FLAGS_DEFAULT + )) < 0) { - /* No IPMI device detected on this host! - if ((*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_USERNAME_INVALID + if ( (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_USERNAME_INVALID || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_AUTHENTICATION_TYPE_UNAVAILABLE || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID - || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) { */ + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT + ) { + upsdebugx(3, "nut_ipmi_ctx_open_outofband (%s): " + "No IPMI device detected on this host!", + IPaddr); + } - /* FIXME: don't log timeout errors */ - upsdebugx(2, "nut_ipmi_ctx_open_outofband (%s): %s", - IPaddr, (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); - return NULL; - /*}*/ + /* FIXME: don't log timeout errors */ + upsdebugx(2, "nut_ipmi_ctx_open_outofband (%s): %s", + IPaddr, (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); + return NULL; } } @@ -630,8 +673,8 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * using drivers/libfreeipmi_get_board_info() */ current_nut_dev = nutscan_add_device_to_device( - current_nut_dev, - nut_dev); + current_nut_dev, + nut_dev); memset (port_id, 0, sizeof(port_id)); } @@ -641,6 +684,7 @@ nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t if (ipmi_ctx) { (*nut_ipmi_ctx_close) (ipmi_ctx); (*nut_ipmi_ctx_destroy) (ipmi_ctx); + ipmi_ctx = NULL; } return current_nut_dev; @@ -841,7 +885,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut */ int stwST = sem_trywait(semaphore_scantype); int stwS = sem_trywait(semaphore); - pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); + pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0) ? TRUE : FALSE; upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE " thread_count=%" PRIuSIZE @@ -929,7 +973,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut #endif /* HAVE_PTHREAD */ if (pass) { - tmp_sec = malloc(sizeof(nutscan_ipmi_t)); + tmp_sec = (nutscan_ipmi_t*)malloc(sizeof(nutscan_ipmi_t)); if (tmp_sec == NULL) { upsdebugx(0, "%s: Memory allocation error", __func__); break; @@ -947,7 +991,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut # endif /* HAVE_PTHREAD_TRYJOIN */ thread_count++; - new_thread_array = realloc(thread_array, + new_thread_array = (nutscan_thread_t*)realloc(thread_array, thread_count * sizeof(nutscan_thread_t)); if (new_thread_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread array", __func__); diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 9321d96a62..acdaa16c47 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -2,7 +2,7 @@ * Copyright (C) 2011 - 2023 Arnaud Quette (Design and part of implementation) * Copyright (C) 2011 - EATON * Copyright (C) 2016-2021 - EATON - Various threads-related improvements - * Copyright (C) 2020-2024 - Jim Klimov - support and modernization of codebase + * Copyright (C) 2020-2026 - Jim Klimov - support and modernization of codebase * * 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 @@ -86,10 +86,12 @@ int nutscan_unload_upsclient_library(void) int nutscan_load_upsclient_library(const char *libname_path); int nutscan_load_upsclient_library(const char *libname_path) { + char *symbol = NULL; + if (dl_handle != NULL) { /* if previous init failed */ - if (dl_handle == (void *)1) { - return 0; + if (dl_handle == (lt_dlhandle)1) { + return 0; } /* init has already been done */ return 1; @@ -111,39 +113,44 @@ int nutscan_load_upsclient_library(const char *libname_path) goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); *(void **) (&nut_upscli_splitaddr) = lt_dlsym(dl_handle, - "upscli_splitaddr"); + symbol = "upscli_splitaddr"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_upscli_tryconnect) = lt_dlsym(dl_handle, - "upscli_tryconnect"); + symbol = "upscli_tryconnect"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_upscli_list_start) = lt_dlsym(dl_handle, - "upscli_list_start"); + symbol = "upscli_list_start"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_upscli_list_next) = lt_dlsym(dl_handle, - "upscli_list_next"); + symbol = "upscli_list_next"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_upscli_disconnect) = lt_dlsym(dl_handle, - "upscli_disconnect"); + symbol = "upscli_disconnect"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -152,9 +159,13 @@ int nutscan_load_upsclient_library(const char *libname_path) err: upsdebugx(0, - "Cannot load NUT library (%s) : %s. NUT search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load NUT library (%s) : %s%s%s%s. NUT search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -179,7 +190,7 @@ static void * list_nut_devices_thready(void * arg) const char *query[4]; char **answer = NULL; char *hostname = NULL; - UPSCONN_t *ups = xcalloc(1, sizeof(*ups)); + UPSCONN_t *ups = (UPSCONN_t*)xcalloc(1, sizeof(*ups)); nutscan_device_t * dev = NULL; size_t buf_size; @@ -193,6 +204,7 @@ static void * list_nut_devices_thready(void * arg) if ((*nut_upscli_splitaddr)(target_hostname, &hostname, &port) != 0) { /* Avoid disconnect from not connected ups */ + upsdebugx(4, "%s: upscli_splitaddr() failed", __func__); if (ups) { if (ups->host) free(ups->host); @@ -204,6 +216,7 @@ static void * list_nut_devices_thready(void * arg) if ((*nut_upscli_tryconnect)(ups, hostname, port, UPSCLI_CONN_TRYSSL, &tv) < 0) { /* Avoid disconnect from not connected ups */ + upsdebugx(4, "%s: upscli_tryconnect() failed", __func__); if (ups) { if (ups->host) free(ups->host); @@ -214,12 +227,14 @@ static void * list_nut_devices_thready(void * arg) } if ((*nut_upscli_list_start)(ups, numq, query) < 0) { + upsdebugx(4, "%s: upscli_list_start() failed", __func__); goto end; } while ((*nut_upscli_list_next)(ups, numq, query, &numa, &answer) == 1) { /* UPS */ if (numa < 3) { + upsdebugx(4, "%s: upscli_list_next() failed", __func__); goto end; } @@ -243,7 +258,7 @@ static void * list_nut_devices_thready(void * arg) buf_size += 6; } - dev->port = malloc(buf_size); + dev->port = (char*)malloc(buf_size); if (dev->port) { /* Check if IPv6 and needs brackets */ @@ -463,7 +478,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons */ int stwST = sem_trywait(semaphore_scantype); int stwS = sem_trywait(semaphore); - pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); + pass = (((max_threads_scantype == 0) || (stwST == 0)) && (stwS == 0)) ? TRUE : FALSE; upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE " thread_count=%" PRIuSIZE @@ -565,7 +580,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons ip_dest = strdup(ip_str); } - if ((nut_arg = malloc(sizeof(struct scan_nut_arg))) == NULL) { + if ((nut_arg = (struct scan_nut_arg*)malloc(sizeof(struct scan_nut_arg))) == NULL) { upsdebugx(0, "%s: Memory allocation error", __func__); free(ip_dest); break; @@ -583,7 +598,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons # endif /* HAVE_PTHREAD_TRYJOIN */ thread_count++; - new_thread_array = realloc(thread_array, + new_thread_array = (nutscan_thread_t*)realloc(thread_array, thread_count * sizeof(nutscan_thread_t)); if (new_thread_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread array", __func__); diff --git a/tools/nut-scanner/scan_nut_simulation.c b/tools/nut-scanner/scan_nut_simulation.c index e0b39f7c2f..8cf9b352c7 100644 --- a/tools/nut-scanner/scan_nut_simulation.c +++ b/tools/nut-scanner/scan_nut_simulation.c @@ -42,7 +42,7 @@ nutscan_device_t * nutscan_scan_nut_simulation(void) nutscan_device_t * dev = NULL; const char *dirname = confpath(); -#if HAVE_PTHREAD +#ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); #endif /* HAVE_PTHREAD */ @@ -85,7 +85,7 @@ nutscan_device_t * nutscan_scan_nut_simulation(void) } closedir(dp); -#if HAVE_PTHREAD +#ifdef HAVE_PTHREAD pthread_mutex_destroy(&dev_mutex); #endif /* HAVE_PTHREAD */ diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index e004ceffca..6dc8e23240 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 - EATON * Copyright (C) 2016-2021 - EATON - Various threads-related improvements - * Copyright (C) 2020-2024 - Jim Klimov - support and modernization of codebase + * Copyright (C) 2020-2026 - Jim Klimov - support and modernization of codebase * * 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 @@ -33,7 +33,7 @@ /* externally visible to nutscan-init */ int nutscan_unload_snmp_library(void); -#ifdef WITH_SNMP +#if (defined WITH_SNMP) && WITH_SNMP #ifndef WIN32 # include @@ -271,7 +271,7 @@ int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); #endif int nutscan_unload_snmp_library(void) { -#ifdef WITH_SNMP_STATIC +#if (defined WITH_SNMP_STATIC) && WITH_SNMP_STATIC return 0; #else nut_initialized_snmp = 0; @@ -359,7 +359,7 @@ int init_snmp_device_table(void) int nutscan_load_snmp_library(const char *libname_path); int nutscan_load_snmp_library(const char *libname_path) { -#ifdef WITH_SNMP_STATIC +#if (defined WITH_SNMP_STATIC) && WITH_SNMP_STATIC /* With MinGW, the netsnmp library may be linked statically (no dll) */ NUT_UNUSED_VARIABLE(libname_path); @@ -371,72 +371,75 @@ int nutscan_load_snmp_library(const char *libname_path) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # endif - *(void **) (&nut_init_snmp) = init_snmp; + *(void **) (&nut_init_snmp) = + init_snmp; *(void **) (&nut_snmp_sess_init) = - snmp_sess_init; + snmp_sess_init; *(void **) (&nut_snmp_sess_open) = - snmp_sess_open; + snmp_sess_open; *(void **) (&nut_snmp_sess_close) = - snmp_sess_close; + snmp_sess_close; *(void **) (&nut_snmp_sess_session) = - snmp_sess_session; + snmp_sess_session; *(void **) (&nut_snmp_parse_oid) = - snmp_parse_oid; + snmp_parse_oid; *(void **) (&nut_snmp_pdu_create) = - snmp_pdu_create; + snmp_pdu_create; *(void **) (&nut_snmp_add_null_var) = - snmp_add_null_var; + snmp_add_null_var; *(void **) (&nut_snmp_sess_synch_response) = - snmp_sess_synch_response; + snmp_sess_synch_response; *(void **) (&nut_snmp_oid_compare) = - snmp_oid_compare; - *(void **) (&nut_snmp_free_pdu) = snmp_free_pdu; - *(void **) (&nut_generate_Ku) = generate_Ku; + snmp_oid_compare; + *(void **) (&nut_snmp_free_pdu) = + snmp_free_pdu; + *(void **) (&nut_generate_Ku) = + generate_Ku; *(void **) (&nut_snmp_out_toggle_options) = - snmp_out_toggle_options; + snmp_out_toggle_options; *(void **) (&nut_snmp_api_errstring) = - snmp_api_errstring; + snmp_api_errstring; /* Note: this one is an (int) exposed by netsnmp, not a function! */ nut_snmp_errno = &snmp_errno; #if NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol || NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol *(void **) (&nut_usmAESPrivProtocol) = - USMAESPRIVPROTOCOL_PTR; + USMAESPRIVPROTOCOL_PTR; #endif #if NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol *(void **) (&nut_usmHMACMD5AuthProtocol) = - usmHMACMD5AuthProtocol; + usmHMACMD5AuthProtocol; #endif #if NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol *(void **) (&nut_usmHMACSHA1AuthProtocol) = - usmHMACSHA1AuthProtocol; + usmHMACSHA1AuthProtocol; #endif #if NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol *(void **) (&nut_usmDESPrivProtocol) = - usmDESPrivProtocol; + usmDESPrivProtocol; #endif #if NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 # if NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol *(void **) (&nut_usmAES192PrivProtocol) = - usmAES192PrivProtocol; + usmAES192PrivProtocol; # endif # if NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol *(void **) (&nut_usmAES256PrivProtocol) = - usmAES256PrivProtocol; + usmAES256PrivProtocol; # endif #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol *(void **) (&nut_usmHMAC192SHA256AuthProtocol) = - usmHMAC192SHA256AuthProtocol; + usmHMAC192SHA256AuthProtocol; #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol *(void **) (&nut_usmHMAC256SHA384AuthProtocol) = - usmHMAC256SHA384AuthProtocol; + usmHMAC256SHA384AuthProtocol; #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol *(void **) (&nut_usmHMAC384SHA512AuthProtocol) = - usmHMAC384SHA512AuthProtocol; + usmHMAC384SHA512AuthProtocol; #endif # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) @@ -444,9 +447,11 @@ int nutscan_load_snmp_library(const char *libname_path) # endif #else /* not WITH_SNMP_STATIC */ + char *symbol = NULL; + if (dl_handle != NULL) { /* if previous init failed */ - if (dl_handle == (void *)1) { + if (dl_handle == (lt_dlhandle)1) { return 0; } /* init has already been done */ @@ -469,98 +474,104 @@ int nutscan_load_snmp_library(const char *libname_path) goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); - *(void **) (&nut_init_snmp) = lt_dlsym(dl_handle, "init_snmp"); + *(void **) (&nut_init_snmp) = lt_dlsym(dl_handle, + symbol = "init_snmp"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_sess_init) = lt_dlsym(dl_handle, - "snmp_sess_init"); + symbol = "snmp_sess_init"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_sess_open) = lt_dlsym(dl_handle, - "snmp_sess_open"); + symbol = "snmp_sess_open"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_sess_close) = lt_dlsym(dl_handle, - "snmp_sess_close"); + symbol = "snmp_sess_close"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_sess_session) = lt_dlsym(dl_handle, - "snmp_sess_session"); + symbol = "snmp_sess_session"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_parse_oid) = lt_dlsym(dl_handle, - "snmp_parse_oid"); + symbol = "snmp_parse_oid"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_pdu_create) = lt_dlsym(dl_handle, - "snmp_pdu_create"); + symbol = "snmp_pdu_create"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_add_null_var) = lt_dlsym(dl_handle, - "snmp_add_null_var"); + symbol = "snmp_add_null_var"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_sess_synch_response) = lt_dlsym(dl_handle, - "snmp_sess_synch_response"); + symbol = "snmp_sess_synch_response"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_oid_compare) = lt_dlsym(dl_handle, - "snmp_oid_compare"); + symbol = "snmp_oid_compare"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_snmp_free_pdu) = lt_dlsym(dl_handle, "snmp_free_pdu"); + *(void **) (&nut_snmp_free_pdu) = lt_dlsym(dl_handle, + symbol = "snmp_free_pdu"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_generate_Ku) = lt_dlsym(dl_handle, "generate_Ku"); + *(void **) (&nut_generate_Ku) = lt_dlsym(dl_handle, + symbol = "generate_Ku"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_out_toggle_options) = lt_dlsym(dl_handle, - "snmp_out_toggle_options"); + symbol = "snmp_out_toggle_options"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_snmp_api_errstring) = lt_dlsym(dl_handle, - "snmp_api_errstring"); + symbol = "snmp_api_errstring"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_snmp_errno) = lt_dlsym(dl_handle, "snmp_errno"); + *(void **) (&nut_snmp_errno) = lt_dlsym(dl_handle, + symbol = "snmp_errno"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } #if NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol || NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol *(void **) (&nut_usmAESPrivProtocol) = lt_dlsym(dl_handle, - USMAESPRIVPROTOCOL); + symbol = USMAESPRIVPROTOCOL); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -568,7 +579,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol *(void **) (&nut_usmHMACMD5AuthProtocol) = lt_dlsym(dl_handle, - "usmHMACMD5AuthProtocol"); + symbol = "usmHMACMD5AuthProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -576,7 +587,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol *(void **) (&nut_usmHMACSHA1AuthProtocol) = lt_dlsym(dl_handle, - "usmHMACSHA1AuthProtocol"); + symbol = "usmHMACSHA1AuthProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -584,7 +595,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol *(void **) (&nut_usmDESPrivProtocol) = lt_dlsym(dl_handle, - "usmDESPrivProtocol"); + symbol = "usmDESPrivProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -593,7 +604,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 # if NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol *(void **) (&nut_usmAES192PrivProtocol) = lt_dlsym(dl_handle, - "usmAES192PrivProtocol"); + symbol = "usmAES192PrivProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -601,7 +612,7 @@ int nutscan_load_snmp_library(const char *libname_path) # if NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol *(void **) (&nut_usmAES256PrivProtocol) = lt_dlsym(dl_handle, - "usmAES256PrivProtocol"); + symbol = "usmAES256PrivProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -610,7 +621,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol *(void **) (&nut_usmHMAC192SHA256AuthProtocol) = lt_dlsym(dl_handle, - "usmHMAC192SHA256AuthProtocol"); + symbol = "usmHMAC192SHA256AuthProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -618,7 +629,7 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol *(void **) (&nut_usmHMAC256SHA384AuthProtocol) = lt_dlsym(dl_handle, - "usmHMAC256SHA384AuthProtocol"); + symbol = "usmHMAC256SHA384AuthProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -626,12 +637,15 @@ int nutscan_load_snmp_library(const char *libname_path) #if NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol *(void **) (&nut_usmHMAC384SHA512AuthProtocol) = lt_dlsym(dl_handle, - "usmHMAC384SHA512AuthProtocol"); + symbol = "usmHMAC384SHA512AuthProtocol"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } #endif /* NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol */ + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -643,9 +657,13 @@ int nutscan_load_snmp_library(const char *libname_path) #ifndef WITH_SNMP_STATIC err: upsdebugx(0, - "Cannot load SNMP library (%s) : %s. SNMP search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load SNMP library (%s) : %s%s%s%s. SNMP search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -763,7 +781,7 @@ static void scan_snmp_add_device(nutscan_snmp_t * sec, struct snmp_pdu *response * Does our driver support the notation? */ dev->port = strdup(session->peername); if (response != NULL) { - buf = malloc (response->variables->val_len + 1); + buf = (char*)malloc (response->variables->val_len + 1); if (buf) { memcpy(buf, response->variables->val.string, response->variables->val_len); @@ -803,7 +821,7 @@ static void scan_snmp_add_device(nutscan_snmp_t * sec, struct snmp_pdu *response } } else { - buf = malloc (session->community_len + 1); + buf = (char*)malloc(session->community_len + 1); if (buf) { memcpy(buf, session->community, session->community_len); @@ -858,8 +876,8 @@ static struct snmp_pdu * scan_snmp_get_oid(char* oid_str, void* handle) || response->variables == NULL || response->variables->name == NULL || ((*nut_snmp_oid_compare)(response->variables->name, - response->variables->name_length, - name, name_len) != 0) + response->variables->name_length, + name, name_len) != 0) || response->variables->val.string == NULL ) { (*nut_snmp_free_pdu)(response); @@ -1064,13 +1082,14 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) __func__, snmp_sess->securityAuthProtoLen); return 0; } - if ((*nut_generate_Ku)(snmp_sess->securityAuthProto, - (u_int)snmp_sess->securityAuthProtoLen, - (unsigned char *) sec->authPassword, - strlen(sec->authPassword), - snmp_sess->securityAuthKey, - &snmp_sess->securityAuthKeyLen) - != SNMPERR_SUCCESS + if ((*nut_generate_Ku)( + snmp_sess->securityAuthProto, + (u_int)snmp_sess->securityAuthProtoLen, + (unsigned char *) sec->authPassword, + strlen(sec->authPassword), + snmp_sess->securityAuthKey, + &snmp_sess->securityAuthKeyLen + ) != SNMPERR_SUCCESS ) { upsdebugx(0, "WARNING: %s: " "Error generating Ku from " @@ -1153,13 +1172,14 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec) __func__, snmp_sess->securityAuthProtoLen); return 0; } - if ((*nut_generate_Ku)(snmp_sess->securityAuthProto, - (u_int)snmp_sess->securityAuthProtoLen, - (unsigned char *) sec->privPassword, - strlen(sec->privPassword), - snmp_sess->securityPrivKey, - &snmp_sess->securityPrivKeyLen) - != SNMPERR_SUCCESS + if ((*nut_generate_Ku)( + snmp_sess->securityAuthProto, + (u_int)snmp_sess->securityAuthProtoLen, + (unsigned char *) sec->privPassword, + strlen(sec->privPassword), + snmp_sess->securityPrivKey, + &snmp_sess->securityPrivKeyLen + ) != SNMPERR_SUCCESS ) { upsdebugx(0, "WARNING: %s: " "Error generating Ku from " @@ -1236,8 +1256,7 @@ static void * try_SysOID_thready(void * arg) (*nut_snmp_add_null_var)(pdu, name, name_len); - (*nut_snmp_sess_synch_response)(handle, - pdu, &response); + (*nut_snmp_sess_synch_response)(handle, pdu, &response); if (response) { sec->handle = handle; @@ -1246,8 +1265,8 @@ static void * try_SysOID_thready(void * arg) /* SysOID is supposed to give the required MIB. */ /* Check if the received OID match with a known sysOID */ - if (response->variables != NULL && - response->variables->val.objid != NULL + if (response->variables != NULL + && response->variables->val.objid != NULL ) { while (snmp_device_table[index].mib != NULL) { if (snmp_device_table[index].sysoid == NULL) { @@ -1323,8 +1342,9 @@ static void init_snmp_once(void) } } -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_snmp( + const char * start_ip, const char * stop_ip, + useconds_t usec_timeout, nutscan_snmp_t * sec) { nutscan_device_t *ndret; nutscan_ip_range_list_t irl; @@ -1342,8 +1362,9 @@ nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip return ndret; } -nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, - useconds_t usec_timeout, nutscan_snmp_t * sec) +nutscan_device_t * nutscan_scan_ip_range_snmp( + nutscan_ip_range_list_t * irl, + useconds_t usec_timeout, nutscan_snmp_t * sec) { bool_t pass = TRUE; /* Track that we may spawn a scanning thread */ nutscan_device_t * result; @@ -1570,7 +1591,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, #endif /* HAVE_PTHREAD */ if (pass) { - tmp_sec = malloc(sizeof(nutscan_snmp_t)); + tmp_sec = (nutscan_snmp_t*)malloc(sizeof(nutscan_snmp_t)); if (tmp_sec == NULL) { upsdebugx(0, "%s: Memory allocation error", __func__); break; @@ -1588,7 +1609,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, # endif /* HAVE_PTHREAD_TRYJOIN */ thread_count++; - new_thread_array = realloc(thread_array, + new_thread_array = (nutscan_thread_t*)realloc(thread_array, thread_count * sizeof(nutscan_thread_t)); if (new_thread_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread array", __func__); @@ -1720,8 +1741,9 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, #else /* not WITH_SNMP */ /* stub function */ -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_snmp( + const char * start_ip, const char * stop_ip, + useconds_t usec_timeout, nutscan_snmp_t * sec) { NUT_UNUSED_VARIABLE(start_ip); NUT_UNUSED_VARIABLE(stop_ip); @@ -1732,8 +1754,9 @@ nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip } /* stub function */ -nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, - useconds_t usec_timeout, nutscan_snmp_t * sec) +nutscan_device_t * nutscan_scan_ip_range_snmp( + nutscan_ip_range_list_t * irl, + useconds_t usec_timeout, nutscan_snmp_t * sec) { NUT_UNUSED_VARIABLE(irl); NUT_UNUSED_VARIABLE(usec_timeout); diff --git a/tools/nut-scanner/scan_upower.c b/tools/nut-scanner/scan_upower.c new file mode 100644 index 0000000000..d2ab2b8a2d --- /dev/null +++ b/tools/nut-scanner/scan_upower.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2026 Tim Niemueller + * Copyright (C) 2026 - Jim Klimov - support and modernization of codebase + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! \file scan_upower.c + \brief detect NUT supported devices via UPower (GDBus/GIO) + \author Tim Niemueller +*/ + +#include "common.h" +#include "nut-scan.h" + +/* externally visible to nutscan-init */ +int nutscan_unload_upower_library(void); +/* externally visible to nut-scanner */ +nutscan_device_t * nutscan_scan_upower(void); + +#if (defined WITH_UPOWER) && WITH_UPOWER + +#include +#include +#include +#include +#include + +/* dynamic link library stuff */ +static lt_dlhandle dl_handle = NULL; +static const char *dl_error = NULL; +static char *dl_saved_libname = NULL; + +/* Function pointers */ +static GDBusConnection * (*nut_g_bus_get_sync)(GBusType bus_type, GCancellable *cancellable, GError **error); +static GDBusProxy * (*nut_g_dbus_proxy_new_sync)(GDBusConnection *connection, GDBusProxyFlags flags, GDBusInterfaceInfo *info, const gchar *name, const gchar *object_path, const gchar *interface_name, GCancellable *cancellable, GError **error); +static GVariant * (*nut_g_dbus_proxy_call_sync)(GDBusProxy *proxy, const gchar *method_name, GVariant *parameters, GDBusCallFlags flags, gint timeout_msec, GCancellable *cancellable, GError **error); +static GVariant * (*nut_g_dbus_proxy_get_cached_property)(GDBusProxy *proxy, const gchar *property_name); +static void (*nut_g_variant_unref)(GVariant *value); +static void (*nut_g_object_unref)(gpointer object); +static void (*nut_g_error_free)(GError *error); +static const gchar * (*nut_g_variant_get_string)(GVariant *value, gsize *length); +static gboolean (*nut_g_variant_iter_next)(GVariantIter *iter, const gchar *format_string, ...); +static gsize (*nut_g_variant_iter_init)(GVariantIter *iter, GVariant *value); +static guint32 (*nut_g_variant_get_uint32)(GVariant *value); +static GVariant * (*nut_g_variant_get_child_value)(GVariant *value, gsize index_); + +/* Return 0 on success, -1 on error e.g. "was not loaded"; + * other values may be possible if lt_dlclose() errors set them; + * visible externally */ +int nutscan_unload_library(int *avail, lt_dlhandle *pdl_handle, char **libpath); +int nutscan_unload_upower_library(void) +{ + return nutscan_unload_library(&nutscan_avail_upower, &dl_handle, &dl_saved_libname); +} + +/* Return 0 on error; visible externally */ +int nutscan_load_upower_library(const char *libname_path); +int nutscan_load_upower_library(const char *libname_path) +{ + char *symbol = NULL; + + if (dl_handle != NULL) { + /* if previous init failed */ + if (dl_handle == (lt_dlhandle)1) { + return 0; + } + /* init has already been done */ + return 1; + } + + if (libname_path == NULL) { + upsdebugx(0, "GIO library not found. UPower search disabled."); + return 0; + } + + if (lt_dlinit() != 0) { + upsdebugx(0, "%s: Error initializing lt_dlinit", __func__); + return 0; + } + + dl_handle = lt_dlopen(libname_path); + if (!dl_handle) { + dl_error = lt_dlerror(); + goto err; + } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + + /* Clear any existing error */ + lt_dlerror(); + + *(void **) (&nut_g_bus_get_sync) = lt_dlsym(dl_handle, + symbol = "g_bus_get_sync"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_dbus_proxy_new_sync) = lt_dlsym(dl_handle, + symbol = "g_dbus_proxy_new_sync"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_dbus_proxy_call_sync) = lt_dlsym(dl_handle, + symbol = "g_dbus_proxy_call_sync"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_dbus_proxy_get_cached_property) = lt_dlsym(dl_handle, + symbol = "g_dbus_proxy_get_cached_property"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_unref) = lt_dlsym(dl_handle, + symbol = "g_variant_unref"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_object_unref) = lt_dlsym(dl_handle, + symbol = "g_object_unref"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_error_free) = lt_dlsym(dl_handle, + symbol = "g_error_free"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_get_string) = lt_dlsym(dl_handle, + symbol = "g_variant_get_string"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_iter_next) = lt_dlsym(dl_handle, + symbol = "g_variant_iter_next"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_iter_init) = lt_dlsym(dl_handle, + symbol = "g_variant_iter_init"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_get_uint32) = lt_dlsym(dl_handle, + symbol = "g_variant_get_uint32"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + *(void **) (&nut_g_variant_get_child_value) = lt_dlsym(dl_handle, + symbol = "g_variant_get_child_value"); + if ((dl_error = lt_dlerror()) != NULL) goto err; + + /* Passed final lt_dlsym() */ + symbol = NULL; + + if (dl_saved_libname) + free(dl_saved_libname); + dl_saved_libname = xstrdup(libname_path); + + return 1; + +err: + upsdebugx(0, + "Cannot load GIO library (%s) : %s%s%s%s. UPower search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; + lt_dlexit(); + if (dl_saved_libname) { + free(dl_saved_libname); + dl_saved_libname = NULL; + } + return 0; +} + +nutscan_device_t * nutscan_scan_upower(void) +{ + GError *error = NULL; + GDBusConnection *connection; + GDBusProxy *proxy_upower = NULL; + GVariant *result = NULL; + GVariant *child = NULL; + GVariantIter iter; + gchar *object_path; + nutscan_device_t * dev_ret = NULL; + + if (!nutscan_avail_upower) { + return NULL; + } + + connection = (*nut_g_bus_get_sync)(G_BUS_TYPE_SYSTEM, NULL, &error); + if (connection == NULL) { + upsdebugx(1, "Error connecting to system bus: %s", error->message); + (*nut_g_error_free)(error); + return NULL; + } + + proxy_upower = (*nut_g_dbus_proxy_new_sync)( + connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.UPower", + "/org/freedesktop/UPower", + "org.freedesktop.UPower", + NULL, + &error); + + if (proxy_upower == NULL) { + upsdebugx(1, "Error creating UPower proxy: %s", error->message); + (*nut_g_error_free)(error); + (*nut_g_object_unref)(connection); + return NULL; + } + + result = (*nut_g_dbus_proxy_call_sync)( + proxy_upower, + "EnumerateDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (result == NULL) { + upsdebugx(1, "Error enumerating devices: %s", error->message); + (*nut_g_error_free)(error); + (*nut_g_object_unref)(proxy_upower); + (*nut_g_object_unref)(connection); + return NULL; + } + + /* Result is (ao) - array of object paths */ + child = (*nut_g_variant_get_child_value)(result, 0); + (*nut_g_variant_iter_init)(&iter, child); + + while ((*nut_g_variant_iter_next)(&iter, "o", &object_path)) { + GDBusProxy *proxy_device; + GVariant *v_type, *v_model, *v_vendor, *v_serial, *v_native_path; + nutscan_device_t * dev; + + proxy_device = (*nut_g_dbus_proxy_new_sync)( + connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.UPower", + object_path, + "org.freedesktop.UPower.Device", + NULL, + &error); + + if (proxy_device == NULL) { + upsdebugx(1, "Error creating device proxy for %s: %s", object_path, error->message); + (*nut_g_error_free)(error); + free(object_path); + continue; + } + + /* Check Type property: 2 is Battery, 3 is UPS */ + v_type = (*nut_g_dbus_proxy_get_cached_property)(proxy_device, "Type"); + if (v_type) { + guint32 type = (*nut_g_variant_get_uint32)(v_type); + (*nut_g_variant_unref)(v_type); + + if (type == 2 || type == 3) { /* Battery or UPS */ + dev = nutscan_new_device(); + dev->type = TYPE_UPOWER; + dev->driver = strdup("upower"); + dev->port = strdup(object_path); + + v_vendor = (*nut_g_dbus_proxy_get_cached_property)(proxy_device, "Vendor"); + if (v_vendor) { + nutscan_add_option_to_device(dev, "vendor", (char*)(*nut_g_variant_get_string)(v_vendor, NULL)); + (*nut_g_variant_unref)(v_vendor); + } + + v_model = (*nut_g_dbus_proxy_get_cached_property)(proxy_device, "Model"); + if (v_model) { + nutscan_add_option_to_device(dev, "product", (char*)(*nut_g_variant_get_string)(v_model, NULL)); + (*nut_g_variant_unref)(v_model); + } + + v_serial = (*nut_g_dbus_proxy_get_cached_property)(proxy_device, "Serial"); + if (v_serial) { + nutscan_add_option_to_device(dev, "serial", (char*)(*nut_g_variant_get_string)(v_serial, NULL)); + (*nut_g_variant_unref)(v_serial); + } + + v_native_path = (*nut_g_dbus_proxy_get_cached_property)(proxy_device, "NativePath"); + if (v_native_path) { + nutscan_add_option_to_device(dev, "native_path", (char*)(*nut_g_variant_get_string)(v_native_path, NULL)); + (*nut_g_variant_unref)(v_native_path); + } + + nutscan_add_option_to_device(dev, "bus", "upower"); + + dev_ret = nutscan_add_device_to_device(dev_ret, dev); + } + } + + (*nut_g_object_unref)(proxy_device); + free(object_path); + } + + (*nut_g_variant_unref)(child); + (*nut_g_variant_unref)(result); + (*nut_g_object_unref)(proxy_upower); + (*nut_g_object_unref)(connection); + + return nutscan_rewind_device(dev_ret); +} + +#else /* not WITH_UPOWER */ + +nutscan_device_t * nutscan_scan_upower(void) +{ + return NULL; +} + +int nutscan_unload_upower_library(void) +{ + return 0; +} + +#endif /* WITH_UPOWER */ diff --git a/tools/nut-scanner/scan_usb.c b/tools/nut-scanner/scan_usb.c index dd44bd16f7..29bd9baf52 100644 --- a/tools/nut-scanner/scan_usb.c +++ b/tools/nut-scanner/scan_usb.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011-2016 - EATON - * Copyright (C) 2020-2024 - Jim Klimov - support and modernization of codebase + * Copyright (C) 2020-2026 - Jim Klimov - support and modernization of codebase * * 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 @@ -29,7 +29,7 @@ /* externally visible to nutscan-init */ int nutscan_unload_usb_library(void); -#ifdef WITH_USB +#if (defined WITH_USB) && WITH_USB #include "upsclient.h" #include "nutscan-usb.h" @@ -43,15 +43,17 @@ static const char *dl_error = NULL; static char *dl_saved_libname = NULL; static int (*nut_usb_close)(libusb_device_handle *dev); -static int (*nut_usb_control_transfer)(libusb_device_handle *dev, - uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout); -static int (*nut_usb_get_string_with_langid)(libusb_device_handle *dev, int index, int langid, - char *buf, size_t buflen); +static int (*nut_usb_control_transfer)( + libusb_device_handle *dev, + uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char *data, uint16_t wLength, unsigned int timeout); +static int (*nut_usb_get_string_with_langid)( + libusb_device_handle *dev, int index, int langid, + char *buf, size_t buflen); /* Fallback implem if the above is not a library symbol */ static int nut_usb_get_string_with_langid_control_transfer( - libusb_device_handle *dev, int index, int langid, - char *buf, size_t buflen); + libusb_device_handle *dev, int index, int langid, + char *buf, size_t buflen); /* Compatibility layer between libusb 0.1 and 1.0 */ #if WITH_LIBUSB_1_0 @@ -68,8 +70,10 @@ static int nut_usb_get_string_with_langid_control_transfer( static uint8_t (*nut_usb_get_bus_number)(libusb_device *dev); static uint8_t (*nut_usb_get_device_address)(libusb_device *dev); static uint8_t (*nut_usb_get_port_number)(libusb_device *dev); - static int (*nut_usb_get_device_descriptor)(libusb_device *dev, + static int (*nut_usb_get_device_descriptor)( + libusb_device *dev, struct libusb_device_descriptor *desc); + static const struct libusb_version * (*nut_usb_get_version)(void); # define USB_DT_STRING LIBUSB_DT_STRING # define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN # define USB_REQ_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR @@ -103,13 +107,15 @@ int nutscan_unload_usb_library(void) int nutscan_load_usb_library(const char *libname_path); int nutscan_load_usb_library(const char *libname_path) { + char *symbol = NULL; + if (dl_handle != NULL) { - /* if previous init failed */ - if (dl_handle == (void *)1) { - return 0; - } - /* init has already been done */ - return 1; + /* if previous init failed */ + if (dl_handle == (lt_dlhandle)1) { + return 0; + } + /* init has already been done */ + return 1; } if (libname_path == NULL) { @@ -124,55 +130,68 @@ int nutscan_load_usb_library(const char *libname_path) dl_handle = lt_dlopen(libname_path); if (!dl_handle) { - dl_error = lt_dlerror(); - goto err; + dl_error = lt_dlerror(); + goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); - *(void **) (&nut_usb_init) = lt_dlsym(dl_handle, USB_INIT_SYMBOL); + *(void **) (&nut_usb_init) = lt_dlsym(dl_handle, + symbol = USB_INIT_SYMBOL); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_usb_open) = lt_dlsym(dl_handle, USB_OPEN_SYMBOL); + *(void **) (&nut_usb_open) = lt_dlsym(dl_handle, + symbol = USB_OPEN_SYMBOL); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_usb_close) = lt_dlsym(dl_handle, USB_CLOSE_SYMBOL); + *(void **) (&nut_usb_close) = lt_dlsym(dl_handle, + symbol = USB_CLOSE_SYMBOL); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } - *(void **) (&nut_usb_strerror) = lt_dlsym(dl_handle, USB_STRERROR_SYMBOL); + *(void **) (&nut_usb_strerror) = lt_dlsym(dl_handle, + symbol = USB_STRERROR_SYMBOL); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } #if WITH_LIBUSB_1_0 - *(void **) (&nut_usb_exit) = lt_dlsym(dl_handle, "libusb_exit"); + *(void **) (&nut_usb_exit) = lt_dlsym(dl_handle, + symbol = "libusb_exit"); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + + *(void **) (&nut_usb_get_version) = lt_dlsym(dl_handle, + symbol = "libusb_get_version"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_get_device_list) = lt_dlsym(dl_handle, - "libusb_get_device_list"); + symbol = "libusb_get_device_list"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_free_device_list) = lt_dlsym(dl_handle, - "libusb_free_device_list"); + symbol = "libusb_free_device_list"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_get_bus_number) = lt_dlsym(dl_handle, - "libusb_get_bus_number"); + symbol = "libusb_get_bus_number"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } /* Note: per https://nxmnpg.lemoda.net/3/libusb_get_device_address there @@ -180,9 +199,9 @@ int nutscan_load_usb_library(const char *libname_path) * not for too long (libusb-1.0.12...1.0.16) and now it is deprecated. */ *(void **) (&nut_usb_get_device_address) = lt_dlsym(dl_handle, - "libusb_get_device_address"); + symbol = "libusb_get_device_address"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } /* This method may be absent in some libusb versions, and we should @@ -190,80 +209,83 @@ int nutscan_load_usb_library(const char *libname_path) * #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) */ *(void **) (&nut_usb_get_port_number) = lt_dlsym(dl_handle, - "libusb_get_port_number"); + symbol = "libusb_get_port_number"); if ((dl_error = lt_dlerror()) != NULL) { - upsdebugx(0, "WARNING: %s: " - "While loading USB library (%s), failed to find libusb_get_port_number() : %s. " - "The \"busport\" USB matching option will be disabled.", - __func__, libname_path, dl_error); - nut_usb_get_port_number = NULL; + upsdebugx(0, "WARNING: %s: " + "While loading USB library (%s), failed to find libusb_get_port_number() : %s. " + "The \"busport\" USB matching option will be disabled.", + __func__, libname_path, dl_error); + nut_usb_get_port_number = NULL; } *(void **) (&nut_usb_get_device_descriptor) = lt_dlsym(dl_handle, - "libusb_get_device_descriptor"); + symbol = "libusb_get_device_descriptor"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_control_transfer) = lt_dlsym(dl_handle, - "libusb_control_transfer"); + symbol = "libusb_control_transfer"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_get_string_with_langid) = lt_dlsym(dl_handle, - "libusb_get_string_descriptor"); + symbol = "libusb_get_string_descriptor"); if ((dl_error = lt_dlerror()) != NULL) { - /* This one may be only defined in a header as an inline method; - * then we are adapting it via nut_usb_control_transfer(). - */ - nut_usb_get_string_with_langid = NULL; + /* This one may be only defined in a header as an inline method; + * then we are adapting it via nut_usb_control_transfer(). + */ + nut_usb_get_string_with_langid = NULL; } #else /* for libusb 0.1 */ *(void **) (&nut_usb_find_busses) = lt_dlsym(dl_handle, - "usb_find_busses"); + symbol = "usb_find_busses"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } # ifndef WIN32 *(void **) (&nut_usb_busses) = lt_dlsym(dl_handle, - "usb_busses"); + symbol = "usb_busses"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } # else *(void **) (&nut_usb_get_busses) = lt_dlsym(dl_handle, - "usb_get_busses"); + symbol = "usb_get_busses"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } # endif /* WIN32 */ *(void **)(&nut_usb_find_devices) = lt_dlsym(dl_handle, - "usb_find_devices"); + symbol = "usb_find_devices"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_control_transfer) = lt_dlsym(dl_handle, - "usb_control_msg"); + symbol = "usb_control_msg"); if ((dl_error = lt_dlerror()) != NULL) { - goto err; + goto err; } *(void **) (&nut_usb_get_string_with_langid) = lt_dlsym(dl_handle, - "usb_get_string"); + symbol = "usb_get_string"); if ((dl_error = lt_dlerror()) != NULL) { - /* See comment above */ - nut_usb_get_string_with_langid = NULL; + /* See comment above */ + nut_usb_get_string_with_langid = NULL; } #endif /* not WITH_LIBUSB_1_0 => for libusb 0.1 */ if (nut_usb_get_string_with_langid == NULL) { - nut_usb_get_string_with_langid = nut_usb_get_string_with_langid_control_transfer; + nut_usb_get_string_with_langid = nut_usb_get_string_with_langid_control_transfer; } + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -272,9 +294,13 @@ int nutscan_load_usb_library(const char *libname_path) err: upsdebugx(0, - "Cannot load USB library (%s) : %s. USB search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load USB library (%s) : %s%s%s%s. USB search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -284,8 +310,9 @@ int nutscan_load_usb_library(const char *libname_path) } /* end of dynamic link library stuff */ -static char* is_usb_device_supported(usb_device_id_t *usb_device_id_list, - int dev_VendorID, int dev_ProductID, char **alt) +static char* is_usb_device_supported( + usb_device_id_t *usb_device_id_list, + int dev_VendorID, int dev_ProductID, char **alt) { usb_device_id_t *usbdev; @@ -307,8 +334,8 @@ static char* is_usb_device_supported(usb_device_id_t *usb_device_id_list, * https://github.com/libusb/libusb-compat-0.1/blob/eaed7b8f11badaf07a91e07538f6e8842f59eaab/libusb/libusb-dload.h#L165-L171 */ static int nut_usb_get_string_with_langid_control_transfer( - libusb_device_handle *dev, int index, int langid, - char *buf, size_t buflen) + libusb_device_handle *dev, int index, int langid, + char *buf, size_t buflen) { return (*nut_usb_control_transfer)( dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, @@ -484,7 +511,15 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) /* Initialize Libusb */ #if WITH_LIBUSB_1_0 if ((*nut_usb_init)(NULL) < 0) { - (*nut_usb_exit)(NULL); + /* Per https://github.com/libusb/libusb/issues/511 fixed since + * 1.0.24 by https://github.com/libusb/libusb/commit/a5624b22267ec0e146825d3fe94d9e4b2f5ae503 + * libusb_exit() should not be called unless libusb_init() + * succeeded for same context. + */ + const struct libusb_version *ver = (*nut_usb_get_version)(); + + if (ver && (ver->major > 1 || (ver->major == 1 && ver->minor >= 24))) + (*nut_usb_exit)(NULL); upsdebug_with_errno(0, "Failed to init libusb 1.0"); /* nutscan_avail_usb = 0; */ return NULL; @@ -594,7 +629,7 @@ nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts) "bus/port '%s', skipping: %s", __func__, busname, device_port, bus_port, - (*nut_usb_strerror)(ret)); + (*nut_usb_strerror)((enum libusb_error)ret)); /* Note: closing is not applicable * it seems, and can even segfault diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index a21d9d0e8e..e0b0d0b992 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -2,7 +2,7 @@ * Copyright (C) 2011 - EATON * Copyright (C) 2016 - EATON - IP addressed XML scan * Copyright (C) 2016-2021 - EATON - Various threads-related improvements - * Copyright (C) 2020-2024 - Jim Klimov - support and modernization of codebase + * Copyright (C) 2020-2026 - Jim Klimov - support and modernization of codebase * * 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 @@ -33,7 +33,7 @@ /* externally visible to nutscan-init */ int nutscan_unload_neon_library(void); -#ifdef WITH_NEON +#if (defined WITH_NEON) && WITH_NEON #ifndef WIN32 # include @@ -64,11 +64,12 @@ static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; static char *dl_saved_libname = NULL; -static void (*nut_ne_xml_push_handler)(ne_xml_parser *p, - ne_xml_startelm_cb *startelm, - ne_xml_cdata_cb *cdata, - ne_xml_endelm_cb *endelm, - void *userdata); +static void (*nut_ne_xml_push_handler)( + ne_xml_parser *p, + ne_xml_startelm_cb *startelm, + ne_xml_cdata_cb *cdata, + 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); @@ -101,10 +102,12 @@ int nutscan_unload_neon_library(void) int nutscan_load_neon_library(const char *libname_path); int nutscan_load_neon_library(const char *libname_path) { + char *symbol = NULL; + if (dl_handle != NULL) { /* if previous init failed */ - if (dl_handle == (void *)1) { - return 0; + if (dl_handle == (lt_dlhandle)1) { + return 0; } /* init has already been done */ return 1; @@ -126,35 +129,44 @@ int nutscan_load_neon_library(const char *libname_path) goto err; } + upsdebugx(2, "%s: lt_dlopen() succeeded, searching for needed methods", __func__); + /* Clear any existing error */ lt_dlerror(); *(void **) (&nut_ne_xml_push_handler) = lt_dlsym(dl_handle, - "ne_xml_push_handler"); + symbol = "ne_xml_push_handler"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ne_xml_destroy) = lt_dlsym(dl_handle, "ne_xml_destroy"); + *(void **) (&nut_ne_xml_destroy) = lt_dlsym(dl_handle, + symbol = "ne_xml_destroy"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ne_xml_create) = lt_dlsym(dl_handle, "ne_xml_create"); + *(void **) (&nut_ne_xml_create) = lt_dlsym(dl_handle, + symbol = "ne_xml_create"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ne_xml_parse) = lt_dlsym(dl_handle, "ne_xml_parse"); + *(void **) (&nut_ne_xml_parse) = lt_dlsym(dl_handle, + symbol = "ne_xml_parse"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ne_xml_failed) = lt_dlsym(dl_handle, "ne_xml_failed"); + *(void **) (&nut_ne_xml_failed) = lt_dlsym(dl_handle, + symbol = "ne_xml_failed"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } + /* Passed final lt_dlsym() */ + symbol = NULL; + if (dl_saved_libname) free(dl_saved_libname); dl_saved_libname = xstrdup(libname_path); @@ -163,9 +175,13 @@ int nutscan_load_neon_library(const char *libname_path) err: upsdebugx(0, - "Cannot load XML library (%s) : %s. XML search disabled.", - libname_path, dl_error); - dl_handle = (void *)1; + "Cannot load XML library (%s) : %s%s%s%s. XML search disabled.", + libname_path, dl_error, + symbol ? " Error happened during search for symbol '" : "", + symbol ? symbol : "", + symbol ? "'" : "" + ); + dl_handle = (lt_dlhandle)1; lt_dlexit(); if (dl_saved_libname) { free(dl_saved_libname); @@ -309,9 +325,7 @@ static void * nutscan_scan_xml_http_thready(void * arg) upsdebugx(5, "%s: sent request to %s, " "loop #%d/%d, waiting for responses", __func__, (ip ? ip : ""), (i + 1), MAX_RETRIES); - while ((ret = select(peerSocket + 1, &fds, NULL, NULL, - &timeout)) - ) { + while ((ret = select(peerSocket + 1, &fds, NULL, NULL, &timeout))) { ne_xml_parser *parser; int parserFailed; @@ -372,8 +386,9 @@ static void * nutscan_scan_xml_http_thready(void * arg) nut_dev->type = TYPE_XML; /* Try to read device type */ parser = (*nut_ne_xml_create)(); - (*nut_ne_xml_push_handler)(parser, startelm_cb, - NULL, NULL, nut_dev); + (*nut_ne_xml_push_handler)( + parser, startelm_cb, + NULL, NULL, nut_dev); /* recv_size is a ssize_t, so in range of size_t */ (*nut_ne_xml_parse)(parser, buf, (size_t)recv_size); parserFailed = (*nut_ne_xml_failed)(parser); /* 0 = ok, nonzero = fail */ @@ -610,7 +625,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, */ int stwST = sem_trywait(semaphore_scantype); int stwS = sem_trywait(semaphore); - pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0); + pass = ((max_threads_scantype == 0 || stwST == 0) && stwS == 0) ? TRUE : FALSE; upsdebugx(4, "%s: max_threads_scantype=%" PRIuSIZE " curr_threads=%" PRIuSIZE " thread_count=%" PRIuSIZE @@ -685,7 +700,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, if (curr_threads >= max_threads || (curr_threads >= max_threads_scantype && max_threads_scantype > 0) ) { - usleep (10000); /* microSec's, so 0.01s here */ + usleep (10000); /* microSec's, so 0.01s here */ } } upsdebugx(2, "%s: proceeding with scan", __func__); @@ -698,7 +713,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, #endif /* HAVE_PTHREAD */ if (pass) { - tmp_sec = malloc(sizeof(nutscan_xml_t)); + tmp_sec = (nutscan_xml_t*)malloc(sizeof(nutscan_xml_t)); if (tmp_sec == NULL) { upsdebugx(0, "%s: Memory allocation error", __func__); break; @@ -719,7 +734,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, # endif /* HAVE_PTHREAD_TRYJOIN */ thread_count++; - new_thread_array = realloc(thread_array, + new_thread_array = (nutscan_thread_t*)realloc(thread_array, thread_count * sizeof(nutscan_thread_t)); if (new_thread_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread array", __func__); @@ -849,7 +864,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, } /* end of: scan range of 1+ IP address(es), maybe in parallel */ /* both start_ip == end_ip == NULL, scan broadcast */ - tmp_sec = malloc(sizeof(nutscan_xml_t)); + tmp_sec = (nutscan_xml_t*)malloc(sizeof(nutscan_xml_t)); if (tmp_sec == NULL) { upsdebugx(0, "%s: Memory allocation error", __func__); return NULL; diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index a02f32b286..784ee16ae5 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -21,7 +21,7 @@ $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonstr.la \ $(top_builddir)/common/libcommonversion.la \ $(top_builddir)/common/libnutconf.la \ -$(top_builddir)/tools/nut-scanner/libnutscan.la: dummy +$(top_builddir)/tools/nut-scanner/libnutscan.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Builds from root dir arrange stuff decently. Make sure parallel builds @@ -35,7 +35,7 @@ $(top_builddir)/clients/libupsclient.la: $(top_builddir)/common/libcommonclient. if ENABLE_SHARED_PRIVATE_LIBS $(top_builddir)/common/libcommonversion-private.la \ $(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-all.la \ -$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy +$(top_builddir)/common/libnutprivate-@NUT_SOURCE_GITREV_SEMVER_UNDERSCORES@-common-client.la: dummy @dotMAKE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) $(top_builddir)/common/libcommonversion-private.la: $(top_builddir)/include/nut_version.h diff --git a/tools/semver-compare.sh b/tools/semver-compare.sh index 688aa22575..bbbe81eb39 100755 --- a/tools/semver-compare.sh +++ b/tools/semver-compare.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (C) 2025 by Jim Klimov +# Copyright (C) 2025-2026 by Jim Klimov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -190,8 +190,9 @@ Actions: Return sorted (via expansion) list of original semvers (till end of args) in their original spelling (with unstripped leading zeroes, if present) - $0 [OPTS] {test|[} "SEMVER1" {-gt|-ge|-lt|-le|-eq|=|==|-ne|!=|<>|<|<=|>|>=} "SEMVER2" - Shellish syntax to compare two semvers + $0 [OPTS] {test|[|[[} "SEMVER1" {-gt|>|-ge|>=|-lt|<|-le|<=|-eq|=|==|-ne|!=|<>} "SEMVER2" {]|]]} + Relaxed shellish syntax to compare two semvers, so this script can be + just prefixed into existing (alphanumeric-based) shell comparisons EOF exit 0 ;;