diff --git a/Jenkinsfile-dynamatrix b/Jenkinsfile-dynamatrix index 923b5658ce..e55a526ddd 100644 --- a/Jenkinsfile-dynamatrix +++ b/Jenkinsfile-dynamatrix @@ -476,6 +476,11 @@ set | sort -n """ // so exclude systems which have e.g. gcc-4.2.1 which claims // type range comparison warnings despite pragma fencing. // gcc-4.8.x on CentOS 7 and Ubuntu 14.04 looks already okay. + + [[~/OS_DISTRO=macos/]] + // MacOS (at least agents prepared with HomeBrew packages) + // requires a few pkg-config and CFLAGS pre-sets which are + // done in ci_build.sh and defeat the purpose of this stage. + // So it is easier and more honest to just skip it. ], body) }, // getParStages //'bodyParStages': {} diff --git a/Makefile.am b/Makefile.am index 622bc6a231..bce1242ab6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -260,7 +260,7 @@ check-NIT check-NIT-devel: ### check-scripts-syntax: @echo 'NOTE: modern bash complains about scripts using backticks (warning not error), which we ignore in NUT codebase for portability reasons: `...` obsolete, use $$(...)' - @RUNBASH=bash; if [ -x /bin/bash ]; then RUNBASH=/bin/bash ; else if [ -x /usr/bin/env ] ; then RUNBASH="/usr/bin/env bash"; fi; fi ; \ + @RUNBASH=bash; if [ -x /bin/bash ] && /bin/bash -c 'echo $${BASH_VERSION}' | grep -E '^[456789]\.' ; then RUNBASH=/bin/bash ; else if [ -x /usr/bin/env ] ; then RUNBASH="/usr/bin/env bash"; fi; fi ; \ for F in `git ls-files || find . -type f` ; do \ case "`file "$$F"`" in \ *"Bourne-Again shell script"*) ( set -x ; $$RUNBASH -n "$$F" ; ) ;; \ diff --git a/NEWS.adoc b/NEWS.adoc index 6ba1eb092d..ccfd44335c 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -183,6 +183,10 @@ during a NUT build. variable support was added to optionally disable this verification. Also the NUT daemons should request to double-check against their run-time process name (if it can be detected). [issue #2463] + * introduced `m4` macros to check during `configure` phase for the + platform, and a `nut_bool.h` header with `nut_bool_t` type to use + during build, to avoid the numerous definitions of Boolean types + and values (or macros) in the NUT codebase. [issue #1176, issue #31] - various recipe, documentation and source files were revised to address respective warnings issued by the new generations of analysis tools. @@ -243,6 +247,9 @@ during a NUT build. of more complex configurations (e.g. some line patterns that involve too many double-quote characters) which are valid for NUT proper. [#657] + - Cross-builds using only a host implementation of `pkg-config` program + should now ignore host `*.pc` files and avoid confusion. + - NUT CI farm build recipes, documentation and some `m4`/`configure.ac` sources updated to handle a much larger build scope on MacOS. Also migrated the builders to Apple Silicon from x86 (deprecated by CircleCI). diff --git a/clients/upssched.c b/clients/upssched.c index 9a8d00dd46..8ee67be755 100644 --- a/clients/upssched.c +++ b/clients/upssched.c @@ -43,17 +43,17 @@ #include #ifndef WIN32 -#include -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include +# include #else -#include "wincompat.h" -#include -#include +# include "wincompat.h" +# include +# include #endif #include "upssched.h" @@ -75,7 +75,7 @@ static const char *upsname, *notify_type; #ifdef WIN32 static OVERLAPPED connect_overlapped; -#define BUF_LEN 512 +# define BUF_LEN 512 #endif #define PARENT_STARTED -2 @@ -361,7 +361,7 @@ static TYPE_FD open_sock(void) /* Wait for a connection */ ConnectNamedPipe(fd,&connect_overlapped); -#endif +#endif /* WIN32 */ return fd; } @@ -482,7 +482,7 @@ static int send_to_one(conn_t *conn, const char *fmt, ...) return 0; /* failed */ } -#endif +#endif /* WIN32 */ return 1; /* OK */ } @@ -495,9 +495,9 @@ static TYPE_FD conn_add(TYPE_FD sockfd) int ret; conn_t *tmp, *last; struct sockaddr_un saddr; -#if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) +# if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) int salen; -#else +# else socklen_t salen; #endif @@ -625,7 +625,7 @@ static TYPE_FD conn_add(TYPE_FD sockfd) upsdebugx(3, "new connection on handle %p", acc); pconf_init(&conn->ctx, NULL); -#endif +#endif /* WIN32 */ return acc; } @@ -753,7 +753,8 @@ static int sock_read(conn_t *conn) /* Restart async read */ memset(conn->buf,0,sizeof(conn->buf)); ReadFile(conn->fd,conn->buf,1,NULL,&(conn->read_overlapped)); -#endif +#endif /* WIN32 */ + ret = pconf_char(&conn->ctx, ch); if (ret == 0) /* nothing to parse yet */ @@ -815,7 +816,7 @@ static void start_daemon(TYPE_FD lockfd) /* child */ /* make fds 0-2 (typically) point somewhere defined */ -#ifdef HAVE_DUP2 +# ifdef HAVE_DUP2 /* system can close (if needed) and (re-)open a specific FD number */ if (1) { /* scoping */ TYPE_FD devnull = open("/dev/null", O_RDWR); @@ -836,8 +837,8 @@ static void start_daemon(TYPE_FD lockfd) close(devnull); } -#else -# ifdef HAVE_DUP +# else /* not HAVE_DUP2 */ +# ifdef HAVE_DUP /* opportunistically duplicate to the "lowest-available" FD number */ close(STDIN_FILENO); if (open("/dev/null", O_RDWR) != STDIN_FILENO) @@ -854,7 +855,7 @@ static void start_daemon(TYPE_FD lockfd) if (dup(STDIN_FILENO) != STDERR_FILENO) fatal_with_errno(EXIT_FAILURE, "dup /dev/null as STDERR"); } -# else +# else /* not HAVE_DUP */ close(STDIN_FILENO); if (open("/dev/null", O_RDWR) != STDIN_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDIN"); @@ -870,8 +871,8 @@ static void start_daemon(TYPE_FD lockfd) if (open("/dev/null", O_RDWR) != STDERR_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDERR"); } -# endif -#endif +# endif /* not HAVE_DUP */ +# endif /* not HAVE_DUP2 */ pipefd = open_sock(); @@ -1048,7 +1049,7 @@ static void start_daemon(TYPE_FD lockfd) checktimers(); } -#endif +#endif /* WIN32 */ } /* --- 'client' functions --- */ @@ -1100,7 +1101,7 @@ static TYPE_FD try_connect(void) if (VALID_FD(pipefd)) return pipefd; -#endif +#endif /* WIN32 */ return ERROR_FD; } @@ -1289,7 +1290,7 @@ static void sendcmd(const char *cmd, const char *arg1, const char *arg2) CloseHandle(pipefd); continue; } -#endif +#endif /* WIN32 */ if (!strncmp(buf, "OK", 2)) return; /* success */ diff --git a/common/Makefile.am b/common/Makefile.am index 257c293b21..13bf15c15c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -45,6 +45,9 @@ endif !BUILDING_IN_TREE $(top_builddir)/include/nut_version.h: +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) +# FIXME: If we maintain some of those helper libs as subsets of the others +# (strictly), maybe build the lowest common denominator only and link the +# bigger scopes with it (rinse and repeat)? libcommon_la_SOURCES = state.c str.c upsconf.c libcommonclient_la_SOURCES = state.c str.c @@ -95,6 +98,15 @@ else !HAVE_STRSEP libcommonclient_la_SOURCES += strsep.c endif !HAVE_STRSEP +if WANT_TIMEGM_FALLBACK + # fall back to simple implem + libcommon_la_SOURCES += timegm_fallback.c + libcommonstr_la_SOURCES += timegm_fallback.c + libcommonclient_la_SOURCES += timegm_fallback.c +else !WANT_TIMEGM_FALLBACK + EXTRA_DIST += timegm_fallback.c +endif !WANT_TIMEGM_FALLBACK + if HAVE_WINDOWS libnutwincompat_la_SOURCES = wincompat.c $(top_srcdir)/include/wincompat.h libnutwincompat_la_LDFLAGS = diff --git a/common/str.c b/common/str.c index 295f450804..df9f0734e8 100644 --- a/common/str.c +++ b/common/str.c @@ -627,3 +627,30 @@ int str_ends_with(const char *s, const char *suff) { return (slen >= sufflen) && (!memcmp(s + slen - sufflen, suff, sufflen)); } + +#ifndef HAVE_STRTOF +# include +# include +float strtof(const char *nptr, char **endptr) +{ + double d; + int i; + + if (!nptr || !*nptr) { + errno = EINVAL; + return 0; + } + + i = sscanf(nptr, "%f", &d); + if (i < 1) { + errno = EINVAL; + return 0; + } + + if (endptr) { + *endptr = (char*)nptr + i; + } + + return (float)d; +} +#endif diff --git a/common/timegm_fallback.c b/common/timegm_fallback.c new file mode 100644 index 0000000000..5c8a9bfc34 --- /dev/null +++ b/common/timegm_fallback.c @@ -0,0 +1,49 @@ +/* Fallback timegm() for systems that lack one. + * Algorithm: http://howardhinnant.github.io/date_algorithms.html + * https://stackoverflow.com/a/58037981/4715872 + */ + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +static int days_from_epoch_1970(int y, int m, int d) +{ + y -= m <= 2; + int era = y / 400; + int yoe = y - era * 400; // [0, 399] + int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365] + int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] + return era * 146097 + doe - 719468; +} + +/* It does not modify broken-down time */ +time_t timegm_fallback(struct tm const* t) +{ + int year = t->tm_year + 1900; + int month = t->tm_mon; // 0-11 + int days_since_epoch_1970; + + if (month > 11) + { + year += month / 12; + month %= 12; + } + else if (month < 0) + { + int years_diff = (11 - month) / 12; + year -= years_diff; + month += 12 * years_diff; + } + days_since_epoch_1970 = days_from_epoch_1970(year, month + 1, t->tm_mday); + + return 60 * (60 * (24L * days_since_epoch_1970 + t->tm_hour) + t->tm_min) + t->tm_sec; +} + diff --git a/configure.ac b/configure.ac index 6afc03c33c..be40080330 100644 --- a/configure.ac +++ b/configure.ac @@ -698,17 +698,21 @@ AX_C_PRAGMAS AX_C___ATTRIBUTE__ AX_C_PRINTF_STRING_NULL +dnl Check if the system provides a boolean type and how it is spelled +NUT_CHECK_BOOL + dnl All current systems provide time.h; it need not be checked for. dnl Not all systems provide sys/time.h, but those that do, all allow dnl you to include it and time.h simultaneously. dnl NUT codebase provides the include/timehead.h to wrap these nuances. -AC_CHECK_HEADERS_ONCE([sys/time.h time.h sys/types.h sys/socket.h netdb.h]) +AC_CHECK_HEADERS_ONCE([sys/time.h time.h sys/types.h]) dnl ###obsolete### AC_HEADER_TIME AS_IF([test "$ac_cv_header_sys_time_h" = yes], [AC_DEFINE([TIME_WITH_SYS_TIME],[1],[Define to 1 if you can safely include both and . This macro is deemed obsolete by autotools.]) ], []) +AC_CHECK_HEADERS_ONCE([fcntl.h sys/stat.h sys/socket.h netdb.h]) AC_CHECK_FUNCS(flock lockf fcvt fcvtl dup dup2 abs_val abs) AC_CHECK_HEADER([float.h], @@ -782,9 +786,30 @@ SEMLIBS="" AC_CHECK_HEADER([semaphore.h], [AC_DEFINE([HAVE_SEMAPHORE_H], [1], [Define to 1 if you have .]) - AC_MSG_CHECKING([for sem_t, sem_init() and sem_destroy()]) + AC_LANG_PUSH([C]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ + myLIBS="${LIBS}" + LIBS="" + SEMLIBS_LRT="" + + dnl Solaris 8 builds complain about indirect dependency involved: + dnl sem_init nut_scanner-nut-scanner.o + dnl (symbol belongs to implicit dependency /usr/lib/librt.so.1) + AC_SEARCH_LIBS([sem_init], [pthread], [], [ + unset ac_cv_search_sem_init + AC_SEARCH_LIBS([sem_init], [pthread], [SEMLIBS_LRT=" -lrt"], [], [-lrt])]) + AC_SEARCH_LIBS([sem_open], [pthread], [], [ + unset ac_cv_search_sem_open + AC_SEARCH_LIBS([sem_open], [pthread], [SEMLIBS_LRT=" -lrt"], [], [-lrt])]) + + AS_CASE([${ac_cv_search_sem_init}], [no*], [], [SEMLIBS="${ac_cv_search_sem_init}"]) + AS_CASE([${ac_cv_search_sem_open}], [no*], [], ["${SEMLIBS}"], [], [SEMLIBS="${ac_cv_search_sem_open}"]) + SEMLIBS="${SEMLIBS}${SEMLIBS_LRT}" + + LIBS="${SEMLIBS}" + + AC_MSG_CHECKING([for sem_t, sem_init() and sem_destroy()]) + AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([ #include ], [sem_t semaphore; @@ -794,18 +819,38 @@ sem_destroy(&semaphore); * normally check for non-zero meaning to look in errno */ ] )], - [AC_DEFINE([HAVE_SEMAPHORE], [1], - [Define to 1 if you have with usable sem_t sem_init() and sem_destroy().]) + [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]) + ], + [AC_MSG_RESULT([no])] + ) - dnl Solaris 8 builds complain about indirect dependency involved: - dnl sem_init nut_scanner-nut-scanner.o - dnl (symbol belongs to implicit dependency /usr/lib/librt.so.1) - - AC_CHECK_LIB(rt, sem_init, SEMLIBS="-lrt") + AC_MSG_CHECKING([for sem_t, sem_open() and sem_close()]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#ifdef HAVE_FCNTL_H +# include /* For O_* constants */ +#endif +#ifdef SYS_STAT_H +# include /* For mode constants */ +#endif +], +[sem_t *semaphore = sem_open("/s", O_CREAT, 0644, 4); +if (semaphore != SEM_FAILED) + sem_close(semaphore); +/* Do not care about actual return value in this test, + * normally check for non-zero meaning to look in errno */ +] + )], + [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]) ], [AC_MSG_RESULT([no])] ) + + LIBS="${myLIBS}" AC_LANG_POP([C]) ] ) @@ -834,7 +879,7 @@ dnl# [], [AC_MSG_WARN([Required C library routine not found; try adding __EXTEN dnl These appear with CFLAGS="-std=c99 -D_POSIX_C_SOURCE=200112L": dnl# Methods below currently do not cause build errors for C99+ modes so are dnl# not tested as thoroughly as those further below: -AC_CHECK_FUNCS(strtok_r fileno sigemptyset sigaction, +AC_CHECK_FUNCS(strtof strtok_r fileno sigemptyset sigaction, [], [AC_MSG_WARN([Required C library routine not found; try adding -D_POSIX_C_SOURCE=200112L])]) dnl For these we have a fallback implementation via the other, @@ -863,8 +908,11 @@ AC_MSG_CHECKING([for at least one timegm implementation]) AS_IF([test x"${ac_cv_func_timegm}-${ac_cv_func__mkgmtime}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine timegm nor _mkgmtime was not found]) + AC_DEFINE_UNQUOTED([WANT_TIMEGM_FALLBACK], [1], [Defined if we want to use timegm_fallback()]) + AM_CONDITIONAL([WANT_TIMEGM_FALLBACK], [true]) ],[ AC_MSG_RESULT([yes]) + AM_CONDITIONAL([WANT_TIMEGM_FALLBACK], [false]) ]) AC_LANG_PUSH([C]) @@ -1477,6 +1525,7 @@ dnl https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-get dnl https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersinfo (before Windows XP; not recommended later) dnl Must check in global context, to have it not-defined where appropriate too NUT_CHECK_HEADER_IPHLPAPI +AC_CHECK_HEADERS_ONCE([ifaddrs.h netinet/in.h net/if.h]) AC_CHECK_FUNCS([getifaddrs], [], [ AS_CASE([${target_os}], [*mingw*], [ diff --git a/docs/Makefile.am b/docs/Makefile.am index 46794f83ca..9c3d6dfd5e 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -229,6 +229,11 @@ check-pdf: $(ASCIIDOC_PDF) # and not exactly two mentions, should allow to catch the case # of overlapping documents. Checking for the last entry allows # to catch incomplete parses, where asciidoc gave up early. +# NOTE: Technically it may be more than two, if the author and +# date were used several times in the original ChangeLog file +# (either with different e-mails, or if different author's work +# is interleaved during the day, e.g. many PRs merged, and no +# CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR=true setting was in place. # NOTE: No dependencies, avoids (re-)generation and log messages. ChangeLog.html-contentchecked: @FAILED=""; \ @@ -237,9 +242,12 @@ ChangeLog.html-contentchecked: FIRST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | head -1 | sed 's/ *[\"<].*//'`" || FIRST_ENTRY="" ; \ LAST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | tail -1 | sed 's/ *[\"<].*//'`" || LAST_ENTRY="" ; \ if [ -n "$${FIRST_ENTRY}" ] ; then \ + O="`grep -cE "^$${FIRST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${FIRST_ENTRY}" 'ChangeLog.html'`" ; \ - if [ 2 != "$${N}" ] ; then \ - echo "FAILED ChangeLog.html check: does not contain expected first entry exactly twice (huge doc, must have got aborted mid-way): $${FIRST_ENTRY} (seen $$N times)" >&2 ; \ + MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ + MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ + if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ + echo "FAILED ChangeLog.html check: does not contain expected first entry the right amount of times (huge doc, must have got aborted mid-way): $${FIRST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ @@ -248,9 +256,12 @@ ChangeLog.html-contentchecked: fi ; \ fi; \ if [ -n "$${SECOND_ENTRY}" ] ; then \ + O="`grep -cE "^$${SECOND_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${SECOND_ENTRY}" 'ChangeLog.html'`" ; \ - if [ 2 != "$${N}" ] ; then \ - echo "FAILED ChangeLog.html check: does not contain expected second entry exactly twice (huge doc, must have got aborted mid-way): $${SECOND_ENTRY} (seen $$N times)" >&2 ; \ + MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ + MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ + if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ + echo "FAILED ChangeLog.html check: does not contain expected second entry the right amount of times (huge doc, must have got aborted mid-way): $${SECOND_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ @@ -259,9 +270,12 @@ ChangeLog.html-contentchecked: fi ; \ fi; \ if [ -n "$${LAST_ENTRY}" ] ; then \ + O="`grep -cE "^$${LAST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${LAST_ENTRY}" 'ChangeLog.html'`" ; \ - if [ 2 != "$${N}" ] ; then \ - echo "FAILED ChangeLog.html check: does not contain expected last entry exactly twice (huge doc, must have got aborted mid-way): $${LAST_ENTRY} (seen $$N times)" >&2 ; \ + MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ + MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ + if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ + echo "FAILED ChangeLog.html check: does not contain expected last entry the right amount of times (huge doc, must have got aborted mid-way): $${LAST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ diff --git a/docs/config-prereqs.txt b/docs/config-prereqs.txt index 5b3d155944..2a1a450137 100644 --- a/docs/config-prereqs.txt +++ b/docs/config-prereqs.txt @@ -1400,7 +1400,11 @@ Alternatively, to prepare building sessions with `ci_build.sh` you can: NOTE: For Jenkins agents, also need to `brew install --cask temurin@21` for JRE/JDK 21. Java 17 or 21 (an LTS) is required to run Jenkins agents -after summer 2024. +after summer 2024. Note that you would have to create symbolic links to +e.g. `clang-14` and `clang++-14` in both `/usr/local/bin` (pointing to +`/bin/clang(++)` and in the `ccache` location prepared above (pointing +to `../bin/ccache`). Apparently that is the only compiler available; +various names of `gcc*` are symlinks to the same binary. Windows builds diff --git a/docs/nut.dict b/docs/nut.dict index 56ab5fd94e..d5661d3895 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1562,6 +1562,7 @@ bitmask bitness bitnesses bn +bool boolean bootable bp diff --git a/drivers/bcmxcp.c b/drivers/bcmxcp.c index 475316c217..cb45f134c5 100644 --- a/drivers/bcmxcp.c +++ b/drivers/bcmxcp.c @@ -110,15 +110,13 @@ TODO List: #include "main.h" -#include /* For ldexp() */ -#include /*for FLT_MAX */ - -#include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t, ... */ +#include "nut_float.h" /* For ldexp(), FLT_MAX */ +#include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t, ... */ #include "bcmxcp_io.h" #include "bcmxcp.h" -#define DRIVER_NAME "BCMXCP UPS driver" -#define DRIVER_VERSION "0.34" +#define DRIVER_NAME "BCMXCP UPS driver" +#define DRIVER_VERSION "0.35" #define MAX_NUT_NAME_LENGTH 128 #define NUT_OUTLET_POSITION 7 diff --git a/drivers/belkin-hid.c b/drivers/belkin-hid.c index 1baed8f00d..5b81e3b808 100644 --- a/drivers/belkin-hid.c +++ b/drivers/belkin-hid.c @@ -26,14 +26,13 @@ * */ -#include "main.h" /* for getval() */ +#include "main.h" /* for getval() */ #include "usbhid-ups.h" #include "belkin-hid.h" #include "usb-common.h" +#include "nut_float.h" /* For fabs() */ -#include /* for fabs() */ - -#define BELKIN_HID_VERSION "Belkin/Liebert HID 0.21" +#define BELKIN_HID_VERSION "Belkin/Liebert HID 0.22" /* Belkin */ #define BELKIN_VENDORID 0x050d diff --git a/drivers/isbmex.c b/drivers/isbmex.c index 8aa2512b64..eff64b12f1 100644 --- a/drivers/isbmex.c +++ b/drivers/isbmex.c @@ -22,12 +22,12 @@ #include "main.h" #include "serial.h" +#include "nut_float.h" /* For sqrt() */ -#include /* for sqrt */ #include #define DRIVER_NAME "ISBMEX UPS driver" -#define DRIVER_VERSION "0.09" +#define DRIVER_VERSION "0.10" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/drivers/libhid.c b/drivers/libhid.c index 69511b364d..5ba17b1f0f 100644 --- a/drivers/libhid.c +++ b/drivers/libhid.c @@ -39,7 +39,7 @@ #ifdef HAVE_STRINGS_H # include #endif -/* #include */ +/* #include "nut_float.h" */ #include "libhid.h" #include "hidparser.h" #include "common.h" /* for xmalloc, upsdebugx prototypes */ diff --git a/drivers/powercom.c b/drivers/powercom.c index ca1ca6bb05..660837195f 100644 --- a/drivers/powercom.c +++ b/drivers/powercom.c @@ -83,10 +83,10 @@ #include "main.h" #include "serial.h" #include "powercom.h" -#include "math.h" +#include "nut_float.h" #define DRIVER_NAME "PowerCom protocol UPS driver" -#define DRIVER_VERSION "0.22" +#define DRIVER_VERSION "0.23" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/drivers/powerp-bin.c b/drivers/powerp-bin.c index 0c7da014a0..3c6d74f00b 100644 --- a/drivers/powerp-bin.c +++ b/drivers/powerp-bin.c @@ -32,10 +32,9 @@ #include "powerp-bin.h" #include "nut_stdint.h" +#include "nut_float.h" -#include - -#define POWERPANEL_BIN_VERSION "Powerpanel-Binary 0.5" +#define POWERPANEL_BIN_VERSION "Powerpanel-Binary 0.60" typedef struct { unsigned char start; diff --git a/drivers/powerp-txt.c b/drivers/powerp-txt.c index 0390a7ca64..d13e8899a0 100644 --- a/drivers/powerp-txt.c +++ b/drivers/powerp-txt.c @@ -36,7 +36,7 @@ #include -#define POWERPANEL_TEXT_VERSION "Powerpanel-Text 0.6" +#define POWERPANEL_TEXT_VERSION "Powerpanel-Text 0.60" typedef struct { float i_volt; diff --git a/drivers/tripplite.c b/drivers/tripplite.c index d0eb70078d..cfb4d2230f 100644 --- a/drivers/tripplite.c +++ b/drivers/tripplite.c @@ -113,11 +113,11 @@ #include "serial.h" #include "tripplite.h" #include "nut_stdint.h" -#include +#include "nut_float.h" #include #define DRIVER_NAME "Tripp-Lite SmartUPS driver" -#define DRIVER_VERSION "0.95" +#define DRIVER_VERSION "0.96" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/drivers/tripplite_usb.c b/drivers/tripplite_usb.c index 753d81788a..3cf49d549a 100644 --- a/drivers/tripplite_usb.c +++ b/drivers/tripplite_usb.c @@ -132,12 +132,12 @@ #include "main.h" #include "nut_libusb.h" -#include +#include "nut_float.h" #include #include "usb-common.h" #define DRIVER_NAME "Tripp Lite OMNIVS / SMARTPRO driver" -#define DRIVER_VERSION "0.36" +#define DRIVER_VERSION "0.37" /* driver description structure */ upsdrv_info_t upsdrv_info = { diff --git a/include/Makefile.am b/include/Makefile.am index 2a2109c895..3113204671 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,9 +9,11 @@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ -dist_noinst_HEADERS = attribute.h common.h extstate.h proto.h \ - state.h str.h timehead.h upsconf.h nut_float.h nut_stdint.h nut_platform.h \ - nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp \ +dist_noinst_HEADERS = \ + attribute.h common.h extstate.h proto.h \ + state.h str.h timehead.h upsconf.h \ + nut_bool.h nut_float.h nut_stdint.h nut_platform.h \ + nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp \ wincompat.h # Optionally deliverable as part of NUT public API: diff --git a/include/nut_bool.h b/include/nut_bool.h new file mode 100644 index 0000000000..0fa4b41828 --- /dev/null +++ b/include/nut_bool.h @@ -0,0 +1,99 @@ +/* + * nut_bool.h - Network UPS Tools boolean type definitions + * which should ensure a "nut_bool_t" name with + * lower-case values "true" and "false" + * + * Inspired by earlier efforts and numerous definitions in NUT codebase. + * 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 + */ + +#ifndef NUT_BOOL_H_SEEN +#define NUT_BOOL_H_SEEN 1 + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +/* "config.h" is generated by autotools and lacks a header guard, so + * we use an unambiguously named macro we know we must have, as one. + * It must be the first header: be sure to know all about system config. + */ +#ifndef NUT_NETVERSION +# include "config.h" +#endif + +/* See also https://en.cppreference.com/w/cpp/header/cstdbool for more + * info about what should be available where per standard approach. */ +#ifdef __cplusplus +# if defined HAVE_CSTDBOOL_H || defined HAVE_CSTDBOOL +# include +# else +# ifdef HAVE_STDBOOL_H +# include +# endif +# endif +#else +/* plain C */ +# ifdef HAVE_STDBOOL_H +# include +# endif +#endif + +/* Is the goal achieved by the system headers or compiler itself, + * so we can just alias to existing type and its values? */ +#if defined __bool_true_false_are_defined && __bool_true_false_are_defined + typedef bool nut_bool_t; +#elif defined FOUND__BOOL_TYPE && defined HAVE__BOOL_VALUE_LOWERCASE + typedef FOUND__BOOL_TYPE nut_bool_t; +#elif defined FOUND_BOOL_TYPE && defined HAVE_BOOL_VALUE_LOWERCASE + typedef FOUND_BOOL_TYPE nut_bool_t; +#elif defined FOUND_BOOLEAN_TYPE && defined HAVE_BOOLEAN_VALUE_LOWERCASE + typedef FOUND_BOOLEAN_TYPE nut_bool_t; +#elif defined FOUND_BOOL_T_TYPE && defined HAVE_BOOL_T_VALUE_LOWERCASE + typedef FOUND_BOOL_T_TYPE nut_bool_t; +#else + /* Need a new type; can we use an enum with lower-case values? */ +# if (defined true && defined false) || defined HAVE__BOOL_VALUE_LOWERCASE || defined HAVE_BOOL_VALUE_LOWERCASE || defined HAVE_BOOLEAN_VALUE_LOWERCASE || defined HAVE_BOOL_T_VALUE_LOWERCASE + /* Lower-case true/false are known */ +# if defined FOUND__BOOL_TYPE + /* Got a C99 built-in mandated by the standard */ + typedef FOUND__BOOL_TYPE nut_bool_t; +# else + typedef int nut_bool_t; +# endif +# elif defined FOUND__BOOL_VALUE_TRUE && defined FOUND__BOOL_VALUE_FALSE + typedef enum nut_bool_enum { false = FOUND__BOOL_VALUE_FALSE, true = FOUND__BOOL_VALUE_TRUE } nut_bool_t; +# elif defined FOUND_BOOL_VALUE_TRUE && defined FOUND_BOOL_VALUE_FALSE + typedef enum nut_bool_enum { false = FOUND_BOOL_VALUE_FALSE, true = FOUND_BOOL_VALUE_TRUE } nut_bool_t; +# elif defined FOUND_BOOLEAN_VALUE_TRUE && defined FOUND_BOOLEAN_VALUE_FALSE + typedef enum nut_bool_enum { false = FOUND_BOOLEAN_VALUE_FALSE, true = FOUND_BOOLEAN_VALUE_TRUE } nut_bool_t; +# elif defined FOUND_BOOL_T_VALUE_TRUE && defined FOUND_BOOL_T_VALUE_FALSE + typedef enum nut_bool_enum { false = FOUND_BOOL_T_VALUE_FALSE, true = FOUND_BOOL_T_VALUE_TRUE } nut_bool_t; +# else + typedef enum nut_bool_enum { false = 0, true = 1 } nut_bool_t; +# endif +#endif + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif /* NUT_BOOL_H_SEEN */ diff --git a/include/nut_float.h b/include/nut_float.h index 0b89974b62..fe790e6e99 100644 --- a/include/nut_float.h +++ b/include/nut_float.h @@ -57,4 +57,9 @@ #define d_equal(x, y) ( fabs((double)(x) - (double)(y)) <= DBL_EPSILON ) #define ld_equal(x, y) ( fabsl((long double)(x) - (long double)(y)) <= LDBL_EPSILON ) +#ifndef HAVE_STRTOF +/* Use fallback from libcommon */ +float strtof(const char *nptr, char **endptr); +#endif + #endif /* NUT_FLOAT_H_SEEN */ diff --git a/include/timehead.h b/include/timehead.h index ed36d1b168..de72d9b8fe 100644 --- a/include/timehead.h +++ b/include/timehead.h @@ -1,8 +1,8 @@ /* timehead.h - from the autoconf docs: sanely include the right time headers everywhere - Copyright (C) 2001 Russell Kroll - 2005 Arnaud Quette - 2020 Jim Klimov + Copyright (C) 2001 Russell Kroll + 2005 Arnaud Quette + 2020-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 @@ -77,7 +77,12 @@ static inline struct tm *gmtime_r( const time_t *timer, struct tm *buf ) { # ifdef HAVE__MKGMTIME # define timegm(tm) _mkgmtime(tm) # else -# error "No fallback implementation for timegm" +# ifdef WANT_TIMEGM_FALLBACK + /* use an implementation from fallbacks in NUT codebase */ +# define timegm(tm) timegm_fallback(tm) +# else +# error "No fallback implementation for timegm" +# endif # endif #endif diff --git a/m4/nut_check_bool.m4 b/m4/nut_check_bool.m4 new file mode 100644 index 0000000000..f77d345fbc --- /dev/null +++ b/m4/nut_check_bool.m4 @@ -0,0 +1,378 @@ +dnl # For the sake of portability, check if the system offers a "bool" or a +dnl # "bool_t" type, and "true"/"false" values for it, and try to determine +dnl # how exactly these are spelled and implemented. For consumers in the +dnl # codebase, this plays along with "includes/nut_bool.h" header. +dnl # Ideally the just exists and provides reasonable types and +dnl # values (all lower-case), per the standard, which we would just alias +dnl # as "nut_bool_t" and use. +dnl # See also https://en.cppreference.com/w/cpp/header/cstdbool for more +dnl # info about what should be available where per standard approach. + +dnl # Copyright (C) 2024 by Jim Klimov + +AC_DEFUN([NUT_CHECK_BOOL], +[ +if test -z "${nut_check_bool_seen}"; then + nut_check_bool_seen="yes" + + AC_MSG_NOTICE([Checking below whether bool types are provided by system headers and how]) + + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS_ONCE([cstdbool]) + AC_LANG_POP([C++]) + + AC_LANG_PUSH([C]) + + dnl # Check for existing definition of boolean type (should be stdbool.h, but...) + AC_CHECK_HEADERS_ONCE([stdbool.h]) + + myINCLUDE_STDBOOL=" +#ifdef HAVE_STDBOOL_H +# include +#endif +" + + dnl # Below we would check for C99 built-in "_Bool", and for "bool", + dnl # "boolean" and/or "bool_t" type names with various spellings + dnl # that may come from headers like + + FOUND__BOOL_TYPE="" + FOUND__BOOL_IMPLEM_STR="" + dnl # _bool + HAVE__BOOL_TYPE_LOWERCASE=false + dnl # _BOOL + HAVE__BOOL_TYPE_UPPERCASE=false + dnl # _Bool + HAVE__BOOL_TYPE_CAMELCASE=false + + FOUND_BOOL_TYPE="" + FOUND_BOOL_IMPLEM_STR="" + dnl # bool + HAVE_BOOL_TYPE_LOWERCASE=false + dnl # BOOL + HAVE_BOOL_TYPE_UPPERCASE=false + dnl # Bool + HAVE_BOOL_TYPE_CAMELCASE=false + + FOUND_BOOLEAN_TYPE="" + FOUND_BOOLEAN_IMPLEM_STR="" + dnl # boolean + HAVE_BOOLEAN_TYPE_LOWERCASE=false + dnl # BOOLEAN + HAVE_BOOLEAN_TYPE_UPPERCASE=false + dnl # Boolean + HAVE_BOOLEAN_TYPE_CAMELCASE=false + + FOUND_BOOL_T_TYPE="" + FOUND_BOOL_T_IMPLEM_STR="" + dnl # bool_t + HAVE_BOOL_T_TYPE_LOWERCASE=false + dnl # BOOL_T + HAVE_BOOL_T_TYPE_UPPERCASE=false + dnl # Bool_t? + HAVE_BOOL_T_TYPE_CAMELCASE=false + + FOUND__BOOL_VALUE_TRUE="" + FOUND__BOOL_VALUE_FALSE="" + dnl # true/false + HAVE__BOOL_VALUE_LOWERCASE=false + dnl # TRUE/FALSE + HAVE__BOOL_VALUE_UPPERCASE=false + dnl # True/False + HAVE__BOOL_VALUE_CAMELCASE=false + + FOUND_BOOL_VALUE_TRUE="" + FOUND_BOOL_VALUE_FALSE="" + HAVE_BOOL_VALUE_LOWERCASE=false + HAVE_BOOL_VALUE_UPPERCASE=false + HAVE_BOOL_VALUE_CAMELCASE=false + + FOUND_BOOLEAN_VALUE_TRUE="" + FOUND_BOOLEAN_VALUE_FALSE="" + HAVE_BOOLEAN_VALUE_LOWERCASE=false + HAVE_BOOLEAN_VALUE_UPPERCASE=false + HAVE_BOOLEAN_VALUE_CAMELCASE=false + + FOUND_BOOL_T_VALUE_TRUE="" + FOUND_BOOL_T_VALUE_FALSE="" + HAVE_BOOL_T_VALUE_LOWERCASE=false + HAVE_BOOL_T_VALUE_UPPERCASE=false + HAVE_BOOL_T_VALUE_CAMELCASE=false + + HAVE__BOOL_IMPLEM_MACRO=false + HAVE__BOOL_IMPLEM_INT=false + HAVE__BOOL_IMPLEM_ENUM=false + + HAVE_BOOL_IMPLEM_MACRO=false + HAVE_BOOL_IMPLEM_INT=false + HAVE_BOOL_IMPLEM_ENUM=false + + HAVE_BOOLEAN_IMPLEM_MACRO=false + HAVE_BOOLEAN_IMPLEM_INT=false + HAVE_BOOLEAN_IMPLEM_ENUM=false + + HAVE_BOOL_T_IMPLEM_MACRO=false + HAVE_BOOL_T_IMPLEM_INT=false + HAVE_BOOL_T_IMPLEM_ENUM=false + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_bool b])], [HAVE__BOOL_TYPE_LOWERCASE=true; FOUND__BOOL_TYPE="_bool"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_BOOL b])], [HAVE__BOOL_TYPE_UPPERCASE=true; FOUND__BOOL_TYPE="_BOOL"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_Bool b])], [HAVE__BOOL_TYPE_CAMELCASE=true; FOUND__BOOL_TYPE="_Bool"]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [bool b])], [HAVE_BOOL_TYPE_LOWERCASE=true; FOUND_BOOL_TYPE="bool"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOL b])], [HAVE_BOOL_TYPE_UPPERCASE=true; FOUND_BOOL_TYPE="BOOL"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Bool b])], [HAVE_BOOL_TYPE_CAMELCASE=true; FOUND_BOOL_TYPE="Bool"]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [boolean b])], [HAVE_BOOLEAN_TYPE_LOWERCASE=true; FOUND_BOOLEAN_TYPE="boolean"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOLEAN b])], [HAVE_BOOLEAN_TYPE_UPPERCASE=true; FOUND_BOOLEAN_TYPE="BOOLEAN"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Boolean b])], [HAVE_BOOLEAN_TYPE_CAMELCASE=true; FOUND_BOOLEAN_TYPE="Boolean"]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [bool_t b])], [HAVE_BOOL_T_TYPE_LOWERCASE=true; FOUND_BOOL_T_TYPE="bool_t"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOL_T b])], [HAVE_BOOL_T_TYPE_UPPERCASE=true; FOUND_BOOL_T_TYPE="BOOL_T"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Bool_t b])], [HAVE_BOOL_T_TYPE_CAMELCASE=true; FOUND_BOOL_T_TYPE="Bool_t"]) + + AS_IF([test x"${FOUND__BOOL_TYPE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = true, bF = false])], [HAVE__BOOL_VALUE_LOWERCASE=true; FOUND__BOOL_VALUE_TRUE="true"; FOUND__BOOL_VALUE_FALSE="false"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = TRUE, bF = FALSE])], [HAVE__BOOL_VALUE_UPPERCASE=true; FOUND__BOOL_VALUE_TRUE="TRUE"; FOUND__BOOL_VALUE_FALSE="FALSE"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = True, bF = False])], [HAVE__BOOL_VALUE_CAMELCASE=true; FOUND__BOOL_VALUE_TRUE="True"; FOUND__BOOL_VALUE_FALSE="False"]) + ]) + + AS_IF([test x"${FOUND_BOOL_TYPE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = true, bF = false])], [HAVE_BOOL_VALUE_LOWERCASE=true; FOUND_BOOL_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = TRUE, bF = FALSE])], [HAVE_BOOL_VALUE_UPPERCASE=true; FOUND_BOOL_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = True, bF = False])], [HAVE_BOOL_VALUE_CAMELCASE=true; FOUND_BOOL_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) + ]) + + AS_IF([test x"${FOUND_BOOLEAN_TYPE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = true, bF = false])], [HAVE_BOOLEAN_VALUE_LOWERCASE=true; FOUND_BOOLEAN_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = TRUE, bF = FALSE])], [HAVE_BOOLEAN_VALUE_UPPERCASE=true; FOUND_BOOLEAN_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = True, bF = False])], [HAVE_BOOLEAN_VALUE_CAMELCASE=true; FOUND_BOOLEAN_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) + ]) + + AS_IF([test x"${FOUND_BOOL_T_TYPE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = true, bF = false])], [HAVE_BOOL_T_VALUE_LOWERCASE=true; FOUND_BOOL_T_VALUE_TRUE="true"; FOUND_BOOL_T_VALUE_FALSE="false"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = TRUE, bF = FALSE])], [HAVE_BOOL_T_VALUE_UPPERCASE=true; FOUND_BOOL_T_VALUE_TRUE="TRUE"; FOUND_BOOL_T_VALUE_FALSE="FALSE"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = True, bF = False])], [HAVE_BOOL_T_VALUE_CAMELCASE=true; FOUND_BOOL_T_VALUE_TRUE="True"; FOUND_BOOL_T_VALUE_FALSE="False"]) + ]) + + dnl # FIXME: Some more diligent checks for signed/unsigned int/char/... + dnl # type details? e.g. via sizeof, assignment to negatives, etc. + AS_IF([test x"${FOUND__BOOL_TYPE}" = x && test x"${FOUND_BOOL_TYPE}" = x && test x"${FOUND_BOOLEAN_TYPE}" = x && test x"${FOUND_BOOL_T_TYPE}" = x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = true, bF = false])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_LOWERCASE=true; FOUND_BOOL_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = TRUE, bF = FALSE])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_UPPERCASE=true; FOUND_BOOL_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = True, bF = False])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_CAMELCASE=true; FOUND_BOOL_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) + ]) + + dnl # Assume there are only 3 implementation options we can discern here + + dnl #################################################################### + + AS_IF([test x"${FOUND__BOOL_TYPE}" != x && test x"${FOUND__BOOL_VALUE_TRUE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +#ifndef ${FOUND__BOOL_VALUE_TRUE} +#error "${FOUND__BOOL_VALUE_TRUE} is not a macro +#endif +#ifndef ${FOUND__BOOL_VALUE_FALSE} +#error "${FOUND__BOOL_VALUE_FALSE} is not a macro +#endif + ])], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND__BOOL_TYPE} bT = ${FOUND__BOOL_VALUE_TRUE}; +bT = 42 + ])], [HAVE__BOOL_IMPLEM_INT=true; FOUND__BOOL_IMPLEM="number"], [HAVE__BOOL_IMPLEM_ENUM=true; FOUND__BOOL_IMPLEM="enum"]) + ], [HAVE__BOOL_IMPLEM_MACRO=true; FOUND__BOOL_IMPLEM="macro"]) + + dnl # Final check + AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND__BOOL_TYPE} b = ${FOUND__BOOL_VALUE_TRUE}; +int ret = 0; + +if (!(!b == ${FOUND__BOOL_VALUE_FALSE})) ret = 1; +if (!(b != ${FOUND__BOOL_VALUE_FALSE})) ret = 2; +if (!(!b != ${FOUND__BOOL_VALUE_TRUE})) ret = 3; +if (!b) ret = 4; +if (ret) + return ret +/* no ";return 0;" here - autoconf adds one */ + ])], + [ dnl # All tests passed, remember this + AC_MSG_NOTICE([Detected a semantically usable "_Bool"-like type name ${FOUND__BOOL_TYPE} implemented as ${FOUND__BOOL_IMPLEM} with boolean values '${FOUND__BOOL_VALUE_TRUE}' and '${FOUND__BOOL_VALUE_FALSE}']) + AC_DEFINE_UNQUOTED([FOUND__BOOL_TYPE], [${FOUND__BOOL_TYPE}], [C spelling of _Bool type]) + AC_DEFINE_UNQUOTED([FOUND__BOOL_IMPLEM_STR], ["${FOUND__BOOL_IMPLEM}"], [String spelling of _Bool type implementation]) + AC_DEFINE_UNQUOTED([FOUND__BOOL_VALUE_TRUE], [${FOUND__BOOL_VALUE_TRUE}], [C spelling of _Bool type true value]) + AC_DEFINE_UNQUOTED([FOUND__BOOL_VALUE_FALSE], [${FOUND__BOOL_VALUE_FALSE}], [C spelling of _Bool type false value]) + + AS_IF([${HAVE__BOOL_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_LOWERCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as lower-case token])]) + AS_IF([${HAVE__BOOL_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_UPPERCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as upper-case token])]) + AS_IF([${HAVE__BOOL_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_CAMELCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as camel-case token])]) + + AS_IF([${HAVE__BOOL_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as lower-case tokens])]) + AS_IF([${HAVE__BOOL_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as upper-case tokens])]) + AS_IF([${HAVE__BOOL_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as camel-case tokens])]) + + AS_IF([${HAVE__BOOL_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_INT], [1], [Boolean type ${FOUND__BOOL_TYPE} is defined as a general-purpose number type (int)])]) + AS_IF([${HAVE__BOOL_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_ENUM], [1], [Boolean type ${FOUND__BOOL_TYPE} is defined as an enum with specific values allowed])]) + AS_IF([${HAVE__BOOL_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_MACRO], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) + ], + [AC_MSG_NOTICE([Detected a "_Bool"-like type name ${FOUND__BOOL_TYPE}, but it was not semantically usable])]) + ], [AC_MSG_NOTICE([A "_Bool"-like type name or its useful values were not detected])]) + + dnl #################################################################### + + AS_IF([test x"${FOUND_BOOL_TYPE}" != x && test x"${FOUND_BOOL_VALUE_TRUE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +#ifndef ${FOUND_BOOL_VALUE_TRUE} +#error "${FOUND_BOOL_VALUE_TRUE} is not a macro +#endif +#ifndef ${FOUND_BOOL_VALUE_FALSE} +#error "${FOUND_BOOL_VALUE_FALSE} is not a macro +#endif + ])], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND_BOOL_TYPE} bT = ${FOUND_BOOL_VALUE_TRUE}; +bT = 42 + ])], [HAVE_BOOL_IMPLEM_INT=true; FOUND_BOOL_IMPLEM="number"], [HAVE_BOOL_IMPLEM_ENUM=true; FOUND_BOOL_IMPLEM="enum"]) + ], [HAVE_BOOL_IMPLEM_MACRO=true; FOUND_BOOL_IMPLEM="macro"]) + + dnl # Final check + AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND_BOOL_TYPE} b = ${FOUND_BOOL_VALUE_TRUE}; +int ret = 0; + +if (!(!b == ${FOUND_BOOL_VALUE_FALSE})) ret = 1; +if (!(b != ${FOUND_BOOL_VALUE_FALSE})) ret = 2; +if (!(!b != ${FOUND_BOOL_VALUE_TRUE})) ret = 3; +if (!b) ret = 4; +if (ret) + return ret +/* no ";return 0;" here - autoconf adds one */ + ])], + [ dnl # All tests passed, remember this + AC_MSG_NOTICE([Detected a semantically usable "bool"-like type name ${FOUND_BOOL_TYPE} implemented as ${FOUND_BOOL_IMPLEM} with boolean values '${FOUND_BOOL_VALUE_TRUE}' and '${FOUND_BOOL_VALUE_FALSE}']) + AC_DEFINE_UNQUOTED([FOUND_BOOL_TYPE], [${FOUND_BOOL_TYPE}], [C spelling of bool type]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_IMPLEM_STR], ["${FOUND_BOOL_IMPLEM}"], [String spelling of bool type implementation]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_VALUE_TRUE], [${FOUND_BOOL_VALUE_TRUE}], [C spelling of bool type true value]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_VALUE_FALSE], [${FOUND_BOOL_VALUE_FALSE}], [C spelling of bool type false value]) + + AS_IF([${HAVE_BOOL_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as lower-case token])]) + AS_IF([${HAVE_BOOL_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as upper-case token])]) + AS_IF([${HAVE_BOOL_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as camel-case token])]) + + AS_IF([${HAVE_BOOL_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as lower-case tokens])]) + AS_IF([${HAVE_BOOL_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as upper-case tokens])]) + AS_IF([${HAVE_BOOL_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as camel-case tokens])]) + + AS_IF([${HAVE_BOOL_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOL_TYPE} is defined as a general-purpose number type (int)])]) + AS_IF([${HAVE_BOOL_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOL_TYPE} is defined as an enum with specific values allowed])]) + AS_IF([${HAVE_BOOL_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) + ], + [AC_MSG_NOTICE([Detected a "bool"-like type name ${FOUND_BOOL_TYPE}, but it was not semantically usable])]) + ], [AC_MSG_NOTICE([A "bool"-like type name or its useful values were not detected])]) + + dnl #################################################################### + + AS_IF([test x"${FOUND_BOOLEAN_TYPE}" != x && test x"${FOUND_BOOLEAN_VALUE_TRUE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +#ifndef ${FOUND_BOOLEAN_VALUE_TRUE} +#error "${FOUND_BOOLEAN_VALUE_TRUE} is not a macro +#endif +#ifndef ${FOUND_BOOLEAN_VALUE_FALSE} +#error "${FOUND_BOOLEAN_VALUE_FALSE} is not a macro +#endif + ])], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND_BOOLEAN_TYPE} bT = ${FOUND_BOOLEAN_VALUE_TRUE}; +bT = 42 + ])], [HAVE_BOOLEAN_IMPLEM_INT=true; FOUND_BOOLEAN_IMPLEM="number"], [HAVE_BOOLEAN_IMPLEM_ENUM=true; FOUND_BOOLEAN_IMPLEM="enum"]) + ], [HAVE_BOOLEAN_IMPLEM_MACRO=true; FOUND_BOOLEAN_IMPLEM="macro"]) + + dnl # Final check + AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND_BOOLEAN_TYPE} b = ${FOUND_BOOLEAN_VALUE_TRUE}; +int ret = 0; + +if (!(!b == ${FOUND_BOOLEAN_VALUE_FALSE})) ret = 1; +if (!(b != ${FOUND_BOOLEAN_VALUE_FALSE})) ret = 2; +if (!(!b != ${FOUND_BOOLEAN_VALUE_TRUE})) ret = 3; +if (!b) ret = 4; +if (ret) + return ret +/* no ";return 0;" here - autoconf adds one */ + ])], + [ dnl # All tests passed, remember this + AC_MSG_NOTICE([Detected a semantically usable "boolean"-like type name ${FOUND_BOOLEAN_TYPE} implemented as ${FOUND_BOOLEAN_IMPLEM} with boolean values '${FOUND_BOOLEAN_VALUE_TRUE}' and '${FOUND_BOOL_VALUE_FALSE}']) + AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_TYPE], [${FOUND_BOOLEAN_TYPE}], [C spelling of boolean type]) + AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_IMPLEM_STR], ["${FOUND_BOOLEAN_IMPLEM}"], [String spelling of boolean type implementation]) + AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_VALUE_TRUE], [${FOUND_BOOLEAN_VALUE_TRUE}], [C spelling of boolean type true value]) + AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_VALUE_FALSE], [${FOUND_BOOLEAN_VALUE_FALSE}], [C spelling of boolean type false value]) + + AS_IF([${HAVE_BOOLEAN_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as lower-case token])]) + AS_IF([${HAVE_BOOLEAN_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as upper-case token])]) + AS_IF([${HAVE_BOOLEAN_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as camel-case token])]) + + AS_IF([${HAVE_BOOLEAN_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as lower-case tokens])]) + AS_IF([${HAVE_BOOLEAN_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as upper-case tokens])]) + AS_IF([${HAVE_BOOLEAN_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as camel-case tokens])]) + + AS_IF([${HAVE_BOOLEAN_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOLEAN_TYPE} is defined as a general-purpose number type (int)])]) + AS_IF([${HAVE_BOOLEAN_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOLEAN_TYPE} is defined as an enum with specific values allowed])]) + AS_IF([${HAVE_BOOLEAN_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) + ], + [AC_MSG_NOTICE([Detected a "boolean"-like type name ${FOUND_BOOLEAN_TYPE}, but it was not semantically usable])]) + ], [AC_MSG_NOTICE([A "boolean"-like type name or its useful values were not detected])]) + + dnl #################################################################### + + AS_IF([test x"${FOUND_BOOL_T_TYPE}" != x && test x"${FOUND_BOOL_T_VALUE_TRUE}" != x], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +#ifndef ${FOUND_BOOL_T_VALUE_TRUE} +#error "${FOUND_BOOL_T_VALUE_TRUE} is not a macro +#endif + ])], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_T_STDBOOL}], [ +${FOUND_BOOL_T_TYPE} bT = ${FOUND_BOOL_T_VALUE_TRUE}; +bT = 42 + ])], [HAVE_BOOL_T_IMPLEM_INT=true; FOUND_BOOL_T_IMPLEM="number"], [HAVE_BOOL_T_IMPLEM_ENUM=true; FOUND_BOOL_T_IMPLEM="enum"]) + ], [HAVE_BOOL_T_IMPLEM_MACRO=true; FOUND_BOOL_T_IMPLEM="macro"]) + + dnl # Final check + AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ +${FOUND_BOOL_T_TYPE} b = ${FOUND_BOOL_T_VALUE_TRUE}; +int ret = 0; + +if (!(!b == ${FOUND_BOOL_T_VALUE_FALSE})) ret = 1; +if (!(b != ${FOUND_BOOL_T_VALUE_FALSE})) ret = 2; +if (!(!b != ${FOUND_BOOL_T_VALUE_TRUE})) ret = 3; +if (!b) ret = 4; +if (ret) + return ret +/* no ";return 0;" here - autoconf adds one */ + ])], + [ dnl # All tests passed, remember this + AC_MSG_NOTICE([Detected a semantically usable "bool_t"-like type name ${FOUND_BOOL_T_TYPE} implemented as ${FOUND_BOOL_T_IMPLEM} with boolean values '${FOUND_BOOL_T_VALUE_TRUE}' and '${FOUND_BOOL_T_VALUE_FALSE}']) + AC_DEFINE_UNQUOTED([FOUND_BOOL_T_TYPE], [${FOUND_BOOL_T_TYPE}], [C spelling of bool_t type]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_T_IMPLEM_STR], ["${FOUND_BOOL_T_IMPLEM}"], [String spelling of bool_t type implementation]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_T_VALUE_TRUE], [${FOUND_BOOL_T_VALUE_TRUE}], [C spelling of bool_t type true value]) + AC_DEFINE_UNQUOTED([FOUND_BOOL_T_VALUE_FALSE], [${FOUND_BOOL_T_VALUE_FALSE}], [C spelling of bool_t type false value]) + + AS_IF([${HAVE_BOOL_T_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as lower-case token])]) + AS_IF([${HAVE_BOOL_T_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as upper-case token])]) + AS_IF([${HAVE_BOOL_T_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as camel-case token])]) + + AS_IF([${HAVE_BOOL_T_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as lower-case tokens])]) + AS_IF([${HAVE_BOOL_T_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as upper-case tokens])]) + AS_IF([${HAVE_BOOL_T_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as camel-case tokens])]) + + AS_IF([${HAVE_BOOL_T_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOL_T_TYPE} is defined as a general-purpose number type (int)])]) + AS_IF([${HAVE_BOOL_T_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOL_T_TYPE} is defined as an enum with specific values allowed])]) + AS_IF([${HAVE_BOOL_T_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) + ], + [AC_MSG_NOTICE([Detected a "bool_t"-like type name ${FOUND_BOOL_T_TYPE}, but it was not semantically usable])]) + ], [AC_MSG_NOTICE([A "bool_t"-like type name or its useful values were not detected])]) + + dnl #################################################################### + + AC_LANG_POP([C]) + +fi +]) diff --git a/m4/nut_check_libusb.m4 b/m4/nut_check_libusb.m4 index 24a04110f5..236e013355 100644 --- a/m4/nut_check_libusb.m4 +++ b/m4/nut_check_libusb.m4 @@ -88,9 +88,13 @@ if test -z "${nut_have_libusb_seen}"; then AS_IF([test x"${LIBUSB_0_1_VERSION}" != xnone], [ AS_CASE(["${target_os}"], [*mingw*], [ - AC_MSG_NOTICE([mingw builds prefer libusb-0.1(-compat) if available]) - LIBUSB_VERSION="${LIBUSB_0_1_VERSION}" - nut_usb_lib="(libusb-0.1)" + AS_IF([test x"$build" = x"$host"], [ + AC_MSG_NOTICE([mingw/MSYS2 native builds prefer libusb-0.1(-compat) over libusb-1.0 if both are available]) + LIBUSB_VERSION="${LIBUSB_0_1_VERSION}" + nut_usb_lib="(libusb-0.1)" + ],[ + AC_MSG_NOTICE([mingw cross-builds prefer libusb-1.0 over libusb-0.1(-compat) if both are available]) + ]) ]) ] ) diff --git a/m4/nut_check_pkgconfig.m4 b/m4/nut_check_pkgconfig.m4 index fd9a2449ef..4e2b6b77bd 100644 --- a/m4/nut_check_pkgconfig.m4 +++ b/m4/nut_check_pkgconfig.m4 @@ -5,7 +5,7 @@ dnl do the checking only once. AC_DEFUN([NUT_CHECK_PKGCONFIG], [ -AS_IF([test -z "${nut_have_pkg_config_seen}"], [ + AS_IF([test -z "${nut_have_pkg_config_seen}"], [ nut_have_pkg_config_seen=yes dnl Note that PKG_CONFIG may be a filename, path, @@ -83,8 +83,43 @@ AS_IF([test -z "${nut_have_pkg_config_seen}"], [ PKG_CONFIG="false" ], [AS_IF([test x"$have_PKG_CONFIG_MACROS" = xno], - [AC_MSG_WARN([pkg-config macros are needed to look for further dependencies, but in some cases pkg-config program can be used directly])] - )] + [AC_MSG_WARN([pkg-config macros are needed to look for further dependencies, but in some cases pkg-config program can be used directly])]) + + AC_MSG_CHECKING([for pkg-config envvar PKG_CONFIG_PATH (if passed to configure script)]) + AC_MSG_RESULT([${PKG_CONFIG_PATH}]) + + AC_MSG_CHECKING([for pkg-config reported pc_path]) + myPKG_CONFIG_PC_PATH="`pkg-config --variable pc_path pkg-config`" || myPKG_CONFIG_PC_PATH="" + AC_MSG_RESULT([${myPKG_CONFIG_PC_PATH}]) + + dnl # The piece below is inspired by https://github.com/wxWidgets/wxWidgets/commit/7899850496ba2707c41cc534b51d14ac5b9fdbba + dnl When cross-compiling for another system from Linux, don't use .pc files on + dnl the build system, they are at best useless and can be harmful (e.g. they + dnl may define options inappropriate for the cross-build, resulting in the + dnl failure of all the subsequent tests). + dnl + dnl However do use .pc files for the host libraries that can be found by the + dnl host-specific pkg-config if it was found by PKG_PROG_PKG_CONFIG above. + AS_IF([test x"$build" != x"$host"], [ + AS_CASE(["$PKG_CONFIG"], + [*/"$host"-pkg-config], [], + [AC_MSG_WARN([Not using native pkg-config when cross-compiling.]) + + dnl pkg.m4 forbids the use of PKG_XXX, so undo it here + dnl to avoid autoconf errors. + m4_pattern_allow([PKG_CONFIG_LIBDIR]) + + dnl If pkg-config libdir is already defined, we suppose that + dnl callers know what they're doing and leave it alone, but + dnl if not, set it to a path in which no .pc files will be found. + AS_IF([test x"$PKG_CONFIG_LIBDIR" = x], [ + AC_MSG_WARN([Exporting a hack PKG_CONFIG_LIBDIR to avoid search for .pc files in host paths]) + PKG_CONFIG_LIBDIR=/dev/null + export PKG_CONFIG_LIBDIR + ]) + ]) + ]) + ] ) ]) dnl if nut_have_pkg_config_seen diff --git a/server/upsd.c b/server/upsd.c index 92b033d61d..de4b6e6084 100644 --- a/server/upsd.c +++ b/server/upsd.c @@ -465,10 +465,12 @@ static void setuptcp(stype_t *server) fatal_with_errno(EXIT_FAILURE, "setuptcp: setsockopt"); } +#ifdef IPV6_V6ONLY /* Ordinarily we request that IPv6 listeners handle only IPv6 * and not IPv4 mapped addresses - if the OS would honour that. * TOTHINK: Does any platform need `#ifdef IPV6_V6ONLY` given * that we apparently already have AF_INET6 OS support everywhere? + * YES: Solaris 8 has IPv6 but not this symbol. */ if (ai->ai_family == AF_INET6) { if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one, sizeof(one)) != 0) { @@ -476,6 +478,7 @@ static void setuptcp(stype_t *server) /* ack, ignore */ } } +#endif if (bind(sock_fd, ai->ai_addr, ai->ai_addrlen) < 0) { upsdebug_with_errno(3, "setuptcp: bind"); diff --git a/tests/.gitignore b/tests/.gitignore index 97af77e45d..ab9969c713 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -16,6 +16,9 @@ /nuttimetest /nuttimetest.log /nuttimetest.trs +/nutbooltest +/nutbooltest.log +/nutbooltest.trs /getexponenttest-belkin-hid /getexponenttest-belkin-hid.log /getexponenttest-belkin-hid.trs diff --git a/tests/Makefile.am b/tests/Makefile.am index b2d8176f8f..47531ba8ce 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -57,6 +57,10 @@ TESTS += nuttimetest nuttimetest_SOURCES = nuttimetest.c nuttimetest_LDADD = $(top_builddir)/common/libcommon.la +TESTS += nutbooltest +nutbooltest_SOURCES = nutbooltest.c +#nutbooltest_LDADD = $(top_builddir)/common/libcommon.la + # Separate the .deps of other dirs from this one LINKED_SOURCE_FILES = hidparser.c diff --git a/tests/nutbooltest.c b/tests/nutbooltest.c new file mode 100644 index 0000000000..41f679643f --- /dev/null +++ b/tests/nutbooltest.c @@ -0,0 +1,57 @@ +/* nutbooltest.c - test custom nut_bool_t usability + * + * 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 "config.h" +#include "nut_bool.h" + +#include +#include + +int main(void) +{ + nut_bool_t bt = true, bf = false; + int ret = 0; + + /* Check basic boolean operations */ + if (bf) ret++; + if (!bt) ret++; + if (!bt == !bf) ret++; + if (bt == bf) ret++; + + if (!(!bt == bf)) ret++; + if (!(bt == !bf)) ret++; + + if (!(bt != bf)) ret++; + if (!(!bt != !bf)) ret++; + + if (bf && bt) ret++; + if (!bf && !bt) ret++; + + if (!(!bf && bt)) ret++; + if (!(bf || bt)) ret++; + if (!(!bf || !bt)) ret++; + + if (ret != 0) + printf("nutbooltest collected %i errors", ret); + + return (ret != 0); +} diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index 4b09db2578..4d481b24d5 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -70,9 +70,18 @@ #ifdef HAVE_PTHREAD # include -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) # include # endif + +# ifdef HAVE_SEMAPHORE_NAMED +# ifdef HAVE_FCNTL_H +# include /* For O_* constants with sem_open() */ +# endif +# ifdef SYS_STAT_H +# include /* For mode constants */ +# endif +# endif #endif #ifdef __cplusplus @@ -82,10 +91,25 @@ extern "C" { #endif #ifdef HAVE_PTHREAD -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) extern size_t max_threads, curr_threads, max_threads_netxml, max_threads_oldnut, max_threads_netsnmp, max_threads_ipmi; # endif +# if defined HAVE_SEMAPHORE_UNNAMED +# define REPORT_SEM_INIT_METHOD "sem_init" +# elif defined HAVE_SEMAPHORE_NAMED +# define REPORT_SEM_INIT_METHOD "sem_open" +# endif + +# ifdef HAVE_SEMAPHORE_NAMED +# define SEMNAME_TOPLEVEL "/libnutscan-toplevel-bus-scans" +# define SEMNAME_NETXML "/libnutscan-netxml" +# define SEMNAME_UPSCLIENT "/libnutscan-upsclient" +# define SEMNAME_EATON_SERIAL "/libnutscan-eaton-serial" +# define SEMNAME_SNMP "/libnutscan-snmp" +# define SEMNAME_IPMI "/libnutscan-ipmi" +# endif + # ifdef HAVE_PTHREAD_TRYJOIN extern pthread_mutex_t threadcount_mutex; # endif @@ -185,10 +209,11 @@ 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); #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Expose shared libnutscan semaphore for overall thread count * limited across different scanning methods (protocols/media): */ sem_t * nutscan_semaphore(void); +void nutscan_semaphore_set(sem_t *s); # endif #endif diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index 66358fc6bb..fac8d4c2e0 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -44,7 +44,9 @@ #ifndef WIN32 # include # include -# include +# ifdef HAVE_IFADDRS_H +# include +# endif # include # include # include @@ -63,13 +65,14 @@ # include "wincompat.h" #endif +#include "nut_stdint.h" + #ifdef HAVE_PTHREAD # include -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) # include # endif -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) -# include "nut_stdint.h" +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) # ifdef HAVE_SYS_RESOURCE_H # include /* for getrlimit() and struct rlimit */ # include @@ -78,10 +81,12 @@ * following practical investigation summarized at * https://github.com/networkupstools/nut/pull/1158 * and probably means the usual stdin/stdout/stderr triplet + * Another +1 is for NetSNMP which wants to open MIB files, + * potential per-host configuration files, etc. */ -# define RESERVE_FD_COUNT 3 +# define RESERVE_FD_COUNT 4 # endif /* HAVE_SYS_RESOURCE_H */ -# endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE */ +# endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ #include "nut-scan.h" @@ -343,6 +348,7 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) upsdebugx(3, "Entering %s('%s')", __func__, arg_addr); +#if defined HAVE_GETIFADDRS || (defined WIN32 && (defined HAVE_GETADAPTERSINFO || defined HAVE_GETADAPTERSADDRESSES)) /* Is this a `-m auto` mode? */ if (!strncmp(arg_addr, "auto", 4)) { /* TODO: Maybe split later, to allow separate @@ -418,6 +424,7 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) *auto_nets_ptr = auto_nets; } } +#endif /* HAVE_GETIFADDRS || HAVE_GETADAPTERSINFO || HAVE_GETADAPTERSADDRESSES */ if (auto_nets < 0) { /* not a supported `-m auto*` pattern => is `-m cidr` */ @@ -431,6 +438,7 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) return; } +#if defined HAVE_GETIFADDRS || (defined WIN32 && (defined HAVE_GETADAPTERSINFO || defined HAVE_GETADAPTERSADDRESSES)) /* Handle `-m auto*` modes below */ #ifdef HAVE_GETIFADDRS upsdebugx(4, "%s: using getifaddrs()", __func__); @@ -954,6 +962,11 @@ static void handle_arg_cidr(const char *arg_addr, int *auto_nets_ptr) } upsdebugx(3, "Finished %s('%s'), selected %" PRIuSIZE " subnets automatically", __func__, arg_addr, auto_subnets_found); +#else /* not (HAVE_GETIFADDRS || ( WIN32 && (HAVE_GETADAPTERSINFO || HAVE_GETADAPTERSADDRESSES))) */ + fatalx(EXIT_FAILURE, + "Have no way to query local interface addresses on this " + "platform, please run without the '-m auto*' options!"); +#endif /* HAVE_GETIFADDRS || ( WIN32 && (HAVE_GETADAPTERSINFO || HAVE_GETADAPTERSADDRESSES)) */ } static void show_usage(void) @@ -997,7 +1010,7 @@ static void show_usage(void) printf(" -E, --eaton_serial : Scan serial Eaton devices (XCP, SHUT and Q1).\n"); -#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) ) +#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) ) printf(" -T, --thread : Limit the amount of scanning threads running simultaneously (default: %" PRIuSIZE ").\n", max_threads); #else printf(" -T, --thread : Limit the amount of scanning threads running simultaneously (not implemented in this build: no pthread support)\n"); @@ -1013,7 +1026,7 @@ static void show_usage(void) printf(" -e, --end_ip : Last IP address to scan.\n"); printf(" -m, --mask_cidr : Give a range of IP using CIDR notation.\n"); printf(" -m, --mask_cidr auto: Detect local IP address(es) and scan corresponding subnet(s).\n"); -#ifdef WIN32 +#if !(defined HAVE_GETIFADDRS || (defined WIN32 && (defined HAVE_GETADAPTERSINFO || defined HAVE_GETADAPTERSADDRESSES))) printf(" (Currently not implemented for this platform)\n"); #endif printf(" -m, --mask_cidr auto4/auto6: Likewise, limiting to IPv4 or IPv6 interfaces.\n"); @@ -1164,11 +1177,11 @@ int main(int argc, char *argv[]) void (*display_func)(nutscan_device_t * device); int ret_code = EXIT_SUCCESS; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t *current_sem; # endif #endif -#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) ) && (defined HAVE_SYS_RESOURCE_H) +#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) ) && (defined HAVE_SYS_RESOURCE_H) struct rlimit nofile_limit; /* Limit the max scanning thread count by the amount of allowed open @@ -1197,7 +1210,7 @@ int main(int argc, char *argv[]) } } } -#endif /* HAVE_PTHREAD && ( HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE ) && HAVE_SYS_RESOURCE_H */ +#endif /* HAVE_PTHREAD && ( HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED ) && HAVE_SYS_RESOURCE_H */ memset(&snmp_sec, 0, sizeof(snmp_sec)); memset(&ipmi_sec, 0, sizeof(ipmi_sec)); @@ -1428,7 +1441,7 @@ int main(int argc, char *argv[]) port = strdup(optarg); break; case 'T': { -#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) ) +#if (defined HAVE_PTHREAD) && ( (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) ) char* endptr; long val = strtol(optarg, &endptr, 10); /* With endptr we check that no chars were left in optarg @@ -1569,21 +1582,40 @@ int main(int argc, char *argv[]) } #ifdef HAVE_PTHREAD -# if (defined HAVE_PTHREAD_TRYJOIN) && (defined HAVE_SEMAPHORE) - upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && HAVE_PTHREAD_TRYJOIN && HAVE_SEMAPHORE"); + { /* scoping for the string */ +# if defined HAVE_SEMAPHORE_UNNAMED + char * semsuf = "_UNNAMED"; +# elif defined HAVE_SEMAPHORE_NAMED + char * semsuf = "_NAMED"; +# else + char * semsuf = "*"; +# endif + NUT_UNUSED_VARIABLE(semsuf); /* just in case */ + +# if (defined HAVE_PTHREAD_TRYJOIN) && ((defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED)) + upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && HAVE_PTHREAD_TRYJOIN && HAVE_SEMAPHORE%s", semsuf); # elif (defined HAVE_PTHREAD_TRYJOIN) - upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && HAVE_PTHREAD_TRYJOIN && !HAVE_SEMAPHORE"); -# elif (defined HAVE_SEMAPHORE) - upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && !HAVE_PTHREAD_TRYJOIN && HAVE_SEMAPHORE"); + upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && HAVE_PTHREAD_TRYJOIN && !HAVE_SEMAPHORE*"); +# elif (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) + upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && !HAVE_PTHREAD_TRYJOIN && HAVE_SEMAPHORE%s", semsuf); # else - upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && !HAVE_PTHREAD_TRYJOIN && !HAVE_SEMAPHORE"); + upsdebugx(1, "Parallel scan support: HAVE_PTHREAD && !HAVE_PTHREAD_TRYJOIN && !HAVE_SEMAPHORE*"); # endif -# ifdef HAVE_SEMAPHORE + } + +# 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). */ current_sem = nutscan_semaphore(); +# ifdef HAVE_SEMAPHORE_UNNAMED sem_destroy(current_sem); +# elif defined HAVE_SEMAPHORE_NAMED + if (current_sem) { + sem_unlink(SEMNAME_TOPLEVEL); + sem_close(current_sem); + } +# endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif @@ -1603,15 +1635,27 @@ int main(int argc, char *argv[]) #pragma GCC diagnostic pop #endif fprintf(stderr, "\n\n" - "WARNING: Limiting max_threads to range acceptable for sem_init()\n\n"); + "WARNING: Limiting max_threads to range acceptable for " + REPORT_SEM_INIT_METHOD "()\n\n"); max_threads = UINT_MAX - 1; } upsdebugx(1, "Parallel scan support: max_threads=%" PRIuSIZE, max_threads); +# ifdef HAVE_SEMAPHORE_UNNAMED if (sem_init(current_sem, 0, (unsigned int)max_threads)) { /* Show this one to end-users so they know */ - upsdebug_with_errno(0, "Parallel scan support: sem_init() failed"); + upsdebug_with_errno(0, "Parallel scan support: " REPORT_SEM_INIT_METHOD "() failed"); + } +# elif defined HAVE_SEMAPHORE_NAMED + /* FIXME: Do we need O_EXCL here? */ + if (SEM_FAILED == (current_sem = sem_open(SEMNAME_TOPLEVEL, O_CREAT, 0644, (unsigned int)max_threads))) { + /* Show this one to end-users so they know */ + upsdebug_with_errno(0, "Parallel scan support: " REPORT_SEM_INIT_METHOD "() failed"); + current_sem = NULL; } + nutscan_semaphore_set(current_sem); +# endif + # endif #else upsdebugx(1, "Parallel scan support: !HAVE_PTHREAD"); @@ -1887,8 +1931,14 @@ int main(int argc, char *argv[]) nutscan_free_device(dev[TYPE_EATON_SERIAL]); #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# ifdef HAVE_SEMAPHORE_UNNAMED sem_destroy(nutscan_semaphore()); +# elif defined HAVE_SEMAPHORE_NAMED + if (nutscan_semaphore()) { + sem_unlink(SEMNAME_TOPLEVEL); + sem_close(nutscan_semaphore()); + nutscan_semaphore_set(NULL); + } # endif #endif diff --git a/tools/nut-scanner/nutscan-init.c b/tools/nut-scanner/nutscan-init.c index 609c9a04d2..5c81da464e 100644 --- a/tools/nut-scanner/nutscan-init.c +++ b/tools/nut-scanner/nutscan-init.c @@ -74,7 +74,7 @@ int nutscan_load_upsclient_library(const char *libname_path); int nutscan_unload_upsclient_library(void); #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# ifdef HAVE_SEMAPHORE_UNNAMED /* Shared by library consumers, exposed by nutscan_semaphore() below */ static sem_t semaphore; @@ -82,13 +82,33 @@ sem_t * nutscan_semaphore(void) { return &semaphore; } -# endif /* HAVE_SEMAPHORE */ + +void nutscan_semaphore_set(sem_t *s) +{ + NUT_UNUSED_VARIABLE(s); +} +# elif defined HAVE_SEMAPHORE_NAMED +/* Shared by library consumers, exposed by nutscan_semaphore() below. + * Methods like sem_open() return the pointer and sem_close() frees its data. + */ +static sem_t *semaphore = NULL; /* TOTHINK: maybe SEM_FAILED? */ + +sem_t * nutscan_semaphore(void) +{ + return semaphore; +} + +void nutscan_semaphore_set(sem_t *s) +{ + semaphore = s; +} +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ # ifdef HAVE_PTHREAD_TRYJOIN pthread_mutex_t threadcount_mutex; # endif -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* We have 3 networked scan types: nut, snmp, xml, * and users typically give their /24 subnet as "-m" arg. * With some systems having a 1024 default (u)limit to @@ -113,7 +133,7 @@ size_t max_threads_netsnmp = 0; /* 10240; */ */ size_t max_threads_ipmi = 0; /* limits not yet known */ -# endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE */ +# endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ @@ -148,7 +168,7 @@ void nutscan_init(void) * and the more naive but portable methods be an * if-else proposition? At least when initializing? */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* NOTE: This semaphore may get re-initialized in nut-scanner program * after parsing command-line arguments. It calls nutscan_init() before * parsing CLI, to know about available libs and to set defaults below. @@ -172,16 +192,24 @@ void nutscan_init(void) #pragma GCC diagnostic pop #endif upsdebugx(1, - "WARNING: %s: Limiting max_threads to range acceptable for sem_init()", + "WARNING: %s: Limiting max_threads to range acceptable for " REPORT_SEM_INIT_METHOD "()", __func__); max_threads = UINT_MAX - 1; } upsdebugx(1, "%s: Parallel scan support: max_threads=%" PRIuSIZE, __func__, max_threads); +# ifdef HAVE_SEMAPHORE_UNNAMED if (sem_init(&semaphore, 0, (unsigned int)max_threads)) { - upsdebug_with_errno(4, "%s: Parallel scan support: sem_init() failed", __func__); + upsdebug_with_errno(4, "%s: Parallel scan support: " REPORT_SEM_INIT_METHOD "() failed", __func__); + } +# elif defined HAVE_SEMAPHORE_NAMED + /* FIXME: Do we need O_EXCL here? */ + if (SEM_FAILED == (semaphore = sem_open(SEMNAME_TOPLEVEL, O_CREAT, 0644, (unsigned int)max_threads))) { + upsdebug_with_errno(4, "%s: Parallel scan support: " REPORT_SEM_INIT_METHOD "() failed", __func__); + semaphore = NULL; } +# endif # endif # ifdef HAVE_PTHREAD_TRYJOIN @@ -674,8 +702,14 @@ void nutscan_free(void) #ifdef HAVE_PTHREAD /* TOTHINK: See comments near mutex/semaphore init code above */ -# ifdef HAVE_SEMAPHORE +# ifdef HAVE_SEMAPHORE_UNNAMED sem_destroy(nutscan_semaphore()); +# elif defined HAVE_SEMAPHORE_NAMED + if (nutscan_semaphore()) { + sem_unlink(SEMNAME_TOPLEVEL); + sem_close(nutscan_semaphore()); + nutscan_semaphore_set(NULL); + } # endif # ifdef HAVE_PTHREAD_TRYJOIN diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c index 93f95875bf..2c462522fc 100644 --- a/tools/nut-scanner/scan_eaton_serial.c +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -419,13 +419,13 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) int current_port_nb; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t * semaphore = nutscan_semaphore(); /* TODO? Port semaphore_scantype / max_threads_scantype * from sibling sources? We do not have that many serial * ports to care much, usually... right? */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; size_t thread_count = 0, i; @@ -467,7 +467,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) * for below in pthread_join()... */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Just wait for someone to free a semaphored slot, * if none are available, and then/otherwise grab one */ @@ -506,7 +506,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) if (!thread_array[i].active) continue; pthread_mutex_lock(&threadcount_mutex); - upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + upsdebugx(3, "%s: Trying to join thread #%" PRIuSIZE "...", __func__, i); ret = pthread_tryjoin_np(thread_array[i].thread, NULL); switch (ret) { case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ @@ -547,7 +547,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) /* NOTE: No change to default "pass" in this ifdef: * if we got to this line, we have a slot to use */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ if (pass) { @@ -586,7 +586,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) current_port_nb++; } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Wait for all current scans to complete */ if (thread_array != NULL) { upsdebugx (2, "%s: Running too many scanning threads (%" @@ -619,7 +619,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) # ifdef HAVE_PTHREAD_TRYJOIN /* TODO: Move the wait-loop for TRYJOIN here? */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* if: could we "pass" or not? */ } /* while */ @@ -638,7 +638,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) __func__, ret); } thread_array[i].active = FALSE; -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_post(semaphore); # else # ifdef HAVE_PTHREAD_TRYJOIN @@ -653,7 +653,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) } pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ } free(thread_array); upsdebugx(2, "%s: all threads freed", __func__); diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 316f15bd15..0d40bfa63f 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -736,18 +736,22 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut char * ip_str = NULL; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t * semaphore = nutscan_semaphore(); +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_t semaphore_scantype_inst; sem_t * semaphore_scantype = &semaphore_scantype_inst; -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + sem_t * semaphore_scantype = NULL; +# endif +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; size_t thread_count = 0, i; -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) size_t max_threads_scantype = max_threads_ipmi; # endif -#endif +#endif /* HAVE_PTHREAD */ if (irl->ip_ranges_count == 1 && (irl->ip_ranges->start_ip == irl->ip_ranges->end_ip @@ -763,7 +767,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut #ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) if (max_threads_scantype > 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push @@ -784,17 +788,26 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut #pragma GCC diagnostic pop #endif upsdebugx(1, - "WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()", + "WARNING: %s: Limiting max_threads_scantype to range acceptable for " REPORT_SEM_INIT_METHOD "()", __func__); max_threads_scantype = UINT_MAX - 1; } - upsdebugx(4, "%s: sem_init() for %" PRIuSIZE " threads", __func__, max_threads_scantype); + upsdebugx(4, "%s: " REPORT_SEM_INIT_METHOD "() for %" PRIuSIZE " threads", __func__, max_threads_scantype); +# if (defined HAVE_SEMAPHORE_UNNAMED) if (sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype)) { - upsdebug_with_errno(4, "%s: sem_init() failed", __func__); + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + max_threads_scantype = 0; + } +# elif (defined HAVE_SEMAPHORE_NAMED) + if (SEM_FAILED == (semaphore_scantype = sem_open(SEMNAME_IPMI, O_CREAT, 0644, (unsigned int)max_threads_scantype))) { + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + semaphore_scantype = NULL; + max_threads_scantype = 0; } +# endif } -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ @@ -809,7 +822,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut * for below in pthread_join()... */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Just wait for someone to free a semaphored slot, * if none are available, and then/otherwise grab one */ @@ -869,7 +882,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut if (!thread_array[i].active) continue; pthread_mutex_lock(&threadcount_mutex); - upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + upsdebugx(3, "%s: Trying to join thread #%" PRIuSIZE "...", __func__, i); ret = pthread_tryjoin_np(thread_array[i].thread, NULL); switch (ret) { case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ @@ -912,7 +925,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut /* NOTE: No change to default "pass" in this ifdef: * if we got to this line, we have a slot to use */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ if (pass) { @@ -950,9 +963,9 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ } -#else /* if not HAVE_PTHREAD */ +#else /* if not HAVE_PTHREAD */ nutscan_scan_ipmi_device_thready(tmp_sec); -#endif /* if HAVE_PTHREAD */ +#endif /* if HAVE_PTHREAD */ /* Prepare the next iteration; note that * nutscan_scan_ipmi_device_thready() @@ -963,7 +976,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut ip_str = nutscan_ip_ranges_iter_inc(&ip); } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Wait for all current scans to complete */ if (thread_array != NULL) { upsdebugx (2, "%s: Running too many scanning threads (%" @@ -1000,7 +1013,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut # ifdef HAVE_PTHREAD_TRYJOIN /* TODO: Move the wait-loop for TRYJOIN here? */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* if: could we "pass" or not? */ } /* while */ @@ -1019,7 +1032,7 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut __func__, ret); } thread_array[i].active = FALSE; -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_post(semaphore); if (max_threads_scantype > 0) sem_post(semaphore_scantype); @@ -1036,17 +1049,26 @@ nutscan_device_t * nutscan_scan_ip_range_ipmi(nutscan_ip_range_list_t * irl, nut } pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ } free(thread_array); upsdebugx(2, "%s: all threads freed", __func__); } pthread_mutex_destroy(&dev_mutex); -# ifdef HAVE_SEMAPHORE - if (max_threads_scantype > 0) +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) + if (max_threads_scantype > 0) { +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_destroy(semaphore_scantype); -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + if (semaphore_scantype) { + sem_unlink(SEMNAME_IPMI); + sem_close(semaphore_scantype); + semaphore_scantype = NULL; + } +# endif + } +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* end of: scan range of 1+ IP address(es), maybe in parallel */ diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index da11aa53a5..76410785f5 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -333,23 +333,25 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons struct scan_nut_arg *nut_arg; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t * semaphore = nutscan_semaphore(); +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_t semaphore_scantype_inst; sem_t * semaphore_scantype = &semaphore_scantype_inst; -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + sem_t * semaphore_scantype = NULL; +# endif +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; size_t thread_count = 0, i; -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) size_t max_threads_scantype = max_threads_oldnut; # endif -#endif /* HAVE_PTHREAD */ -#ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) if (max_threads_scantype > 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push @@ -370,17 +372,26 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons #pragma GCC diagnostic pop #endif upsdebugx(1, - "WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()", + "WARNING: %s: Limiting max_threads_scantype to range acceptable for " REPORT_SEM_INIT_METHOD "()", __func__); max_threads_scantype = UINT_MAX - 1; } - upsdebugx(4, "%s: sem_init() for %" PRIuSIZE " threads", __func__, max_threads_scantype); + upsdebugx(4, "%s: " REPORT_SEM_INIT_METHOD "() for %" PRIuSIZE " threads", __func__, max_threads_scantype); +# if (defined HAVE_SEMAPHORE_UNNAMED) if (sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype)) { - upsdebug_with_errno(4, "%s: sem_init() failed", __func__); + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + max_threads_scantype = 0; + } +# elif (defined HAVE_SEMAPHORE_NAMED) + if (SEM_FAILED == (semaphore_scantype = sem_open(SEMNAME_UPSCLIENT, O_CREAT, 0644, (unsigned int)max_threads_scantype))) { + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + semaphore_scantype = NULL; + max_threads_scantype = 0; } +# endif } -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ @@ -433,7 +444,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons * for below in pthread_join()... */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Just wait for someone to free a semaphored slot, * if none are available, and then/otherwise grab one */ @@ -493,7 +504,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons if (!thread_array[i].active) continue; pthread_mutex_lock(&threadcount_mutex); - upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + upsdebugx(3, "%s: Trying to join thread #%" PRIuSIZE "...", __func__, i); ret = pthread_tryjoin_np(thread_array[i].thread, NULL); switch (ret) { case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ @@ -536,7 +547,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons /* NOTE: No change to default "pass" in this ifdef: * if we got to this line, we have a slot to use */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ if (pass) { @@ -602,7 +613,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons ip_str = nutscan_ip_ranges_iter_inc(&ip); } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Wait for all current scans to complete */ if (thread_array != NULL) { upsdebugx (2, "%s: Running too many scanning threads (%" @@ -639,7 +650,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons # ifdef HAVE_PTHREAD_TRYJOIN /* TODO: Move the wait-loop for TRYJOIN here? */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* if: could we "pass" or not? */ } /* while */ @@ -658,7 +669,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons __func__, ret); } thread_array[i].active = FALSE; -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_post(semaphore); if (max_threads_scantype > 0) sem_post(semaphore_scantype); @@ -675,17 +686,26 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons } pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ } free(thread_array); upsdebugx(2, "%s: all threads freed", __func__); } pthread_mutex_destroy(&dev_mutex); -# ifdef HAVE_SEMAPHORE - if (max_threads_scantype > 0) +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) + if (max_threads_scantype > 0) { +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_destroy(semaphore_scantype); -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + if (semaphore_scantype) { + sem_unlink(SEMNAME_UPSCLIENT); + sem_close(semaphore_scantype); + semaphore_scantype = NULL; + } +# endif + } +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ #ifndef WIN32 diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index c2f09e7d51..4f4464fb55 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -1107,21 +1107,25 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, char * ip_str = NULL; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t * semaphore = nutscan_semaphore(); +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_t semaphore_scantype_inst; sem_t * semaphore_scantype = &semaphore_scantype_inst; -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + sem_t * semaphore_scantype = NULL; +# endif +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; size_t thread_count = 0, i; -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) size_t max_threads_scantype = max_threads_netsnmp; # endif pthread_mutex_init(&dev_mutex, NULL); -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) if (max_threads_scantype > 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push @@ -1142,17 +1146,26 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, #pragma GCC diagnostic pop #endif upsdebugx(1, - "WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()", + "WARNING: %s: Limiting max_threads_scantype to range acceptable for " REPORT_SEM_INIT_METHOD "()", __func__); max_threads_scantype = UINT_MAX - 1; } - upsdebugx(4, "%s: sem_init() for %" PRIuSIZE " threads", __func__, max_threads_scantype); + upsdebugx(4, "%s: " REPORT_SEM_INIT_METHOD "() for %" PRIuSIZE " threads", __func__, max_threads_scantype); +# if (defined HAVE_SEMAPHORE_UNNAMED) if (sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype)) { - upsdebug_with_errno(4, "%s: sem_init() failed", __func__); + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + max_threads_scantype = 0; } +# elif (defined HAVE_SEMAPHORE_NAMED) + if (SEM_FAILED == (semaphore_scantype = sem_open(SEMNAME_SNMP, O_CREAT, 0644, (unsigned int)max_threads_scantype))) { + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + semaphore_scantype = NULL; + max_threads_scantype = 0; + } +# endif } -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ @@ -1199,7 +1212,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, * for below in pthread_join()... */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Just wait for someone to free a semaphored slot, * if none are available, and then/otherwise grab one */ @@ -1259,7 +1272,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, if (!thread_array[i].active) continue; pthread_mutex_lock(&threadcount_mutex); - upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + upsdebugx(3, "%s: Trying to join thread #%" PRIuSIZE "...", __func__, i); ret = pthread_tryjoin_np(thread_array[i].thread, NULL); switch (ret) { case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ @@ -1302,7 +1315,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, /* NOTE: No change to default "pass" in this ifdef: * if we got to this line, we have a slot to use */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ if (pass) { @@ -1353,7 +1366,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, ip_str = nutscan_ip_ranges_iter_inc(&ip); } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Wait for all current scans to complete */ if (thread_array != NULL) { upsdebugx (2, "%s: Running too many scanning threads (%" @@ -1390,7 +1403,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, # ifdef HAVE_PTHREAD_TRYJOIN /* TODO: Move the wait-loop for TRYJOIN here? */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* if: could we "pass" or not? */ } /* while */ @@ -1409,7 +1422,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, __func__, ret); } thread_array[i].active = FALSE; -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_post(semaphore); if (max_threads_scantype > 0) sem_post(semaphore_scantype); @@ -1426,17 +1439,26 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl, } pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ } free(thread_array); upsdebugx(2, "%s: all threads freed", __func__); } pthread_mutex_destroy(&dev_mutex); -# ifdef HAVE_SEMAPHORE - if (max_threads_scantype > 0) +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) + if (max_threads_scantype > 0) { +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_destroy(semaphore_scantype); -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + if (semaphore_scantype) { + sem_unlink(SEMNAME_SNMP); + sem_close(semaphore_scantype); + semaphore_scantype = NULL; + } +# endif + } +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ result = nutscan_rewind_device(dev_ret); diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index 9bec46f37b..f8729b499e 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -505,18 +505,22 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, char * ip_str = NULL; #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_t * semaphore = nutscan_semaphore(); +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_t semaphore_scantype_inst; sem_t * semaphore_scantype = &semaphore_scantype_inst; -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + sem_t * semaphore_scantype = NULL; +# endif +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ pthread_t thread; nutscan_thread_t * thread_array = NULL; size_t thread_count = 0, i; -# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE) +# if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) size_t max_threads_scantype = max_threads_netxml; # endif -#endif +#endif /* HAVE_PTHREAD */ if (irl->ip_ranges_count == 1 && (irl->ip_ranges->start_ip == irl->ip_ranges->end_ip @@ -532,7 +536,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, #ifdef HAVE_PTHREAD pthread_mutex_init(&dev_mutex, NULL); -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) if (max_threads_scantype > 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push @@ -553,17 +557,26 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, #pragma GCC diagnostic pop #endif upsdebugx(1, - "WARNING: %s: Limiting max_threads_scantype to range acceptable for sem_init()", + "WARNING: %s: Limiting max_threads_scantype to range acceptable for " REPORT_SEM_INIT_METHOD "()", __func__); max_threads_scantype = UINT_MAX - 1; } - upsdebugx(4, "%s: sem_init() for %" PRIuSIZE " threads", __func__, max_threads_scantype); + upsdebugx(4, "%s: " REPORT_SEM_INIT_METHOD "() for %" PRIuSIZE " threads", __func__, max_threads_scantype); +# if (defined HAVE_SEMAPHORE_UNNAMED) if (sem_init(semaphore_scantype, 0, (unsigned int)max_threads_scantype)) { - upsdebug_with_errno(4, "%s: sem_init() failed", __func__); + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + max_threads_scantype = 0; + } +# elif (defined HAVE_SEMAPHORE_NAMED) + if (SEM_FAILED == (semaphore_scantype = sem_open(SEMNAME_NETXML, O_CREAT, 0644, (unsigned int)max_threads_scantype))) { + upsdebug_with_errno(4, "%s: " REPORT_SEM_INIT_METHOD "() failed", __func__); + semaphore_scantype = NULL; + max_threads_scantype = 0; } +# endif } -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ @@ -578,7 +591,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, * for below in pthread_join()... */ -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Just wait for someone to free a semaphored slot, * if none are available, and then/otherwise grab one */ @@ -638,7 +651,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, if (!thread_array[i].active) continue; pthread_mutex_lock(&threadcount_mutex); - upsdebugx(3, "%s: Trying to join thread #%i...", __func__, i); + upsdebugx(3, "%s: Trying to join thread #%" PRIuSIZE "...", __func__, i); ret = pthread_tryjoin_np(thread_array[i].thread, NULL); switch (ret) { case ESRCH: /* No thread with the ID thread could be found - already "joined"? */ @@ -681,7 +694,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, /* NOTE: No change to default "pass" in this ifdef: * if we got to this line, we have a slot to use */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ if (pass) { @@ -722,9 +735,9 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ } -#else /* if not HAVE_PTHREAD */ +#else /* if not HAVE_PTHREAD */ nutscan_scan_xml_http_thready(tmp_sec); -#endif /* if HAVE_PTHREAD */ +#endif /* if HAVE_PTHREAD */ /* Prepare the next iteration; note that * nutscan_scan_xml_http_thready() @@ -735,7 +748,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, ip_str = nutscan_ip_ranges_iter_inc(&ip); } else { /* if not pass -- all slots busy */ #ifdef HAVE_PTHREAD -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) /* Wait for all current scans to complete */ if (thread_array != NULL) { upsdebugx (2, "%s: Running too many scanning threads (%" @@ -772,7 +785,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, # ifdef HAVE_PTHREAD_TRYJOIN /* TODO: Move the wait-loop for TRYJOIN here? */ # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ } /* if: could we "pass" or not? */ } /* while */ @@ -791,7 +804,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, __func__, ret); } thread_array[i].active = FALSE; -# ifdef HAVE_SEMAPHORE +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) sem_post(semaphore); if (max_threads_scantype > 0) sem_post(semaphore_scantype); @@ -808,17 +821,26 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl, } pthread_mutex_unlock(&threadcount_mutex); # endif /* HAVE_PTHREAD_TRYJOIN */ -# endif /* HAVE_SEMAPHORE */ +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ } free(thread_array); upsdebugx(2, "%s: all threads freed", __func__); } pthread_mutex_destroy(&dev_mutex); -# ifdef HAVE_SEMAPHORE - if (max_threads_scantype > 0) +# if (defined HAVE_SEMAPHORE_UNNAMED) || (defined HAVE_SEMAPHORE_NAMED) + if (max_threads_scantype > 0) { +# if (defined HAVE_SEMAPHORE_UNNAMED) sem_destroy(semaphore_scantype); -# endif /* HAVE_SEMAPHORE */ +# elif (defined HAVE_SEMAPHORE_NAMED) + if (semaphore_scantype) { + sem_unlink(SEMNAME_NETXML); + sem_close(semaphore_scantype); + semaphore_scantype = NULL; + } +# endif + } +# endif /* HAVE_SEMAPHORE_UNNAMED || HAVE_SEMAPHORE_NAMED */ #endif /* HAVE_PTHREAD */ result = nutscan_rewind_device(dev_ret);