diff --git a/configure.ac b/configure.ac
index 1db3350fdb..d291ac97ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,2278 +1,2281 @@
 dnl
 dnl autoconf for Pacemaker
 dnl
 dnl Copyright 2009-2024 the Pacemaker project contributors
 dnl
 dnl The version control history for this file may have further details.
 dnl
 dnl This source code is licensed under the GNU General Public License version 2
 dnl or later (GPLv2+) WITHOUT ANY WARRANTY.
 
 
 dnl ==============================================
 dnl Bootstrap autotools
 dnl ==============================================
 
 # Require a minimum version of autoconf itself
 AC_PREREQ(2.64)
 
 dnl AC_CONFIG_MACRO_DIR is deprecated as of autoconf 2.70 (2020-12-08).
 dnl Once we can require that version, we can simplify this, and no longer
 dnl need ACLOCAL_AMFLAGS in Makefile.am.
 m4_ifdef([AC_CONFIG_MACRO_DIRS],
          [AC_CONFIG_MACRO_DIRS([m4])],
          [AC_CONFIG_MACRO_DIR([m4])])
 
 m4_include([m4/version.m4])
 AC_INIT([pacemaker], VERSION_NUMBER, [users@clusterlabs.org], [pacemaker],
         PCMK_URL)
 
 LT_CONFIG_LTDL_DIR([libltdl])
 AC_CONFIG_AUX_DIR([libltdl/config])
 
 dnl Where #defines that autoconf makes (e.g. HAVE_whatever) go
 dnl
 dnl include/config.h
 dnl   - Internal API
 dnl   - Contains all defines
 dnl   - include/config.h.in is generated automatically by autoheader
 dnl   - Not to be included in any header files except crm_internal.h
 dnl     (which is also not to be included in any other header files)
 dnl
 dnl include/crm_config.h
 dnl   - External API
 dnl   - Contains a subset of defines
 dnl   - include/crm_config.h.in is manually edited to select the subset
 dnl   - Should not include HAVE_* defines
 dnl   - Safe to include anywhere
 AC_CONFIG_HEADERS([include/config.h include/crm_config.h])
 
 dnl 1.13:           minimum automake version required
 dnl foreign:        don't require GNU-standard top-level files
 dnl tar-ustar:      use (older) POSIX variant of generated tar rather than v7
 dnl subdir-objects: keep .o's with their .c's (no-op in 2.0+)
 AM_INIT_AUTOMAKE([1.13 foreign tar-ustar subdir-objects])
 
 dnl Require minimum version of pkg-config
 PKG_PROG_PKG_CONFIG(0.27)
 AS_IF([test x"${PKG_CONFIG}" != x""], [],
       [AC_MSG_FAILURE([Could not find required build tool pkg-config (0.27 or later)])])
 PKG_INSTALLDIR
 PKG_NOARCH_INSTALLDIR
 
 
 dnl ==============================================
 dnl Compiler checks and helpers
 dnl ==============================================
 
 dnl A particular compiler can be forced by setting the CC environment variable
 AC_PROG_CC
 
 dnl C++ is needed only to run maintainer utilities, not to build
 AC_PROG_CXX
 
 dnl Use at least C99 if possible (automatic for autoconf >= 2.70)
 m4_version_prereq([2.70], [:], [AC_PROG_CC_STDC])
 
 # cc_supports_flag <compiler-flag>
 #  Return success if the C compiler supports the given flag
 cc_supports_flag() {
     local CFLAGS="-Werror $@"
     AC_MSG_CHECKING([whether $CC supports $@])
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])],
                       [RC=0; AC_MSG_RESULT([yes])],
                       [RC=1; AC_MSG_RESULT([no])])
     return $RC
 }
 
 # cc_temp_flags <compiler-flags>
 #  Use the given flags for subsequent C compilation. These can be reverted to
 #  what was used previously with cc_restore_flags. This allows certain tests to
 #  use specific flags without affecting anything else.
 cc_temp_flags() {
     ac_save_CFLAGS="$CFLAGS"
     CFLAGS="$*"
 }
 
 # cc_restore_flags
 #  Restore C compiler flags to what they were before the last cc_temp_flags
 #  call.
 cc_restore_flags() {
     CFLAGS=$ac_save_CFLAGS
 }
 
 # Check for fatal warning support
 AS_IF([test $enable_fatal_warnings -ne $DISABLED dnl
        && test x"$GCC" = x"yes" && cc_supports_flag -Werror],
       [WERROR="-Werror"],
       [
           WERROR=""
           AS_CASE([$enable_fatal_warnings],
                   [$REQUIRED], [AC_MSG_ERROR([Compiler does not support fatal warnings])],
                   [$OPTIONAL], [enable_fatal_warnings=$DISABLED])
       ])
 
 dnl We use md5.c from gnulib, which has its own m4 macros. Per its docs:
 dnl "The macro gl_EARLY must be called as soon as possible after verifying that
 dnl the C compiler is working. ... The core part of the gnulib checks are done
 dnl by the macro gl_INIT." In addition, prevent gnulib from introducing OpenSSL
 dnl as a dependency.
 gl_EARLY
 gl_SET_CRYPTO_CHECK_DEFAULT([no])
 gl_INIT
 
 AC_CHECK_SIZEOF(long)
 
 
 dnl ==============================================
 dnl Linker checks
 dnl ==============================================
 
 # Check whether linker supports --enable-new-dtags to use RUNPATH instead of
 # RPATH. It is necessary to do this before libtool does linker detection.
 # See also: https://github.com/kronosnet/kronosnet/issues/107
 AX_CHECK_LINK_FLAG([-Wl,--enable-new-dtags],
                   [AM_LDFLAGS=-Wl,--enable-new-dtags],
                   [AC_MSG_ERROR(["Linker support for --enable-new-dtags is required"])])
 AC_SUBST([AM_LDFLAGS])
 
 saved_LDFLAGS="$LDFLAGS"
 LDFLAGS="$AM_LDFLAGS $LDFLAGS"
 LT_INIT([dlopen])
 LDFLAGS="$saved_LDFLAGS"
 LTDL_INIT([convenience])
 
 
 dnl ==============================================
 dnl Define configure options
 dnl ==============================================
 
 # yes_no_try <user-response> <default>
 #  Map a yes/no/try user selection to $REQUIRED for yes, $DISABLED for no, and
 #  $OPTIONAL for try.
 DISABLED=0
 REQUIRED=1
 OPTIONAL=2
 yes_no_try() {
     local value
     AS_IF([test x"$1" = x""], [value="$2"], [value="$1"])
     AS_CASE(["`echo "$value" | tr '[A-Z]' '[a-z]'`"],
             [0|no|false|disable], [return $DISABLED],
             [1|yes|true|enable], [return $REQUIRED],
             [try|check], [return $OPTIONAL]
     )
     AC_MSG_ERROR([Invalid option value "$value"])
 }
 
 #
 # Fix the defaults of certain built-in variables so they can be used in the
 # defaults for our custom arguments
 #
 
 AC_MSG_NOTICE([Sanitizing prefix: ${prefix}])
 AS_IF([test x"$prefix" = x"NONE"],
       [
           prefix=/usr
           dnl Fix default variables - "prefix" variable if not specified
           AS_IF([test x"$localstatedir" = x"\${prefix}/var"],
                 [localstatedir="/var"])
           AS_IF([test x"$sysconfdir" = x"\${prefix}/etc"],
                 [sysconfdir="/etc"])
       ])
 
 AC_MSG_NOTICE([Sanitizing exec_prefix: ${exec_prefix}])
 AS_CASE([$exec_prefix],
         [prefix|NONE], [exec_prefix=$prefix])
 
 AC_MSG_NOTICE([Sanitizing libdir: ${libdir}])
 AS_CASE([$libdir],
         [prefix|NONE], [
             AC_MSG_CHECKING([which lib directory to use])
             for aDir in lib64 lib
             do
                 trydir="${exec_prefix}/${aDir}"
                 AS_IF([test -d ${trydir}],
                       [
                           libdir=${trydir}
                           break
                       ])
             done
             AC_MSG_RESULT([$libdir])
         ])
 
 # Start a list of optional features this build supports
 PCMK_FEATURES=""
 
 dnl This section should include only the definition of configure script
 dnl options and determining their values. Processing should be done later when
 dnl possible, other than what's needed to determine values and defaults.
 
 dnl Per the autoconf docs, --enable-*/--disable-* options should control
 dnl features inherent to Pacemaker, while --with-*/--without-* options should
 dnl control the use of external software. However, --enable-*/--disable-* may
 dnl implicitly require additional external dependencies, and
 dnl --with-*/--without-* may implicitly enable or disable features, so the
 dnl line is blurry.
 dnl
 dnl We also use --with-* options for custom file, directory, and path
 dnl locations, since autoconf does not provide an option type for those.
 
 dnl --enable-* options: build process
 
 AC_ARG_ENABLE([quiet],
     [AS_HELP_STRING([--enable-quiet],
         [suppress make output unless there is an error @<:@no@:>@])]
 )
 yes_no_try "$enable_quiet" "no"
 enable_quiet=$?
 
 AC_ARG_ENABLE([fatal-warnings],
     [AS_HELP_STRING([--enable-fatal-warnings],
         [enable pedantic and fatal warnings for gcc @<:@try@:>@])],
 )
 yes_no_try "$enable_fatal_warnings" "try"
 enable_fatal_warnings=$?
 
 AC_ARG_ENABLE([hardening],
     [AS_HELP_STRING([--enable-hardening],
         [harden the resulting executables/libraries @<:@try@:>@])]
 )
 yes_no_try "$enable_hardening" "try"
 enable_hardening=$?
 
 dnl --enable-* options: features
 
 AC_ARG_ENABLE([systemd],
     [AS_HELP_STRING([--enable-systemd],
         [enable support for managing resources via systemd @<:@try@:>@])]
 )
 yes_no_try "$enable_systemd" "try"
 enable_systemd=$?
 
 AC_ARG_ENABLE([upstart],
     [AS_HELP_STRING([--enable-upstart],
         [enable support for managing resources via Upstart (deprecated) @<:@try@:>@])]
 )
 yes_no_try "$enable_upstart" "try"
 enable_upstart=$?
 
 dnl --enable-* options: features inherent to Pacemaker
 
 AC_ARG_ENABLE([compat-2.0],
     [AS_HELP_STRING([--enable-compat-2.0], m4_normalize([
         preserve certain output as it was in 2.0; this option will be
         available only for the lifetime of the 2.1 series @<:@no@:>@]))]
 )
 yes_no_try "$enable_compat_2_0" "no"
 enable_compat_2_0=$?
 
 # Add an option to create symlinks at the pre-2.0.0 daemon name locations, so
 # that users and tools can continue to invoke those names directly (e.g., for
 # meta-data). This option will be removed in a future release.
 AC_ARG_ENABLE([legacy-links],
     [AS_HELP_STRING([--enable-legacy-links],
         [add symlinks for old daemon names (deprecated) @<:@no@:>@])]
 )
 yes_no_try "$enable_legacy_links" "no"
 enable_legacy_links=$?
 
 # AM_GNU_GETTEXT calls AM_NLS which defines the nls option, but it defaults
 # to enabled. We override the definition of AM_NLS to flip the default and mark
 # it as experimental in the help text.
 AC_DEFUN([AM_NLS],
     [AC_MSG_CHECKING([whether NLS is requested])
     AC_ARG_ENABLE([nls],
         [AS_HELP_STRING([--enable-nls],
             [use Native Language Support (experimental)])],
         USE_NLS=$enableval, USE_NLS=no)
     AC_MSG_RESULT([$USE_NLS])
     AC_SUBST([USE_NLS])]
 )
 AM_GNU_GETTEXT([external])
 AM_GNU_GETTEXT_VERSION([0.18])
 
 dnl --with-* options: external software support, and custom locations
 
 dnl This argument is defined via an M4 macro so default can be a variable
 AC_DEFUN([VERSION_ARG],
     [AC_ARG_WITH([version],
         [AS_HELP_STRING([--with-version=VERSION],
             [override package version @<:@$1@:>@])],
         [ PACEMAKER_VERSION="$withval" ],
         [ PACEMAKER_VERSION="$PACKAGE_VERSION" ])]
 )
 VERSION_ARG(VERSION_NUMBER)
 
 CRM_DAEMON_USER=""
 AC_ARG_WITH([daemon-user],
     [AS_HELP_STRING([--with-daemon-user=USER],
         [user to run unprivileged Pacemaker daemons as (advanced option: changing this may break other cluster components unless similarly configured) @<:@hacluster@:>@])],
     [ CRM_DAEMON_USER="$withval" ]
 )
 AS_IF([test x"${CRM_DAEMON_USER}" = x""],
       [CRM_DAEMON_USER="hacluster"])
 
 CRM_DAEMON_GROUP=""
 AC_ARG_WITH([daemon-group],
     [AS_HELP_STRING([--with-daemon-group=GROUP],
         [group to run unprivileged Pacemaker daemons as (advanced option: changing this may break other cluster components unless similarly configured) @<:@haclient@:>@])],
     [ CRM_DAEMON_GROUP="$withval" ]
 )
 AS_IF([test x"${CRM_DAEMON_GROUP}" = x""],
       [CRM_DAEMON_GROUP="haclient"])
 
 BUG_URL=""
 AC_ARG_WITH([bug-url],
     [AS_HELP_STRING([--with-bug-url=DIR], m4_normalize([
         address where users should submit bug reports
         @<:@https://bugs.clusterlabs.org/enter_bug.cgi?product=Pacemaker@:>@]))],
     [ BUG_URL="$withval" ]
 )
 AS_IF([test x"${BUG_URL}" = x""],
       [BUG_URL="https://bugs.clusterlabs.org/enter_bug.cgi?product=Pacemaker"])
 
 dnl --with-* options: features
 
 AC_ARG_WITH([cibsecrets],
     [AS_HELP_STRING([--with-cibsecrets],
         [support separate file for CIB secrets @<:@no@:>@])]
 )
 yes_no_try "$with_cibsecrets" "no"
 with_cibsecrets=$?
 
 AC_ARG_WITH([gnutls],
     [AS_HELP_STRING([--with-gnutls],
         [support Pacemaker Remote and remote-tls-port using GnuTLS @<:@try@:>@])]
 )
 yes_no_try "$with_gnutls" "try"
 with_gnutls=$?
 
 PCMK_GNUTLS_PRIORITIES="NORMAL"
 AC_ARG_WITH([gnutls-priorities],
     [AS_HELP_STRING([--with-gnutls-priorities],
         [default GnuTLS cipher priorities @<:@NORMAL@:>@])],
     [ test x"$withval" = x"no" || PCMK_GNUTLS_PRIORITIES="$withval" ]
 )
 
 AC_ARG_WITH([concurrent-fencing-default],
     [AS_HELP_STRING([--with-concurrent-fencing-default],
         [default value for concurrent-fencing cluster option @<:@false@:>@])],
 )
 AS_CASE([$with_concurrent_fencing_default],
         [""], [with_concurrent_fencing_default="false"],
         [false], [],
         [true], [PCMK_FEATURES="$PCMK_FEATURES default-concurrent-fencing"],
         [AC_MSG_ERROR([Invalid value "$with_concurrent_fencing_default" for --with-concurrent-fencing-default])]
 )
 
 AC_ARG_WITH([sbd-sync-default],
     [AS_HELP_STRING([--with-sbd-sync-default], m4_normalize([
         default value used by sbd if SBD_SYNC_RESOURCE_STARTUP
         environment variable is not set @<:@false@:>@]))],
 )
 AS_CASE([$with_sbd_sync_default],
         [""], [with_sbd_sync_default=false],
         [false], [],
         [true], [PCMK_FEATURES="$PCMK_FEATURES default-sbd-sync"],
         [AC_MSG_ERROR([Invalid value "$with_sbd_sync_default" for --with-sbd-sync-default])]
 )
 
 AC_ARG_WITH([resource-stickiness-default],
     [AS_HELP_STRING([--with-resource-stickiness-default],
         [If positive, value to add to new CIBs as explicit resource default for resource-stickiness @<:@0@:>@])],
 )
 errmsg="Invalid value \"$with_resource_stickiness_default\" for --with-resource-stickiness-default"
 AS_CASE([$with_resource_stickiness_default],
         [0|""], [with_resource_stickiness_default="0"],
         [*[[!0-9]]*], [AC_MSG_ERROR([$errmsg])],
         [PCMK_FEATURES="$PCMK_FEATURES default-resource-stickiness"]
 )
 
 AC_ARG_WITH([corosync],
     [AS_HELP_STRING([--with-corosync],
         [support the Corosync messaging and membership layer @<:@try@:>@])]
 )
 yes_no_try "$with_corosync" "try"
 with_corosync=$?
 
 dnl Get default from Corosync if possible
 PKG_CHECK_VAR([PCMK__COROSYNC_CONF], [corosync], [corosysconfdir],
               [PCMK__COROSYNC_CONF="$PCMK__COROSYNC_CONF/corosync.conf"],
               [PCMK__COROSYNC_CONF="${sysconfdir}/corosync/corosync.conf"])
 AC_ARG_WITH([corosync-conf],
     [AS_HELP_STRING([--with-corosync-conf], m4_normalize([
         location of Corosync configuration file
         @<:@value from Corosync package if available otherwise
         SYSCONFDIR/corosync/corosync.conf@:>@]))],
     [ PCMK__COROSYNC_CONF="$withval" ]
 )
 
 AC_ARG_WITH([nagios],
     [AS_HELP_STRING([--with-nagios], [support nagios resources (deprecated)])]
 )
 yes_no_try "$with_nagios" "try"
 with_nagios=$?
 
 dnl --with-* options: directory locations
 
 AC_ARG_WITH([nagios-plugin-dir],
     [AS_HELP_STRING([--with-nagios-plugin-dir=DIR],
         [directory for nagios plugins (deprecated) @<:@LIBEXECDIR/nagios/plugins@:>@])],
     [ NAGIOS_PLUGIN_DIR="$withval" ]
 )
 
 AC_ARG_WITH([nagios-metadata-dir],
     [AS_HELP_STRING([--with-nagios-metadata-dir=DIR],
         [directory for nagios plugins metadata (deprecated) @<:@DATADIR/nagios/plugins-metadata@:>@])],
     [ NAGIOS_METADATA_DIR="$withval" ]
 )
 
 INITDIR=""
 AC_ARG_WITH([initdir],
     [AS_HELP_STRING([--with-initdir=DIR], m4_normalize([
         directory for lsb resources (init scripts), or "try" to check for
         common locations, or "no" to disable] @<:@try@:>@))],
     [ INITDIR="$withval" ]
 )
 AS_IF([test x"$INITDIR" = x""], [INITDIR="try"])
 
 systemdsystemunitdir="${systemdsystemunitdir-}"
 AC_ARG_WITH([systemdsystemunitdir],
     [AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
         [directory for systemd unit files (advanced option: must match what systemd uses)])],
     [ systemdsystemunitdir="$withval" ]
 )
 
 CONFIGDIR=""
 AC_ARG_WITH([configdir],
     [AS_HELP_STRING([--with-configdir=DIR],
         [directory for Pacemaker configuration file @<:@SYSCONFDIR/sysconfig@:>@])],
     [ CONFIGDIR="$withval" ]
 )
 
 dnl --runstatedir is available as of autoconf 2.70 (2020-12-08). When users
 dnl have an older version, they can use our --with-runstatedir.
 pcmk_runstatedir=""
 AC_ARG_WITH([runstatedir],
     [AS_HELP_STRING([--with-runstatedir=DIR],
         [modifiable per-process data @<:@LOCALSTATEDIR/run@:>@ (ignored if --runstatedir is available)])],
     [ pcmk_runstatedir="$withval" ]
 )
 
 CRM_LOG_DIR=""
 AC_ARG_WITH([logdir],
     [AS_HELP_STRING([--with-logdir=DIR],
         [directory for Pacemaker log file @<:@LOCALSTATEDIR/log/pacemaker@:>@])],
     [ CRM_LOG_DIR="$withval" ]
 )
 
 CRM_BUNDLE_DIR=""
 AC_ARG_WITH([bundledir],
     [AS_HELP_STRING([--with-bundledir=DIR],
         [directory for Pacemaker bundle logs @<:@LOCALSTATEDIR/log/pacemaker/bundles@:>@])],
     [ CRM_BUNDLE_DIR="$withval" ]
 )
 
 dnl Get default from resource-agents if possible. Otherwise, the default uses
 dnl /usr/lib rather than libdir because it's determined by the OCF project and
 dnl not Pacemaker. Even if a user wants to install Pacemaker to /usr/local or
 dnl such, the OCF agents will be expected in their usual location. However, we
 dnl do give the user the option to override it.
 PKG_CHECK_VAR([OCF_ROOT_DIR], [resource-agents], [ocfrootdir], [],
               [OCF_ROOT_DIR="/usr/lib/ocf"])
 AC_ARG_WITH([ocfdir],
     [AS_HELP_STRING([--with-ocfdir=DIR], m4_normalize([
         OCF resource agent root directory (advanced option: changing this
         may break other cluster components unless similarly configured)
         @<:@value from resource-agents package if available otherwise
         /usr/lib/ocf@:>@]))],
     [ OCF_ROOT_DIR="$withval" ]
 )
 
 dnl Get default from resource-agents if possible
 PKG_CHECK_VAR([OCF_RA_PATH], [resource-agents], [ocfrapath], [],
               [OCF_RA_PATH="$OCF_ROOT_DIR/resource.d"])
 AC_ARG_WITH([ocfrapath],
     [AS_HELP_STRING([--with-ocfrapath=DIR], m4_normalize([
         OCF resource agent directories (colon-separated) to search
         @<:@value from resource-agents package if available otherwise
         OCFDIR/resource.d@:>@]))],
     [ OCF_RA_PATH="$withval" ]
 )
 
 OCF_RA_INSTALL_DIR="$OCF_ROOT_DIR/resource.d"
 AC_ARG_WITH([ocfrainstalldir],
     [AS_HELP_STRING([--with-ocfrainstalldir=DIR], m4_normalize([
         OCF installation directory for Pacemakers resource agents
         @<:@OCFDIR/resource.d@:>@]))],
     [ OCF_RA_INSTALL_DIR="$withval" ]
 )
 
 dnl Get default from fence-agents if available
 PKG_CHECK_VAR([FA_PREFIX], [fence-agents], [prefix],
               [PCMK__FENCE_BINDIR="${FA_PREFIX}/sbin"],
               [PCMK__FENCE_BINDIR="$sbindir"])
 AC_ARG_WITH([fence-bindir],
     [AS_HELP_STRING([--with-fence-bindir=DIR], m4_normalize([
         directory for executable fence agents @<:@value from fence-agents
         package if available otherwise SBINDIR@:>@]))],
     [ PCMK__FENCE_BINDIR="$withval" ]
 )
 
 dnl --with-* options: non-production testing
 
 AC_ARG_WITH([profiling],
     [AS_HELP_STRING([--with-profiling],
         [disable optimizations, for effective profiling @<:@no@:>@])]
 )
 yes_no_try "$with_profiling" "no"
 with_profiling=$?
 
 AC_ARG_WITH([coverage],
     [AS_HELP_STRING([--with-coverage],
         [disable optimizations, for effective profiling and coverage testing @<:@no@:>@])]
 )
 yes_no_try "$with_coverage" "no"
 with_coverage=$?
 
 AC_DEFINE_UNQUOTED([PCMK__WITH_COVERAGE], [$with_coverage], [Build with code coverage])
 AM_CONDITIONAL([BUILD_COVERAGE], [test $with_coverage -ne $DISABLED])
 
 AC_ARG_WITH([sanitizers],
   [AS_HELP_STRING([--with-sanitizers=...,...],
     [enable SANitizer build, do *NOT* use for production. Only ASAN/UBSAN/TSAN are currently supported])],
   [ SANITIZERS="$withval" ],
   [ SANITIZERS="" ])
 
 dnl Environment variable options
 
 AC_ARG_VAR([CFLAGS_HARDENED_LIB], [extra C compiler flags for hardened libraries])
 AC_ARG_VAR([LDFLAGS_HARDENED_LIB], [extra linker flags for hardened libraries])
 
 AC_ARG_VAR([CFLAGS_HARDENED_EXE], [extra C compiler flags for hardened executables])
 AC_ARG_VAR([LDFLAGS_HARDENED_EXE], [extra linker flags for hardened executables])
 
 
 dnl ==============================================
 dnl Locate essential tools
 dnl ==============================================
 
 PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
 export PATH
 
 dnl Pacemaker's executable python scripts will invoke the python specified by
 dnl configure's PYTHON variable. If not specified, AM_PATH_PYTHON will check a
 dnl built-in list with (unversioned) "python" having precedence. To configure
 dnl Pacemaker to use a specific python interpreter version, define PYTHON
 dnl when calling configure, for example: ./configure PYTHON=/usr/bin/python3.6
 
 dnl If PYTHON was specified, ensure it is an absolute path
 AS_IF([test x"${PYTHON}" != x""], [AC_PATH_PROG([PYTHON], [$PYTHON])])
 
 dnl Require a minimum Python version
 AM_PATH_PYTHON([3.4])
 
 AC_PROG_LN_S
 AC_PROG_MKDIR_P
 
 AC_PATH_PROG([GIT], [git], [false])
 
 dnl Bash is needed for building man pages and running regression tests.
 dnl We set "BASH_PATH" because "BASH" is already an environment variable.
 REQUIRE_PROG([BASH_PATH], [bash])
 
 AC_PATH_PROGS(VALGRIND_BIN, valgrind, /usr/bin/valgrind)
 AC_DEFINE_UNQUOTED(VALGRIND_BIN, "$VALGRIND_BIN", Valgrind command)
 
 
 dnl ==============================================
 dnl Package and schema versioning
 dnl ==============================================
 
 # Redefine PACKAGE_VERSION and VERSION according to PACEMAKER_VERSION in case
 # the user used --with-version. Unfortunately, this can only affect the
 # substitution variables and later uses in this file, not the config.h
 # constants, so we have to be careful to use only PACEMAKER_VERSION in C code.
 PACKAGE_VERSION=$PACEMAKER_VERSION
 VERSION=$PACEMAKER_VERSION
 
 AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$VERSION",
                    [Version number of this Pacemaker build])
 
 AC_MSG_CHECKING([build version])
 AS_IF([test "$GIT" != "false" && test -d .git],
       [
           BUILD_VERSION=`"$GIT" log --pretty="format:%h" -n 1`
           AC_MSG_RESULT([$BUILD_VERSION (git hash)])
       ],
       [
           # The current directory name make a reasonable default
           # Most generated archives will include the hash or tag
           BASE=`basename $PWD`
           BUILD_VERSION=`echo $BASE | sed s:.*[[Pp]]acemaker-::`
           AC_MSG_RESULT([$BUILD_VERSION (directory name)])
       ])
 AC_DEFINE_UNQUOTED(BUILD_VERSION, "$BUILD_VERSION", Build version)
 AC_SUBST(BUILD_VERSION)
 
 # schema_files <schema-dir>
 #  List all manually edited RNG schemas (as opposed to auto-generated via make)
 #  in the given directory. Use git if available to list managed RNGs, in case
 #  there are leftover schema files from an earlier build of a different
 #  version. Otherwise, check all RNGs.
 schema_files() {
     local files="$("$GIT" ls-files "$1"/*.rng 2>/dev/null)"
 
     AS_IF([test x"$files" = x""],
           [
               files="$(ls -1 "$1"/*.rng | grep -E -v    \
                        '/(pacemaker|api-result|crm_mon|versions)[^/]*\.rng')"
           ])
     echo "$files"
 }
 
 # latest_schema_version <schema-dir>
 #  Determine highest RNG version in the given schema directory.
 latest_schema_version() {
     schema_files "$1" | sed -n -e 's/^.*-\([[0-9]][[0-9.]]*\).rng$/\1/p' dnl
                       | sort -V | tail -1
 }
 
 # schemas_for_make <schema-dir>
 #  Like schema_files, but suitable for use in make variables.
 schemas_for_make() {
     local file
 
     for file in $(schema_files "$1"); do
         AS_ECHO_N(["\$(top_srcdir)/$file "])
     done
 }
 
 # Detect highest API schema version
 API_VERSION=$(latest_schema_version "xml/api")
 AC_DEFINE_UNQUOTED([PCMK__API_VERSION], ["$API_VERSION"],
                    [Highest API schema version])
 
 # Detect highest CIB schema version
 CIB_VERSION=$(latest_schema_version "xml")
 AC_SUBST(CIB_VERSION)
 
 # Re-run configure at next make if schema files change, to re-detect versions
 cib_schemas="$(schemas_for_make "xml")"
 api_schemas="$(schemas_for_make "xml/api")"
 CONFIG_STATUS_DEPENDENCIES="$cib_schemas $api_schemas"
 AC_SUBST(CONFIG_STATUS_DEPENDENCIES)
 
 
 dnl ==============================================
 dnl Process simple options
 dnl ==============================================
 
 AS_IF([test $enable_compat_2_0 -ne $DISABLED],
       [
           AC_DEFINE_UNQUOTED([PCMK__COMPAT_2_0], [1],
                              [Keep certain output compatible with 2.0 release series])
           PCMK_FEATURES="$PCMK_FEATURES compat-2.0"
       ]
 )
 
 AM_CONDITIONAL([BUILD_LEGACY_LINKS], [test $enable_legacy_links -ne $DISABLED])
 
 AS_IF([test x"$enable_nls" = x"yes"], [PCMK_FEATURES="$PCMK_FEATURES nls"])
 
-AC_DEFINE_UNQUOTED([PCMK__CONCURRENT_FENCING_DEFAULT],
-                   ["$with_concurrent_fencing_default"],
-                   [Default value for concurrent-fencing cluster option])
+AS_IF([test x"$with_concurrent_fencing_default" = x"true"],
+      [PCMK__CONCURRENT_FENCING_DEFAULT_TRUE="1"],
+      [PCMK__CONCURRENT_FENCING_DEFAULT_TRUE="0"])
+AC_DEFINE_UNQUOTED([PCMK__CONCURRENT_FENCING_DEFAULT_TRUE],
+                   [$PCMK__CONCURRENT_FENCING_DEFAULT_TRUE],
+                   [Whether concurrent-fencing cluster option default is true])
 
 AC_DEFINE_UNQUOTED([PCMK__SBD_SYNC_DEFAULT],
                    [$with_sbd_sync_default],
                    [Default value for SBD_SYNC_RESOURCE_STARTUP environment variable])
 
 AC_DEFINE_UNQUOTED([PCMK__RESOURCE_STICKINESS_DEFAULT],
                    [$with_resource_stickiness_default],
                    [Default value for resource-stickiness resource meta-attribute])
 
 AS_IF([test x"${PCMK_GNUTLS_PRIORITIES}" != x""], [],
       [AC_MSG_ERROR([--with-gnutls-priorities value must not be empty])])
 AC_DEFINE_UNQUOTED([PCMK_GNUTLS_PRIORITIES], ["$PCMK_GNUTLS_PRIORITIES"],
                    [GnuTLS cipher priorities])
 AC_SUBST(PCMK_GNUTLS_PRIORITIES)
 
 AC_SUBST(BUG_URL)
 AC_DEFINE_UNQUOTED([PCMK__BUG_URL], ["$BUG_URL"],
                    [Where bugs should be reported])
 
 AC_DEFINE_UNQUOTED([CRM_DAEMON_USER], ["$CRM_DAEMON_USER"],
                    [User to run Pacemaker daemons as])
 AC_SUBST(CRM_DAEMON_USER)
 
 AC_DEFINE_UNQUOTED([CRM_DAEMON_GROUP], ["$CRM_DAEMON_GROUP"],
                    [Group to run Pacemaker daemons as])
 AC_SUBST(CRM_DAEMON_GROUP)
 
 
 dnl ==============================================
 dnl Process file paths
 dnl ==============================================
 
 # expand_path_option <path-variable-name> [<default>]
 #  Given the name of a file path variable, expand any variable references
 #  inside it, use the specified default if it is not specified, and ensure it
 #  is a full path.
 expand_path_option() {
     # The first argument is the variable *name* (not value)
     ac_path_varname="$1"
 
     # Get the original value of the variable
     ac_path_value=$(eval echo "\${${ac_path_varname}}")
 
     # Expand any literal variable expressions in the value so that we don't
     # end up with something like '${prefix}' in #defines etc.
     #
     # Autoconf deliberately leaves values unexpanded to allow overriding
     # the configure script choices in make commands (for example,
     # "make exec_prefix=/foo install"). No longer being able to do this seems
     # like no great loss.
     eval ac_path_value=$(eval echo "${ac_path_value}")
 
     # Use (expanded) default if necessary
     AS_IF([test x"${ac_path_value}" = x""],
           [eval ac_path_value=$(eval echo "$2")])
 
     # Require a full path
     AS_CASE(["$ac_path_value"],
             [/*], [eval ${ac_path_varname}="$ac_path_value"],
             [*], [AC_MSG_ERROR([$ac_path_varname value "$ac_path_value" is not a full path])]
     )
 }
 
 dnl Expand values of autoconf-provided directory options
 expand_path_option prefix
 expand_path_option exec_prefix
 expand_path_option bindir
 expand_path_option sbindir
 expand_path_option libexecdir
 expand_path_option datarootdir
 expand_path_option datadir
 expand_path_option sysconfdir
 expand_path_option sharedstatedir
 expand_path_option localstatedir
 expand_path_option libdir
 expand_path_option includedir
 expand_path_option oldincludedir
 expand_path_option infodir
 expand_path_option mandir
 
 AC_DEFUN([AC_DATAROOTDIR_CHECKED])
 
 dnl Expand values of custom directory options
 
 AS_IF([test x"$INITDIR" = x"try"],
       [
           AC_MSG_CHECKING([for an init directory])
           INITDIR=no
           for initdir in /etc/init.d /etc/rc.d/init.d /sbin/init.d \
                          /usr/local/etc/rc.d /etc/rc.d ${sysconfdir}/init.d
           do
               AS_IF([test -d $initdir],
                     [
                         INITDIR=$initdir
                         break
                     ])
           done
           AC_MSG_RESULT([$INITDIR])
       ])
 support_lsb=$DISABLED
 AM_CONDITIONAL([BUILD_LSB], [test x"${INITDIR}" != x"no"])
 AM_COND_IF([BUILD_LSB],
            [
                support_lsb=$REQUIRED
                expand_path_option INITDIR
                PCMK_FEATURES="$PCMK_FEATURES lsb"
            ],
            [ INITDIR="" ])
 AC_SUBST(INITDIR)
 AC_DEFINE_UNQUOTED([PCMK__ENABLE_LSB], [$support_lsb],
                    [Whether to support LSB resource agents])
 AC_DEFINE_UNQUOTED([PCMK__LSB_INIT_DIR], ["$INITDIR"],
                    [Location for LSB init scripts])
 
 expand_path_option localedir "${datadir}/locale"
 AC_DEFINE_UNQUOTED([PCMK__LOCALE_DIR],["$localedir"],
                    [Base directory for message catalogs])
 
 AS_IF([test x"${runstatedir}" = x""], [runstatedir="${pcmk_runstatedir}"])
 expand_path_option runstatedir "${localstatedir}/run"
 AC_DEFINE_UNQUOTED([PCMK_RUN_DIR], ["$runstatedir"],
                    [Location for modifiable per-process data])
 AC_SUBST(runstatedir)
 
 expand_path_option docdir "${datadir}/doc/${PACKAGE}-${VERSION}"
 AC_SUBST(docdir)
 
 expand_path_option CONFIGDIR "${sysconfdir}/sysconfig"
 AC_SUBST(CONFIGDIR)
 
 expand_path_option PCMK__COROSYNC_CONF "${sysconfdir}/corosync/corosync.conf"
 AC_SUBST(PCMK__COROSYNC_CONF)
 
 expand_path_option CRM_LOG_DIR "${localstatedir}/log/pacemaker"
 AC_DEFINE_UNQUOTED([CRM_LOG_DIR], ["$CRM_LOG_DIR"],
                    [Location for Pacemaker log file])
 AC_SUBST(CRM_LOG_DIR)
 
 expand_path_option CRM_BUNDLE_DIR "${localstatedir}/log/pacemaker/bundles"
 AC_DEFINE_UNQUOTED([CRM_BUNDLE_DIR], ["$CRM_BUNDLE_DIR"],
                    [Location for Pacemaker bundle logs])
 AC_SUBST(CRM_BUNDLE_DIR)
 
 expand_path_option PCMK__FENCE_BINDIR
 AC_SUBST(PCMK__FENCE_BINDIR)
 AC_DEFINE_UNQUOTED([PCMK__FENCE_BINDIR], ["$PCMK__FENCE_BINDIR"],
                    [Location for executable fence agents])
 
 expand_path_option OCF_ROOT_DIR
 AC_SUBST(OCF_ROOT_DIR)
 AC_DEFINE_UNQUOTED([OCF_ROOT_DIR], ["$OCF_ROOT_DIR"],
                    [OCF root directory for resource agents and libraries])
 
 expand_path_option OCF_RA_PATH
 AC_SUBST(OCF_RA_PATH)
 AC_DEFINE_UNQUOTED([OCF_RA_PATH], ["$OCF_RA_PATH"],
                    [OCF directories to search for resource agents ])
 
 expand_path_option OCF_RA_INSTALL_DIR
 AC_SUBST(OCF_RA_INSTALL_DIR)
 
 # Derived paths
 
 CRM_SCHEMA_DIRECTORY="${datadir}/pacemaker"
 AC_DEFINE_UNQUOTED([CRM_SCHEMA_DIRECTORY], ["$CRM_SCHEMA_DIRECTORY"],
                    [Location for the Pacemaker Relax-NG Schema])
 AC_SUBST(CRM_SCHEMA_DIRECTORY)
 
 PCMK__REMOTE_SCHEMA_DIR="${localstatedir}/lib/pacemaker/schemas"
 AC_DEFINE_UNQUOTED([PCMK__REMOTE_SCHEMA_DIR], ["$PCMK__REMOTE_SCHEMA_DIR"],
                    [Location to store Relax-NG Schema files on remote nodes])
 AC_SUBST(PCMK__REMOTE_SCHEMA_DIR)
 
 CRM_CORE_DIR="${localstatedir}/lib/pacemaker/cores"
 AC_DEFINE_UNQUOTED([CRM_CORE_DIR], ["$CRM_CORE_DIR"],
                    [Directory Pacemaker daemons should change to (without systemd, core files will go here)])
 AC_SUBST(CRM_CORE_DIR)
 
 CRM_PACEMAKER_DIR="${localstatedir}/lib/pacemaker"
 AC_DEFINE_UNQUOTED([CRM_PACEMAKER_DIR], ["$CRM_PACEMAKER_DIR"],
                    [Location to store directory produced by Pacemaker daemons])
 AC_SUBST(CRM_PACEMAKER_DIR)
 
 CRM_BLACKBOX_DIR="${localstatedir}/lib/pacemaker/blackbox"
 AC_DEFINE_UNQUOTED([CRM_BLACKBOX_DIR], ["$CRM_BLACKBOX_DIR"],
                    [Where to keep blackbox dumps])
 AC_SUBST(CRM_BLACKBOX_DIR)
 
 PE_STATE_DIR="${localstatedir}/lib/pacemaker/pengine"
 AC_DEFINE_UNQUOTED([PE_STATE_DIR], ["$PE_STATE_DIR"],
                    [Where to keep scheduler outputs])
 AC_SUBST(PE_STATE_DIR)
 
 CRM_CONFIG_DIR="${localstatedir}/lib/pacemaker/cib"
 AC_DEFINE_UNQUOTED([CRM_CONFIG_DIR], ["$CRM_CONFIG_DIR"],
                    [Where to keep configuration files])
 AC_SUBST(CRM_CONFIG_DIR)
 
 CRM_DAEMON_DIR="${libexecdir}/pacemaker"
 AC_DEFINE_UNQUOTED([CRM_DAEMON_DIR], ["$CRM_DAEMON_DIR"],
                    [Location for Pacemaker daemons])
 AC_SUBST(CRM_DAEMON_DIR)
 
 CRM_STATE_DIR="${runstatedir}/crm"
 AC_DEFINE_UNQUOTED([CRM_STATE_DIR], ["$CRM_STATE_DIR"],
                    [Where to keep state files and sockets])
 AC_SUBST(CRM_STATE_DIR)
 
 CRM_RSCTMP_DIR="${runstatedir}/resource-agents"
 AC_DEFINE_UNQUOTED([CRM_RSCTMP_DIR], ["$CRM_RSCTMP_DIR"],
                    [Where resource agents should keep state files])
 AC_SUBST(CRM_RSCTMP_DIR)
 
 PACEMAKER_CONFIG_DIR="${sysconfdir}/pacemaker"
 AC_DEFINE_UNQUOTED([PACEMAKER_CONFIG_DIR], ["$PACEMAKER_CONFIG_DIR"],
                    [Where to keep configuration files like authkey])
 AC_SUBST(PACEMAKER_CONFIG_DIR)
 
 AC_DEFINE_UNQUOTED([SBIN_DIR], ["$sbindir"], [Location for system binaries])
 
 # Warn about any directories that don't exist (which may be OK)
 for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
     sharedstatedir localstatedir libdir includedir oldincludedir infodir \
     mandir INITDIR docdir CONFIGDIR localedir
 do
     dirname=`eval echo '${'${j}'}'`
     AS_IF([test -n "$dirname" && test ! -d "$dirname"],
           [AC_MSG_WARN([$j directory ($dirname) does not exist (yet)])])
 done
 
 dnl ===============================================
 dnl General Processing
 dnl ===============================================
 
 us_auth=
 AC_CHECK_HEADER([sys/socket.h], [
     AC_CHECK_DECL([SO_PEERCRED], [
         # Linux
         AC_CHECK_TYPE([struct ucred], [
             us_auth=peercred_ucred;
             AC_DEFINE([HAVE_UCRED], [1],
                       [Define if Unix socket auth method is
                        getsockopt(s, SO_PEERCRED, &ucred, ...)])
         ], [
             # OpenBSD
             AC_CHECK_TYPE([struct sockpeercred], [
                 us_auth=localpeercred_sockepeercred;
                 AC_DEFINE([HAVE_SOCKPEERCRED], [1],
                           [Define if Unix socket auth method is
                            getsockopt(s, SO_PEERCRED, &sockpeercred, ...)])
             ], [], [[#include <sys/socket.h>]])
         ], [[#define _GNU_SOURCE
              #include <sys/socket.h>]])
     ], [], [[#include <sys/socket.h>]])
 ])
 
 AS_IF([test -z "${us_auth}"], [
     # FreeBSD
     AC_CHECK_DECL([getpeereid], [
         us_auth=getpeereid;
         AC_DEFINE([HAVE_GETPEEREID], [1],
                   [Define if Unix socket auth method is
                    getpeereid(s, &uid, &gid)])
     ], [
         # Solaris/OpenIndiana
         AC_CHECK_DECL([getpeerucred], [
             us_auth=getpeerucred;
             AC_DEFINE([HAVE_GETPEERUCRED], [1],
                       [Define if Unix socket auth method is
                        getpeercred(s, &ucred)])
         ], [
             AC_MSG_FAILURE([No way to authenticate a Unix socket peer])
         ], [[#include <ucred.h>]])
     ])
 ])
 
 dnl OS-based decision-making is poor autotools practice; feature-based
 dnl mechanisms are strongly preferred. Keep this section to a bare minimum;
 dnl regard as a "necessary evil".
 
 dnl Set host_os and host_cpu
 AC_CANONICAL_HOST
 
 INIT_EXT=""
 PROCFS=0
 dnl Solaris and some *BSD versions support procfs but not files we need
 AS_CASE(["$host_os"],
         [*bsd*], [INIT_EXT=".sh"],
         [*linux*], [PROCFS=1],
         [darwin*], [
             LIBS="$LIBS -L${prefix}/lib"
             CFLAGS="$CFLAGS -I${prefix}/include"
         ])
 
 AC_SUBST(INIT_EXT)
 AM_CONDITIONAL([SUPPORT_PROCFS], [test $PROCFS -eq 1])
 AC_DEFINE_UNQUOTED([HAVE_LINUX_PROCFS], [$PROCFS],
                    [Define to 1 if procfs is supported])
 
 AS_CASE(["$host_cpu"],
         [ppc64|powerpc64], [
             AS_CASE([$CFLAGS],
                     [*powerpc64*], [],
                     [*], [AS_IF([test x"$GCC" = x"yes"], [CFLAGS="$CFLAGS -m64"])
                     ])
         ])
 
 
 dnl ==============================================
 dnl Documentation build dependencies and checks
 dnl ==============================================
 
 AC_PATH_PROGS([ASCIIDOC_CONV], [asciidoc asciidoctor])
 AC_PATH_PROG([HELP2MAN], [help2man])
 AC_PATH_PROG([SPHINX], [sphinx-build])
 AC_PATH_PROG([INKSCAPE], [inkscape])
 AC_PATH_PROG([XSLTPROC], [xsltproc])
 AC_PATH_PROG([XMLCATALOG], [xmlcatalog])
 
 AM_CONDITIONAL(BUILD_HELP, test x"${HELP2MAN}" != x"")
 AS_IF([test x"${HELP2MAN}" != x""],
       [PCMK_FEATURES="$PCMK_FEATURES generated-manpages"])
 
 MANPAGE_XSLT=""
 AS_IF([test x"${XSLTPROC}" != x""],
       [
           AC_MSG_CHECKING([for DocBook-to-manpage transform])
           # first try to figure out correct template using xmlcatalog query,
           # resort to extensive (semi-deterministic) file search if that fails
           DOCBOOK_XSL_URI='http://docbook.sourceforge.net/release/xsl/current'
           DOCBOOK_XSL_PATH='manpages/docbook.xsl'
           MANPAGE_XSLT=$(${XMLCATALOG} "" ${DOCBOOK_XSL_URI}/${DOCBOOK_XSL_PATH} \
                          | sed -n 's|^file://||p;q')
           AS_IF([test x"${MANPAGE_XSLT}" = x""],
                 [
                     DIRS=$(find "${datadir}" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \
                            -type d 2>/dev/null | LC_ALL=C sort)
                     XSLT=$(basename ${DOCBOOK_XSL_PATH})
                     for d in ${DIRS}
                     do
                         AS_IF([test -f "${d}/${XSLT}"],
                               [
                                   MANPAGE_XSLT="${d}/${XSLT}"
                                   break
                               ])
                     done
                 ])
       ])
 AC_MSG_RESULT([$MANPAGE_XSLT])
 AC_SUBST(MANPAGE_XSLT)
 
 AM_CONDITIONAL(BUILD_XML_HELP, test x"${MANPAGE_XSLT}" != x"")
 AS_IF([test x"${MANPAGE_XSLT}" != x""],
       [PCMK_FEATURES="$PCMK_FEATURES agent-manpages"])
 
 AM_CONDITIONAL([IS_ASCIIDOC], [echo "${ASCIIDOC_CONV}" | grep -Eq 'asciidoc$'])
 AM_CONDITIONAL([BUILD_ASCIIDOC], [test "x${ASCIIDOC_CONV}" != x])
 AS_IF([test x"${ASCIIDOC_CONV}" != x""],
       [PCMK_FEATURES="$PCMK_FEATURES ascii-docs"])
 
 AM_CONDITIONAL([BUILD_SPHINX_DOCS],
                [test x"${SPHINX}" != x"" && test x"${INKSCAPE}" != x""])
 AM_COND_IF([BUILD_SPHINX_DOCS], [PCMK_FEATURES="$PCMK_FEATURES books"])
 
 dnl Pacemaker's shell scripts (and thus man page builders) rely on GNU getopt
 AC_MSG_CHECKING([for GNU-compatible getopt])
 IFS_orig=$IFS
 IFS=:
 for PATH_DIR in $PATH
 do
     IFS=$IFS_orig
     GETOPT_PATH="${PATH_DIR}/getopt"
     AS_IF([test -f "$GETOPT_PATH" && test -x "$GETOPT_PATH"],
           [
               $GETOPT_PATH -T >/dev/null 2>/dev/null
               AS_IF([test $? -eq 4], [break])
           ])
     GETOPT_PATH=""
 done
 IFS=$IFS_orig
 AS_IF([test -n "$GETOPT_PATH"], [AC_MSG_RESULT([$GETOPT_PATH])],
       [
           AC_MSG_RESULT([no])
           AC_MSG_ERROR([Could not find required build tool GNU-compatible getopt])
       ])
 AC_SUBST([GETOPT_PATH])
 
 
 dnl ===============================================
 dnl Libraries
 dnl ===============================================
 AC_CHECK_LIB(socket, socket)                    dnl -lsocket
 AC_CHECK_LIB(c, dlopen)                         dnl if dlopen is in libc...
 AC_CHECK_LIB(dl, dlopen)                        dnl -ldl (for Linux)
 AC_CHECK_LIB(rt, sched_getscheduler)            dnl -lrt (for Tru64)
 AC_CHECK_LIB(gnugetopt, getopt_long)            dnl -lgnugetopt ( if available )
 AC_CHECK_LIB(pam, pam_start)                    dnl -lpam (if available)
 
 PKG_CHECK_MODULES([UUID], [uuid],
                   [CPPFLAGS="${CPPFLAGS} ${UUID_CFLAGS}"
                    LIBS="${LIBS} ${UUID_LIBS}"])
 
 AC_CHECK_FUNCS([sched_setscheduler])
 AS_IF([test x"$ac_cv_func_sched_setscheduler" != x"yes"],
       [PC_LIBS_RT=""],
       [PC_LIBS_RT="-lrt"])
 AC_SUBST(PC_LIBS_RT)
 
 # Require minimum glib version
 PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.42.0],
                   [CPPFLAGS="${CPPFLAGS} ${GLIB_CFLAGS}"
                    LIBS="${LIBS} ${GLIB_LIBS}"])
 
 # Check whether high-resolution sleep function is available
 AC_CHECK_FUNCS([nanosleep usleep])
 
 #
 # Where is dlopen?
 #
 AS_IF([test x"$ac_cv_lib_c_dlopen" = x"yes"],
       [LIBADD_DL=""],
       [test x"$ac_cv_lib_dl_dlopen" = x"yes"],
       [LIBADD_DL=-ldl],
       [LIBADD_DL=${lt_cv_dlopen_libs}])
 
 PKG_CHECK_MODULES(LIBXML2, [libxml-2.0 >= 2.6.0],
                   [CPPFLAGS="${CPPFLAGS} ${LIBXML2_CFLAGS}"
                    LIBS="${LIBS} ${LIBXML2_LIBS}"])
 
 REQUIRE_LIB([xslt], [xsltApplyStylesheet])
 
 AC_MSG_CHECKING([whether __progname and __progname_full are available])
 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern char *__progname, *__progname_full;]],
                                 [[__progname = "foo";
                                   __progname_full = "foo bar";]])],
                [
                    have_progname="yes"
                    AC_DEFINE(HAVE_PROGNAME, 1,
                              [Define to 1 if processes can change their name])
                ],
                [have_progname="no"])
 AC_MSG_RESULT([$have_progname])
 
 dnl ========================================================================
 dnl Headers
 dnl ========================================================================
 
 # Some distributions insert #warnings into deprecated headers. If we will
 # enable fatal warnings for the build, then enable them for the header checks
 # as well, otherwise the build could fail even though the header check
 # succeeds. (We should probably be doing this in more places.)
 cc_temp_flags "$CFLAGS $WERROR"
 
 # Optional headers (inclusion of these should be conditional in C code)
 AC_CHECK_HEADERS([linux/swab.h])
 AC_CHECK_HEADERS([stddef.h])
 AC_CHECK_HEADERS([sys/signalfd.h])
 AC_CHECK_HEADERS([uuid/uuid.h])
 AC_CHECK_HEADERS([security/pam_appl.h pam/pam_appl.h])
 
 # Required headers
 REQUIRE_HEADER([arpa/inet.h])
 REQUIRE_HEADER([ctype.h])
 REQUIRE_HEADER([dirent.h])
 REQUIRE_HEADER([dlfcn.h])
 REQUIRE_HEADER([errno.h])
 REQUIRE_HEADER([fcntl.h])
 REQUIRE_HEADER([float.h])
 REQUIRE_HEADER([glib.h])
 REQUIRE_HEADER([grp.h])
 REQUIRE_HEADER([inttypes.h])
 REQUIRE_HEADER([libgen.h])
 REQUIRE_HEADER([limits.h])
 REQUIRE_HEADER([locale.h])
 REQUIRE_HEADER([netdb.h])
 REQUIRE_HEADER([netinet/in.h])
 REQUIRE_HEADER([netinet/ip.h], [
     #include <sys/types.h>
     #include <netinet/in.h>
 ])
 REQUIRE_HEADER([netinet/tcp.h])
 REQUIRE_HEADER([pwd.h])
 REQUIRE_HEADER([regex.h])
 REQUIRE_HEADER([sched.h])
 REQUIRE_HEADER([signal.h])
 REQUIRE_HEADER([stdarg.h])
 REQUIRE_HEADER([stdbool.h])
 REQUIRE_HEADER([stdint.h])
 REQUIRE_HEADER([stdio.h])
 REQUIRE_HEADER([stdlib.h])
 REQUIRE_HEADER([string.h])
 REQUIRE_HEADER([strings.h])
 REQUIRE_HEADER([sys/ioctl.h])
 REQUIRE_HEADER([sys/param.h])
 REQUIRE_HEADER([sys/reboot.h])
 REQUIRE_HEADER([sys/resource.h])
 REQUIRE_HEADER([sys/socket.h])
 REQUIRE_HEADER([sys/stat.h])
 REQUIRE_HEADER([sys/time.h])
 REQUIRE_HEADER([sys/types.h])
 REQUIRE_HEADER([sys/uio.h])
 REQUIRE_HEADER([sys/utsname.h])
 REQUIRE_HEADER([sys/wait.h])
 REQUIRE_HEADER([termios.h])
 REQUIRE_HEADER([time.h])
 REQUIRE_HEADER([unistd.h])
 REQUIRE_HEADER([libxml/xpath.h])
 REQUIRE_HEADER([libxslt/xslt.h])
 
 cc_restore_flags
 
 dnl ========================================================================
 dnl Generic declarations
 dnl ========================================================================
 
 AC_CHECK_DECLS([CLOCK_MONOTONIC], [PCMK_FEATURES="$PCMK_FEATURES monotonic"], [], [[
     #include <time.h>
 ]])
 
 dnl ========================================================================
 dnl Unit test declarations
 dnl ========================================================================
 
 AC_CHECK_DECLS([assert_float_equal], [], [], [[
     #include <stdarg.h>
     #include <stddef.h>
     #include <setjmp.h>
     #include <cmocka.h>
 ]])
 
 dnl ========================================================================
 dnl Byte size
 dnl ========================================================================
 
 # Compile-time assert hack
 # https://jonjagger.blogspot.com/2017/07/compile-time-assertions-in-c.html
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <limits.h>]],
                                    [[
                                         switch (0) {
                                             case 0:
                                             case (CHAR_BIT == 8):
                                                 break;
                                         }
                                    ]])],
                   [],
                   [AC_MSG_FAILURE(m4_normalize([Pacemaker is not supported on
                                                 platforms where char is not 8
                                                 bits]))])
 
 dnl ========================================================================
 dnl Structures
 dnl ========================================================================
 
 AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[[#include <time.h>]])
 AC_CHECK_MEMBER([struct dirent.d_type],
     AC_DEFINE(HAVE_STRUCT_DIRENT_D_TYPE,1,[Define this if struct dirent has d_type]),,
     [#include <dirent.h>])
 
 dnl ========================================================================
 dnl Functions
 dnl ========================================================================
 
 REQUIRE_FUNC([alphasort])
 REQUIRE_FUNC([getopt])
 REQUIRE_FUNC([scandir])
 REQUIRE_FUNC([setenv])
 REQUIRE_FUNC([strndup])
 REQUIRE_FUNC([strnlen])
 REQUIRE_FUNC([unsetenv])
 REQUIRE_FUNC([uuid_unparse])
 REQUIRE_FUNC([vasprintf])
 
 AC_CHECK_FUNCS([strchrnul])
 
 AC_CHECK_FUNCS([fopen64])
 AM_CONDITIONAL([WRAPPABLE_FOPEN64], [test x"$ac_cv_func_fopen64" = x"yes"])
 
 AC_MSG_CHECKING([whether strerror always returns non-NULL])
 AC_RUN_IFELSE([AC_LANG_PROGRAM([[
     #include <stdio.h>
     #include <string.h>
                                ]], [[
     return strerror(-1) == NULL;
                                ]])],
               [AC_MSG_RESULT([yes])],
               [AC_MSG_ERROR([strerror() is not C99-compliant])],
               [AC_MSG_ERROR([strerror() is not C99-compliant])])
 
 AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[
     const char *s = "some-command-line-arg";
     char *name = NULL;
     int n = sscanf(s, "%ms", &name);
     return n != 1;
                                ]])],
               [have_sscanf_m="yes"],
               [have_sscanf_m="no"],
               [have_sscanf_m="no"])
 AS_IF([test x"$have_sscanf_m" = x"yes"],
       [AC_DEFINE([HAVE_SSCANF_M], [1],
                  [Define to 1 if sscanf %m modifier is available])])
 
 dnl ========================================================================
 dnl   bzip2
 dnl ========================================================================
 REQUIRE_HEADER([bzlib.h])
 REQUIRE_LIB([bz2], [BZ2_bzBuffToBuffCompress])
 
 dnl ========================================================================
 dnl sighandler_t is missing from Illumos, Solaris11 systems
 dnl ========================================================================
 
 AC_MSG_CHECKING([for sighandler_t])
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <signal.h>]], [[sighandler_t *f;]])],
                   [
                       AC_MSG_RESULT([yes])
                       AC_DEFINE([HAVE_SIGHANDLER_T], [1],
                                 [Define to 1 if sighandler_t is available])
                   ],
                   [AC_MSG_RESULT([no])])
 
 dnl ========================================================================
 dnl   ncurses
 dnl ========================================================================
 dnl
 dnl A few OSes (e.g. Linux) deliver a default "ncurses" alongside "curses".
 dnl Many non-Linux deliver "curses"; sites may add "ncurses".
 dnl
 dnl However, the source-code recommendation for both is to #include "curses.h"
 dnl (i.e. "ncurses" still wants the include to be simple, no-'n', "curses.h").
 dnl
 dnl ncurses takes precedence.
 dnl
 AC_CHECK_HEADERS([curses.h curses/curses.h ncurses.h ncurses/ncurses.h])
 
 dnl Although n-library is preferred, only look for it if the n-header was found.
 CURSESLIBS=''
 PC_NAME_CURSES=""
 PC_LIBS_CURSES=""
 AS_IF([test x"$ac_cv_header_ncurses_h" = x"yes"], [
     AC_CHECK_LIB(ncurses, printw,
                  [AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)])
     CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses'
     PC_NAME_CURSES="ncurses"
 ])
 
 AS_IF([test x"$ac_cv_header_ncurses_ncurses_h" = x"yes"], [
     AC_CHECK_LIB(ncurses, printw,
                  [AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)])
     CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses'
     PC_NAME_CURSES="ncurses"
 ])
 
 dnl Only look for non-n-library if there was no n-library.
 AS_IF([test x"$CURSESLIBS" = x"" && test x"$ac_cv_header_curses_h" = x"yes"], [
     AC_CHECK_LIB(curses, printw,
                  [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)])
     PC_LIBS_CURSES="$CURSESLIBS"
 ])
 
 dnl Only look for non-n-library if there was no n-library.
 AS_IF([test x"$CURSESLIBS" = x"" && test x"$ac_cv_header_curses_curses_h" = x"yes"], [
     AC_CHECK_LIB(curses, printw,
                  [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)])
     PC_LIBS_CURSES="$CURSESLIBS"
 ])
 
 AS_IF([test x"$CURSESLIBS" != x""],
       [PCMK_FEATURES="$PCMK_FEATURES ncurses"])
 
 dnl Check for printw() prototype compatibility
 AS_IF([test x"$CURSESLIBS" != x"" && cc_supports_flag -Wcast-qual], [
     ac_save_LIBS=$LIBS
     LIBS="$CURSESLIBS"
 
     # avoid broken test because of hardened build environment in Fedora 23+
     # - https://fedoraproject.org/wiki/Changes/Harden_All_Packages
     # - https://bugzilla.redhat.com/1297985
     AS_IF([cc_supports_flag -fPIC],
 	  [cc_temp_flags "-Wcast-qual $WERROR -fPIC"],
 	  [cc_temp_flags "-Wcast-qual $WERROR"])
 
     AC_MSG_CHECKING([whether curses library is compatible])
     AC_LINK_IFELSE(
         [AC_LANG_PROGRAM([
 #if defined(HAVE_NCURSES_H)
 #  include <ncurses.h>
 #elif defined(HAVE_NCURSES_NCURSES_H)
 #  include <ncurses/ncurses.h>
 #elif defined(HAVE_CURSES_H)
 #  include <curses.h>
 #endif
                          ],
                          [printw((const char *)"Test");]
         )],
         [AC_MSG_RESULT([yes])],
         [
             AC_MSG_RESULT([no])
             AC_MSG_WARN(m4_normalize([Disabling curses because the printw()
                                       function of your (n)curses library is old.
                                       If you wish to enable curses, update to a
                                       newer version (ncurses 5.4 or later is
                                       recommended, available from
                                       https://invisible-island.net/ncurses/)
                                      ]))
             AC_DEFINE([HAVE_INCOMPATIBLE_PRINTW], [1],
                       [Define to 1 if curses library has incompatible printw()])
         ]
     )
 
     LIBS=$ac_save_LIBS
     cc_restore_flags
 ])
 
 AC_SUBST(CURSESLIBS)
 AC_SUBST(PC_NAME_CURSES)
 AC_SUBST(PC_LIBS_CURSES)
 
 dnl ========================================================================
 dnl    Profiling and GProf
 dnl ========================================================================
 
 CFLAGS_ORIG="$CFLAGS"
 AS_IF([test $with_coverage -ne $DISABLED],
       [
         with_profiling=$REQUIRED
         PCMK_FEATURES="$PCMK_FEATURES coverage"
         CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage"
         dnl During linking, make sure to specify -lgcov or -coverage
       ]
 )
 
 AS_IF([test $with_profiling -ne $DISABLED],
       [
           with_profiling=$REQUIRED
           PCMK_FEATURES="$PCMK_FEATURES profile"
 
           dnl Disable various compiler optimizations
           CFLAGS="$CFLAGS -fno-omit-frame-pointer -fno-inline -fno-builtin"
           dnl CFLAGS="$CFLAGS -fno-inline-functions"
           dnl CFLAGS="$CFLAGS -fno-default-inline"
           dnl CFLAGS="$CFLAGS -fno-inline-functions-called-once"
           dnl CFLAGS="$CFLAGS -fno-optimize-sibling-calls"
 
           dnl Turn off optimization so tools can get accurate line numbers
           CFLAGS=`echo $CFLAGS | sed \
                   -e 's/-O.\ //g' \
                   -e 's/-Wp,-D_FORTIFY_SOURCE=.\ //g' \
                   -e 's/-D_FORTIFY_SOURCE=.\ //g'`
           CFLAGS="$CFLAGS -O0 -g3 -gdwarf-2"
 
           AC_MSG_NOTICE([CFLAGS before adding profiling options: $CFLAGS_ORIG])
           AC_MSG_NOTICE([CFLAGS after: $CFLAGS])
       ]
 )
 AC_DEFINE_UNQUOTED([SUPPORT_PROFILING], [$with_profiling], [Support profiling])
 AM_CONDITIONAL([BUILD_PROFILING], [test "$with_profiling" = "$REQUIRED"])
 
 dnl ========================================================================
 dnl    Cluster infrastructure - LibQB
 dnl ========================================================================
 
 PKG_CHECK_MODULES(libqb, libqb >= 0.17)
 CPPFLAGS="$libqb_CFLAGS $CPPFLAGS"
 LIBS="$libqb_LIBS $LIBS"
 
 dnl libqb 2.0.5+ (2022-03)
 AC_CHECK_FUNCS([qb_ipcc_connect_async])
 
 dnl libqb 2.0.2+ (2020-10)
 AC_CHECK_FUNCS([qb_ipcc_auth_get])
 
 dnl libqb 2.0.0+ (2020-05)
 CHECK_ENUM_VALUE([qb/qblog.h],[qb_log_conf],[QB_LOG_CONF_MAX_LINE_LEN])
 CHECK_ENUM_VALUE([qb/qblog.h],[qb_log_conf],[QB_LOG_CONF_ELLIPSIS])
 
 dnl Support Linux-HA fence agents if available
 AS_IF([test x"$cross_compiling" != x"yes"],
       [CPPFLAGS="$CPPFLAGS -I${prefix}/include/heartbeat"])
 AC_CHECK_HEADERS([stonith/stonith.h],
                  [
                      AC_CHECK_LIB([pils], [PILLoadPlugin])
                      AC_CHECK_LIB([plumb], [G_main_add_IPC_Channel])
                      PCMK_FEATURES="$PCMK_FEATURES lha"
                  ])
 AM_CONDITIONAL([BUILD_LHA_SUPPORT], [test x"$ac_cv_header_stonith_stonith_h" = x"yes"])
 
 
 dnl ===============================================
 dnl Detect DBus, systemd, and Upstart support
 dnl ===============================================
 
 HAVE_dbus=1
 PKG_CHECK_MODULES([DBUS], [dbus-1],
                   [CPPFLAGS="${CPPFLAGS} ${DBUS_CFLAGS}"],
                   [HAVE_dbus=0])
 AC_DEFINE_UNQUOTED(HAVE_DBUS, $HAVE_dbus, Support dbus)
 AM_CONDITIONAL(BUILD_DBUS, test $HAVE_dbus = 1)
 dnl libdbus 1.5.12+ (2012-03) / 1.6.0+ (2012-06)
 AC_CHECK_TYPES([DBusBasicValue],,,[[#include <dbus/dbus.h>]])
 AS_IF([test $HAVE_dbus = 0],
       [PC_NAME_DBUS=""],
       [PC_NAME_DBUS="dbus-1"])
 AC_SUBST(PC_NAME_DBUS)
 
 check_systemdsystemunitdir() {
     AC_MSG_CHECKING([which system unit file directory to use])
     PKG_CHECK_VAR([systemdsystemunitdir], [systemd], [systemdsystemunitdir])
     AC_MSG_RESULT([${systemdsystemunitdir}])
     test x"$systemdsystemunitdir" != x""
     return $?
 }
 
 AS_CASE([$enable_systemd],
         [$REQUIRED], [
             AS_IF([test $HAVE_dbus = 0],
                   [AC_MSG_FAILURE([Cannot support systemd resources without DBus])])
             AS_IF([test "$ac_cv_have_decl_CLOCK_MONOTONIC" = "no"],
                   [AC_MSG_FAILURE([Cannot support systemd resources without monotonic clock])])
             AS_IF([check_systemdsystemunitdir], [],
                   [AC_MSG_FAILURE([Cannot support systemd resources without systemdsystemunitdir])])
         ],
         [$OPTIONAL], [
             AS_IF([test $HAVE_dbus = 0 \
                    || test x"$ac_cv_have_decl_CLOCK_MONOTONIC" = x"no"],
                   [enable_systemd=$DISABLED],
                   [
                       AC_MSG_CHECKING([for systemd version (using dbus-send)])
                       ret=$({ dbus-send --system --print-reply \
                                   --dest=org.freedesktop.systemd1 \
                                   /org/freedesktop/systemd1 \
                                   org.freedesktop.DBus.Properties.Get \
                                   string:org.freedesktop.systemd1.Manager \
                                   string:Version 2>/dev/null \
                               || echo "version unavailable"; } | tail -n1)
                       # sanitize output a bit (interested just in value, not type),
                       # ret is intentionally unenquoted so as to normalize whitespace
                       ret=$(echo ${ret} | cut -d' ' -f2-)
                       AC_MSG_RESULT([${ret}])
                       AS_IF([test x"$ret" != x"unavailable" \
                              || systemctl --version 2>/dev/null | grep -q systemd],
                             [
                                 AS_IF([check_systemdsystemunitdir],
                                       [enable_systemd=$REQUIRED],
                                       [enable_systemd=$DISABLED])
                             ],
                             [enable_systemd=$DISABLED]
                       )
                   ])
         ],
 )
 AC_MSG_CHECKING([whether to enable support for managing resources via systemd])
 AS_IF([test $enable_systemd -eq $DISABLED], [AC_MSG_RESULT([no])],
       [
           AC_MSG_RESULT([yes])
           PCMK_FEATURES="$PCMK_FEATURES systemd"
       ]
 )
 AC_SUBST([systemdsystemunitdir])
 AC_DEFINE_UNQUOTED([SUPPORT_SYSTEMD], [$enable_systemd],
                    [Support systemd resources])
 AM_CONDITIONAL([BUILD_SYSTEMD], [test $enable_systemd = $REQUIRED])
 AC_SUBST(SUPPORT_SYSTEMD)
 
 AS_CASE([$enable_upstart],
         [$REQUIRED], [
             AS_IF([test $HAVE_dbus = 0],
                   [AC_MSG_FAILURE([Cannot support Upstart resources without DBus])])
         ],
         [$OPTIONAL], [
             AS_IF([test $HAVE_dbus = 0], [enable_upstart=$DISABLED],
                   [
                       AC_MSG_CHECKING([for Upstart version (using dbus-send)])
                       ret=$({ dbus-send --system --print-reply \
                                   --dest=com.ubuntu.Upstart \
                                   /com/ubuntu/Upstart org.freedesktop.DBus.Properties.Get \
                                   string:com.ubuntu.Upstart0_6 string:version 2>/dev/null \
                               || echo "version unavailable"; } | tail -n1)
                       # sanitize output a bit (interested just in value, not type),
                       # ret is intentionally unenquoted so as to normalize whitespace
                       ret=$(echo ${ret} | cut -d' ' -f2-)
                       AC_MSG_RESULT([${ret}])
                       AS_IF([test x"$ret" != x"unavailable" \
                              || initctl --version 2>/dev/null | grep -q upstart],
                             [enable_upstart=$REQUIRED],
                             [enable_upstart=$DISABLED]
                       )
                   ])
         ],
 )
 AC_MSG_CHECKING([whether to enable support for managing resources via Upstart])
 AS_IF([test $enable_upstart -eq $DISABLED], [AC_MSG_RESULT([no])],
       [
           AC_MSG_RESULT([yes])
           PCMK_FEATURES="$PCMK_FEATURES upstart"
       ]
 )
 AC_DEFINE_UNQUOTED([SUPPORT_UPSTART], [$enable_upstart],
                    [Support Upstart resources])
 AM_CONDITIONAL([BUILD_UPSTART], [test $enable_upstart -eq $REQUIRED])
 AC_SUBST(SUPPORT_UPSTART)
 
 
 dnl ========================================================================
 dnl Detect Nagios support
 dnl ========================================================================
 
 AS_CASE([$with_nagios],
         [$REQUIRED], [
             AS_IF([test x"$ac_cv_have_decl_CLOCK_MONOTONIC" = x"no"],
                   [AC_MSG_FAILURE([Cannot support nagios resources without monotonic clock])])
         ],
         [$OPTIONAL], [
             AS_IF([test x"$ac_cv_have_decl_CLOCK_MONOTONIC" = x"no"],
                   [with_nagios=$DISABLED], [with_nagios=$REQUIRED])
         ]
 )
 AS_IF([test $with_nagios -eq $REQUIRED], [PCMK_FEATURES="$PCMK_FEATURES nagios"])
 AC_DEFINE_UNQUOTED([SUPPORT_NAGIOS], [$with_nagios], [Support nagios plugins])
 AM_CONDITIONAL([BUILD_NAGIOS], [test $with_nagios -eq $REQUIRED])
 
 AS_IF([test x"$NAGIOS_PLUGIN_DIR" = x""],
       [NAGIOS_PLUGIN_DIR="${libexecdir}/nagios/plugins"])
 
 AC_DEFINE_UNQUOTED(NAGIOS_PLUGIN_DIR, "$NAGIOS_PLUGIN_DIR", Directory for nagios plugins)
 AC_SUBST(NAGIOS_PLUGIN_DIR)
 
 AS_IF([test x"$NAGIOS_METADATA_DIR" = x""],
       [NAGIOS_METADATA_DIR="${datadir}/nagios/plugins-metadata"])
 
 AC_DEFINE_UNQUOTED(NAGIOS_METADATA_DIR, "$NAGIOS_METADATA_DIR", Directory for nagios plugins metadata)
 AC_SUBST(NAGIOS_METADATA_DIR)
 
 STACKS=""
 CLUSTERLIBS=""
 PC_NAME_CLUSTER=""
 
 dnl ========================================================================
 dnl Detect support for "service" alias
 dnl ========================================================================
 
 PCMK__ENABLE_SERVICE=$DISABLED
 AM_COND_IF([BUILD_LSB], [PCMK__ENABLE_SERVICE=$REQUIRED])
 AM_COND_IF([BUILD_SYSTEMD], [PCMK__ENABLE_SERVICE=$REQUIRED])
 AM_COND_IF([BUILD_UPSTART], [PCMK__ENABLE_SERVICE=$REQUIRED])
 AS_IF([test $PCMK__ENABLE_SERVICE -ne $DISABLED],
       [PCMK_FEATURES="$PCMK_FEATURES service"])
 AC_SUBST(PCMK__ENABLE_SERVICE)
 AC_DEFINE_UNQUOTED([PCMK__ENABLE_SERVICE], [$PCMK__ENABLE_SERVICE],
                    [Whether "service" is supported as an agent standard])
 
 dnl ========================================================================
 dnl    Cluster stack - Corosync
 dnl ========================================================================
 
 COROSYNC_LIBS=""
 
 AS_CASE([$with_corosync],
         [$REQUIRED], [
             # These will be fatal if unavailable
             PKG_CHECK_MODULES([cpg], [libcpg])
             PKG_CHECK_MODULES([cfg], [libcfg])
             PKG_CHECK_MODULES([cmap], [libcmap])
             PKG_CHECK_MODULES([quorum], [libquorum])
             PKG_CHECK_MODULES([libcorosync_common], [libcorosync_common])
         ]
         [$OPTIONAL], [
             PKG_CHECK_MODULES([cpg], [libcpg], [], [with_corosync=$DISABLED])
             PKG_CHECK_MODULES([cfg], [libcfg], [], [with_corosync=$DISABLED])
             PKG_CHECK_MODULES([cmap], [libcmap], [], [with_corosync=$DISABLED])
             PKG_CHECK_MODULES([quorum], [libquorum], [], [with_corosync=$DISABLED])
             PKG_CHECK_MODULES([libcorosync_common], [libcorosync_common], [], [with_corosync=$DISABLED])
             AS_IF([test $with_corosync -ne $DISABLED], [with_corosync=$REQUIRED])
         ]
 )
 AS_IF([test $with_corosync -ne $DISABLED],
       [
           AC_MSG_CHECKING([for Corosync 2 or later])
           AC_MSG_RESULT([yes])
           CFLAGS="$CFLAGS $libqb_CFLAGS $cpg_CFLAGS $cfg_CFLAGS $cmap_CFLAGS $quorum_CFLAGS $libcorosync_common_CFLAGS"
           CPPFLAGS="$CPPFLAGS `$PKG_CONFIG --cflags-only-I corosync`"
           COROSYNC_LIBS="$COROSYNC_LIBS $cpg_LIBS $cfg_LIBS $cmap_LIBS $quorum_LIBS $libcorosync_common_LIBS"
           CLUSTERLIBS="$CLUSTERLIBS $COROSYNC_LIBS"
           PC_NAME_CLUSTER="$PC_CLUSTER_NAME libcfg libcmap libcorosync_common libcpg libquorum"
           STACKS="$STACKS corosync-ge-2"
 
           dnl Shutdown tracking added (back) to corosync Jan 2021
           saved_LIBS="$LIBS"
           LIBS="$LIBS $COROSYNC_LIBS"
           AC_CHECK_FUNCS([corosync_cfg_trackstart])
           LIBS="$saved_LIBS"
       ]
 )
 AC_DEFINE_UNQUOTED([SUPPORT_COROSYNC], [$with_corosync],
                    [Support the Corosync messaging and membership layer])
 AM_CONDITIONAL([BUILD_CS_SUPPORT], [test $with_corosync -eq $REQUIRED])
 AC_SUBST([SUPPORT_COROSYNC])
 
 dnl
 dnl    Cluster stack - Sanity
 dnl
 
 AS_IF([test x"$STACKS" != x""], [AC_MSG_NOTICE([Supported stacks:${STACKS}])],
       [AC_MSG_FAILURE([At least one cluster stack must be supported])])
 
 PCMK_FEATURES="${PCMK_FEATURES}${STACKS}"
 
 AC_SUBST(CLUSTERLIBS)
 AC_SUBST(PC_NAME_CLUSTER)
 
 dnl ========================================================================
 dnl    CIB secrets
 dnl ========================================================================
 
 AS_IF([test $with_cibsecrets -ne $DISABLED],
       [
           with_cibsecrets=$REQUIRED
           PCMK_FEATURES="$PCMK_FEATURES cibsecrets"
           LRM_CIBSECRETS_DIR="${localstatedir}/lib/pacemaker/lrm/secrets"
           AC_DEFINE_UNQUOTED([LRM_CIBSECRETS_DIR], ["$LRM_CIBSECRETS_DIR"],
                              [Location for CIB secrets])
           AC_SUBST([LRM_CIBSECRETS_DIR])
       ]
 )
 AC_DEFINE_UNQUOTED([SUPPORT_CIBSECRETS], [$with_cibsecrets], [Support CIB secrets])
 AM_CONDITIONAL([BUILD_CIBSECRETS], [test $with_cibsecrets -eq $REQUIRED])
 
 dnl ========================================================================
 dnl    GnuTLS
 dnl ========================================================================
 
 dnl Require GnuTLS >=2.12.0 (2011-03) for Pacemaker Remote support
 PC_NAME_GNUTLS=""
 AS_CASE([$with_gnutls],
         [$REQUIRED], [
             REQUIRE_LIB([gnutls], [gnutls_sec_param_to_pk_bits])
             REQUIRE_HEADER([gnutls/gnutls.h])
         ],
         [$OPTIONAL], [
             AC_CHECK_LIB([gnutls], [gnutls_sec_param_to_pk_bits],
                          [], [with_gnutls=$DISABLED])
             AC_CHECK_HEADERS([gnutls/gnutls.h], [], [with_gnutls=$DISABLED])
         ]
 )
 AS_IF([test $with_gnutls -ne $DISABLED],
       [
           PC_NAME_GNUTLS="gnutls"
           PCMK_FEATURES="$PCMK_FEATURES remote"
       ]
 )
 AC_SUBST([PC_NAME_GNUTLS])
 AM_CONDITIONAL([BUILD_REMOTE], [test $with_gnutls -ne $DISABLED])
 
 # --- ASAN/UBSAN/TSAN (see man gcc) ---
 # when using SANitizers, we need to pass the -fsanitize..
 # to both CFLAGS and LDFLAGS. The CFLAGS/LDFLAGS must be
 # specified as first in the list or there will be runtime
 # issues (for example user has to LD_PRELOAD asan for it to work
 # properly).
 
 AS_IF([test -n "${SANITIZERS}"], [
   SANITIZERS=$(echo $SANITIZERS | sed -e 's/,/ /g')
   for SANITIZER in $SANITIZERS
   do
     AS_CASE([$SANITIZER],
             [asan|ASAN], [
                 SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=address"
                 SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=address -lasan"
                 PCMK_FEATURES="$PCMK_FEATURES asan"
                 REQUIRE_LIB([asan],[main])
             ],
             [ubsan|UBSAN], [
                 SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=undefined"
                 SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=undefined -lubsan"
                 PCMK_FEATURES="$PCMK_FEATURES ubsan"
                 REQUIRE_LIB([ubsan],[main])
             ],
             [tsan|TSAN], [
                 SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=thread"
                 SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=thread -ltsan"
                 PCMK_FEATURES="$PCMK_FEATURES tsan"
                 REQUIRE_LIB([tsan],[main])
             ])
   done
 ])
 
 
 dnl ========================================================================
 dnl Compiler flags
 dnl ========================================================================
 
 dnl Make sure that CFLAGS is not exported. If the user did
 dnl not have CFLAGS in their environment then this should have
 dnl no effect. However if CFLAGS was exported from the user's
 dnl environment, then the new CFLAGS will also be exported
 dnl to sub processes.
 AS_IF([export | fgrep " CFLAGS=" > /dev/null],
       [
           SAVED_CFLAGS="$CFLAGS"
           unset CFLAGS
           CFLAGS="$SAVED_CFLAGS"
           unset SAVED_CFLAGS
       ])
 
 CC_EXTRAS=""
 
 AS_IF([test x"$GCC" != x"yes"], [CFLAGS="$CFLAGS -g"], [
     CFLAGS="$CFLAGS -ggdb"
 
 dnl When we don't have diagnostic push / pull, we can't explicitly disable
 dnl checking for nonliteral formats in the places where they occur on purpose
 dnl thus we disable nonliteral format checking globally as we are aborting
 dnl on warnings. 
 dnl what makes the things really ugly is that nonliteral format checking is 
 dnl obviously available as an extra switch in very modern gcc but for older
 dnl gcc this is part of -Wformat=2 
 dnl so if we have push/pull we can enable -Wformat=2 -Wformat-nonliteral
 dnl if we don't have push/pull but -Wformat-nonliteral we can enable -Wformat=2
 dnl otherwise none of both
 
     gcc_diagnostic_push_pull=no
     cc_temp_flags "$CFLAGS $WERROR"
     AC_MSG_CHECKING([for gcc diagnostic push / pull])
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
 #pragma GCC diagnostic push
 #pragma GCC diagnostic pop
                       ]])],
                       [
                           AC_MSG_RESULT([yes])
                           gcc_diagnostic_push_pull=yes
                       ], AC_MSG_RESULT([no]))
     cc_restore_flags
 
     AS_IF([cc_supports_flag "-Wformat-nonliteral"],
           [gcc_format_nonliteral=yes],
           [gcc_format_nonliteral=no])
         
     # We had to eliminate -Wnested-externs because of libtool changes
     # Make sure to order options so that the former stand for prerequisites
     # of the latter (e.g., -Wformat-nonliteral requires -Wformat).
     EXTRA_FLAGS="-fgnu89-inline"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wall"
     EXTRA_FLAGS="$EXTRA_FLAGS -Waggregate-return"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wbad-function-cast"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wcast-align"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wdeclaration-after-statement"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wendif-labels"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wfloat-equal"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wformat-security"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wimplicit-fallthrough"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wmissing-prototypes"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wmissing-declarations"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wnested-externs"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wno-long-long"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wno-strict-aliasing"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wpointer-arith"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wstrict-prototypes"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wwrite-strings"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wunused-but-set-variable"
     EXTRA_FLAGS="$EXTRA_FLAGS -Wunsigned-char"
 
     AS_IF([test x"$gcc_diagnostic_push_pull" = x"yes"],
           [
               AC_DEFINE([HAVE_FORMAT_NONLITERAL], [],
                         [gcc can complain about nonliterals in format])
               EXTRA_FLAGS="$EXTRA_FLAGS -Wformat=2 -Wformat-nonliteral"
           ],
           [test x"$gcc_format_nonliteral" = x"yes"],
           [EXTRA_FLAGS="$EXTRA_FLAGS -Wformat=2"])
 
 # Additional warnings it might be nice to enable one day
 #                -Wshadow
 #                -Wunreachable-code
     for j in $EXTRA_FLAGS
     do
         AS_IF([cc_supports_flag $CC_EXTRAS $j], [CC_EXTRAS="$CC_EXTRAS $j"])
     done
 
     AC_MSG_NOTICE([Using additional gcc flags: ${CC_EXTRAS}])
 ])
 
 dnl
 dnl Hardening flags
 dnl
 dnl The prime control of whether to apply (targeted) hardening build flags and
 dnl which ones is --{enable,disable}-hardening option passed to ./configure:
 dnl
 dnl --enable-hardening=try (default):
 dnl     depending on whether any of CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE,
 dnl     CFLAGS_HARDENED_LIB or LDFLAGS_HARDENED_LIB environment variables
 dnl     (see below) is set and non-null, all these custom flags (even if not
 dnl     set) are used as are, otherwise the best effort is made to offer
 dnl     reasonably strong hardening in several categories (RELRO, PIE,
 dnl     "bind now", stack protector) according to what the selected toolchain
 dnl     can offer
 dnl
 dnl --enable-hardening:
 dnl     same effect as --enable-hardening=try when the environment variables
 dnl     in question are suppressed
 dnl
 dnl --disable-hardening:
 dnl     do not apply any targeted hardening measures at all
 dnl
 dnl The user-injected environment variables that regulate the hardening in
 dnl default case are as follows:
 dnl
 dnl * CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE
 dnl    compiler and linker flags (respectively) for daemon programs
 dnl    (pacemakerd, pacemaker-attrd, pacemaker-controld, pacemaker-execd,
 dnl    pacemaker-based, pacemaker-fenced, pacemaker-remoted,
 dnl    pacemaker-schedulerd)
 dnl
 dnl * CFLAGS_HARDENED_LIB, LDFLAGS_HARDENED_LIB
 dnl    compiler and linker flags (respectively) for libraries linked
 dnl    with the daemon programs
 dnl
 dnl Note that these are purposedly targeted variables (addressing particular
 dnl targets all over the scattered Makefiles) and have no effect outside of
 dnl the predestined scope (e.g., CLI utilities).  For a global reach,
 dnl use CFLAGS, LDFLAGS, etc. as usual.
 dnl
 dnl For guidance on the suitable flags consult, for instance:
 dnl https://fedoraproject.org/wiki/Changes/Harden_All_Packages#Detailed_Harden_Flags_Description
 dnl https://owasp.org/index.php/C-Based_Toolchain_Hardening#GCC.2FBinutils
 dnl
 
 AS_IF([test $enable_hardening -eq $OPTIONAL],
       [
           AS_IF([test "$(env | grep -Ec '^(C|LD)FLAGS_HARDENED_(EXE|LIB)=.')" = 0],
                 [enable_hardening=$REQUIRED],
                 [AC_MSG_NOTICE([Hardening: using custom flags from environment])]
           )
       ],
       [
           unset CFLAGS_HARDENED_EXE
           unset CFLAGS_HARDENED_LIB
           unset LDFLAGS_HARDENED_EXE
           unset LDFLAGS_HARDENED_LIB
       ]
 )
 AS_CASE([$enable_hardening],
         [$DISABLED], [AC_MSG_NOTICE([Hardening: explicitly disabled])],
         [$REQUIRED], [
             CFLAGS_HARDENED_EXE=
             CFLAGS_HARDENED_LIB=
             LDFLAGS_HARDENED_EXE=
             LDFLAGS_HARDENED_LIB=
             relro=0
             pie=0
             bindnow=0
             stackprot="none"
             # daemons incl. libs: partial RELRO
             flag="-Wl,-z,relro"
             CC_CHECK_LDFLAGS(["${flag}"],
                              [
                                  LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"
                                  LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"
                                  relro=1
                              ])
             # daemons: PIE for both CFLAGS and LDFLAGS
             AS_IF([cc_supports_flag -fPIE],
                   [
                       flag="-pie"
                       CC_CHECK_LDFLAGS(["${flag}"],
                                        [
                                            CFLAGS_HARDENED_EXE="${CFLAGS_HARDENED_EXE} -fPIE"
                                            LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"
                                            pie=1
                                        ])
                   ]
             )
             # daemons incl. libs: full RELRO if sensible + as-needed linking
             #                     so as to possibly mitigate startup performance
             #                     hit caused by excessive linking with unneeded
             #                     libraries
             AS_IF([test "${relro}" = 1 && test "${pie}" = 1],
                   [
                       flag="-Wl,-z,now"
                       CC_CHECK_LDFLAGS(["${flag}"],
                                        [
                                            LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"
                                            LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"
                                            bindnow=1
                                        ])
                   ]
             )
             AS_IF([test "${bindnow}" = 1],
                   [
                       flag="-Wl,--as-needed"
                       CC_CHECK_LDFLAGS(["${flag}"],
                                        [
                                            LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"
                                            LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"
                                        ])
                   ])
             # universal: prefer strong > all > default stack protector if possible
             flag=
             AS_IF([cc_supports_flag -fstack-protector-strong],
                   [
                       flag="-fstack-protector-strong"
                       stackprot="strong"
                   ],
                   [cc_supports_flag -fstack-protector-all],
                   [
                       flag="-fstack-protector-all"
                       stackprot="all"
                   ],
                   [cc_supports_flag -fstack-protector],
                   [
                       flag="-fstack-protector"
                       stackprot="default"
                   ]
             )
             AS_IF([test -n "${flag}"], [CC_EXTRAS="${CC_EXTRAS} ${flag}"])
             # universal: enable stack clash protection if possible
             AS_IF([cc_supports_flag -fstack-clash-protection],
                   [
                       CC_EXTRAS="${CC_EXTRAS} -fstack-clash-protection"
                       AS_IF([test "${stackprot}" = "none"],
                             [stackprot="clash-only"],
                             [stackprot="${stackprot}+clash"]
                       )
                   ]
             )
             # Log a summary
             AS_IF([test "${relro}" = 1 || test "${pie}" = 1 || test x"${stackprot}" != x"none"],
                   [AC_MSG_NOTICE(m4_normalize([Hardening:
                         relro=${relro}
                         pie=${pie}
                         bindnow=${bindnow}
                         stackprot=${stackprot}]))
                   ],
                   [AC_MSG_WARN([Hardening: no suitable features in the toolchain detected])]
             )
         ],
 )
 
 CFLAGS="$SANITIZERS_CFLAGS $CFLAGS $CC_EXTRAS"
 LDFLAGS="$SANITIZERS_LDFLAGS $LDFLAGS"
 CFLAGS_HARDENED_EXE="$SANITIZERS_CFLAGS $CFLAGS_HARDENED_EXE"
 LDFLAGS_HARDENED_EXE="$SANITIZERS_LDFLAGS $LDFLAGS_HARDENED_EXE"
 
 NON_FATAL_CFLAGS="$CFLAGS"
 AC_SUBST(NON_FATAL_CFLAGS)
 
 dnl
 dnl We reset CFLAGS to include our warnings *after* all function
 dnl checking goes on, so that our warning flags don't keep the
 dnl AC_*FUNCS() calls above from working.  In particular, -Werror will
 dnl *always* cause us troubles if we set it before here.
 dnl
 dnl
 AS_IF([test $enable_fatal_warnings -ne $DISABLED], [
     AC_MSG_NOTICE([Enabling fatal compiler warnings])
     CFLAGS="$CFLAGS $WERROR"
 ])
 AC_SUBST(CFLAGS)
 
 dnl This is useful for use in Makefiles that need to remove one specific flag
 CFLAGS_COPY="$CFLAGS"
 AC_SUBST(CFLAGS_COPY)
 
 AC_SUBST(LIBADD_DL)        dnl extra flags for dynamic linking libraries
 
 AC_SUBST(LOCALE)
 
 dnl Options for cleaning up the compiler output
 AS_IF([test $enable_quiet -ne $DISABLED],
       [
           AC_MSG_NOTICE([Suppressing make details])
           QUIET_LIBTOOL_OPTS="--silent"
           QUIET_MAKE_OPTS="-s"  # POSIX compliant
       ],
       [
           QUIET_LIBTOOL_OPTS=""
           QUIET_MAKE_OPTS=""
       ]
 )
 
 dnl Put the above variables to use
 LIBTOOL="${LIBTOOL} --tag=CC \$(QUIET_LIBTOOL_OPTS)"
 MAKEFLAGS="${MAKEFLAGS} ${QUIET_MAKE_OPTS}"
 
 # Make features list available (sorted alphabetically, without leading space)
 PCMK_FEATURES=`echo "$PCMK_FEATURES" | sed -e 's/^ //' -e 's/ /\n/g' | sort | xargs`
 AC_DEFINE_UNQUOTED(CRM_FEATURES, "$PCMK_FEATURES", Set of enabled features)
 AC_SUBST(PCMK_FEATURES)
 
 AC_SUBST(CC)
 AC_SUBST(MAKEFLAGS)
 AC_SUBST(LIBTOOL)
 AC_SUBST(QUIET_LIBTOOL_OPTS)
 
 dnl Files we output that need to be executable
 CONFIG_FILES_EXEC([agents/ocf/ClusterMon],
                   [agents/ocf/Dummy],
                   [agents/ocf/HealthCPU],
                   [agents/ocf/HealthIOWait],
                   [agents/ocf/HealthSMART],
                   [agents/ocf/Stateful],
                   [agents/ocf/SysInfo],
                   [agents/ocf/attribute],
                   [agents/ocf/controld],
                   [agents/ocf/ifspeed],
                   [agents/ocf/o2cb],
                   [agents/ocf/ping],
                   [agents/ocf/remote],
                   [agents/stonith/fence_legacy],
                   [agents/stonith/fence_watchdog],
                   [cts/cluster_test],
                   [cts/cts],
                   [cts/cts-attrd],
                   [cts/cts-cli],
                   [cts/cts-exec],
                   [cts/cts-fencing],
                   [cts/cts-lab],
                   [cts/cts-log-watcher],
                   [cts/cts-regression],
                   [cts/cts-scheduler],
                   [cts/benchmark/clubench],
                   [cts/support/LSBDummy],
                   [cts/support/cts-support],
                   [cts/support/fence_dummy],
                   [cts/support/pacemaker-cts-dummyd],
                   [doc/abi-check],
                   [maint/bumplibs],
                   [tools/cluster-clean],
                   [tools/cluster-helper],
                   [tools/crm_failcount],
                   [tools/crm_master],
                   [tools/crm_report],
                   [tools/crm_standby],
                   [tools/cibsecret],
                   [tools/pcmk_simtimes],
                   [xml/rng-helper])
 
 dnl Other files we output
 AC_CONFIG_FILES(Makefile                                            \
                 agents/Makefile                                     \
                 agents/alerts/Makefile                              \
                 agents/ocf/Makefile                                 \
                 agents/stonith/Makefile                             \
                 cts/Makefile                                        \
                 cts/benchmark/Makefile                              \
                 cts/scheduler/Makefile                              \
                 cts/scheduler/dot/Makefile                          \
                 cts/scheduler/exp/Makefile                          \
                 cts/scheduler/scores/Makefile                       \
                 cts/scheduler/stderr/Makefile                       \
                 cts/scheduler/summary/Makefile                      \
                 cts/scheduler/xml/Makefile                          \
                 cts/support/Makefile                                \
                 cts/support/pacemaker-cts-dummyd@.service           \
                 daemons/Makefile                                    \
                 daemons/attrd/Makefile                              \
                 daemons/based/Makefile                              \
                 daemons/controld/Makefile                           \
                 daemons/execd/Makefile                              \
                 daemons/execd/pacemaker_remote                      \
                 daemons/execd/pacemaker_remote.service              \
                 daemons/fenced/Makefile                             \
                 daemons/pacemakerd/Makefile                         \
                 daemons/pacemakerd/pacemaker.combined.upstart       \
                 daemons/pacemakerd/pacemaker.service                \
                 daemons/pacemakerd/pacemaker.upstart                \
                 daemons/schedulerd/Makefile                         \
                 devel/Makefile                                      \
                 doc/Doxyfile                                        \
                 doc/Makefile                                        \
                 doc/sphinx/Makefile                                 \
                 etc/Makefile                                        \
                 etc/init.d/pacemaker                                \
                 etc/logrotate.d/pacemaker                           \
                 etc/sysconfig/pacemaker                             \
                 include/Makefile                                    \
                 include/crm/Makefile                                \
                 include/crm/cib/Makefile                            \
                 include/crm/common/Makefile                         \
                 include/crm/cluster/Makefile                        \
                 include/crm/fencing/Makefile                        \
                 include/crm/pengine/Makefile                        \
                 include/pcmki/Makefile                              \
                 lib/Makefile                                        \
                 lib/cib/Makefile                                    \
                 lib/cluster/Makefile                                \
                 lib/cluster/tests/Makefile                          \
                 lib/cluster/tests/cluster/Makefile                  \
                 lib/cluster/tests/cpg/Makefile                      \
                 lib/common/Makefile                                 \
                 lib/common/tests/Makefile                           \
                 lib/common/tests/acl/Makefile                       \
                 lib/common/tests/actions/Makefile                   \
                 lib/common/tests/agents/Makefile                    \
                 lib/common/tests/cmdline/Makefile                   \
                 lib/common/tests/flags/Makefile                     \
                 lib/common/tests/health/Makefile                    \
                 lib/common/tests/io/Makefile                        \
                 lib/common/tests/iso8601/Makefile                   \
                 lib/common/tests/lists/Makefile                     \
                 lib/common/tests/nodes/Makefile                     \
                 lib/common/tests/nvpair/Makefile                    \
                 lib/common/tests/options/Makefile                   \
                 lib/common/tests/output/Makefile                    \
                 lib/common/tests/probes/Makefile                    \
                 lib/common/tests/procfs/Makefile                    \
                 lib/common/tests/resources/Makefile                 \
                 lib/common/tests/results/Makefile                   \
                 lib/common/tests/rules/Makefile                     \
                 lib/common/tests/scheduler/Makefile                 \
                 lib/common/tests/schemas/Makefile                   \
                 lib/common/tests/scores/Makefile                    \
                 lib/common/tests/strings/Makefile                   \
                 lib/common/tests/utils/Makefile                     \
                 lib/common/tests/xml/Makefile                       \
                 lib/common/tests/xpath/Makefile                     \
                 lib/fencing/Makefile                                \
                 lib/gnu/Makefile                                    \
                 lib/libpacemaker.pc                                 \
                 lib/lrmd/Makefile                                   \
                 lib/pacemaker/Makefile                              \
                 lib/pacemaker/tests/Makefile                        \
                 lib/pacemaker/tests/pcmk_resource/Makefile          \
                 lib/pacemaker/tests/pcmk_ticket/Makefile            \
                 lib/pacemaker.pc                                    \
                 lib/pacemaker-cib.pc                                \
                 lib/pacemaker-cluster.pc                            \
                 lib/pacemaker-fencing.pc                            \
                 lib/pacemaker-lrmd.pc                               \
                 lib/pacemaker-service.pc                            \
                 lib/pacemaker-pe_rules.pc                           \
                 lib/pacemaker-pe_status.pc                          \
                 lib/pengine/Makefile                                \
                 lib/pengine/tests/Makefile                          \
                 lib/pengine/tests/native/Makefile                   \
                 lib/pengine/tests/status/Makefile                   \
                 lib/pengine/tests/unpack/Makefile                   \
                 lib/pengine/tests/utils/Makefile                    \
                 lib/services/Makefile                               \
                 maint/Makefile                                      \
                 po/Makefile.in                                      \
                 python/Makefile                                     \
                 python/setup.py                                     \
                 python/pacemaker/Makefile                           \
                 python/pacemaker/_cts/Makefile                      \
                 python/pacemaker/_cts/tests/Makefile                \
                 python/pacemaker/buildoptions.py                    \
                 python/tests/Makefile                               \
                 rpm/Makefile                                        \
                 tests/Makefile                                      \
                 tools/Makefile                                      \
                 tools/crm_mon.service                               \
                 tools/crm_mon.upstart                               \
                 tools/report.collector                              \
                 tools/report.common                                 \
                 xml/Makefile                                        \
                 xml/pacemaker-schemas.pc                            \
 )
 
 dnl Now process the entire list of files added by previous
 dnl  calls to AC_CONFIG_FILES()
 AC_OUTPUT()
 
 dnl *****************
 dnl Configure summary
 dnl *****************
 
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([$PACKAGE configuration:])
 AC_MSG_NOTICE([  Version                  = ${VERSION} (Build: $BUILD_VERSION)])
 AC_MSG_NOTICE([  Features                 = ${PCMK_FEATURES}])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([  Prefix                   = ${prefix}])
 AC_MSG_NOTICE([  Executables              = ${sbindir}])
 AC_MSG_NOTICE([  Man pages                = ${mandir}])
 AC_MSG_NOTICE([  Libraries                = ${libdir}])
 AC_MSG_NOTICE([  Header files             = ${includedir}])
 AC_MSG_NOTICE([  Arch-independent files   = ${datadir}])
 AC_MSG_NOTICE([  State information        = ${localstatedir}])
 AC_MSG_NOTICE([  System configuration     = ${sysconfdir}])
 AC_MSG_NOTICE([  OCF agents               = ${OCF_ROOT_DIR}])
 AM_COND_IF([BUILD_LSB],
            [AC_MSG_NOTICE([  LSB agents               = ${INITDIR}])])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([  HA group name            = ${CRM_DAEMON_GROUP}])
 AC_MSG_NOTICE([  HA user name             = ${CRM_DAEMON_USER}])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([  CFLAGS                   = ${CFLAGS}])
 AC_MSG_NOTICE([  CFLAGS_HARDENED_EXE      = ${CFLAGS_HARDENED_EXE}])
 AC_MSG_NOTICE([  CFLAGS_HARDENED_LIB      = ${CFLAGS_HARDENED_LIB}])
 AC_MSG_NOTICE([  LDFLAGS_HARDENED_EXE     = ${LDFLAGS_HARDENED_EXE}])
 AC_MSG_NOTICE([  LDFLAGS_HARDENED_LIB     = ${LDFLAGS_HARDENED_LIB}])
 AC_MSG_NOTICE([  Libraries                = ${LIBS}])
 AC_MSG_NOTICE([  Stack Libraries          = ${CLUSTERLIBS}])
 AC_MSG_NOTICE([  Unix socket auth method  = ${us_auth}])
diff --git a/lib/common/options.c b/lib/common/options.c
index 1b64c4d8d6..a5bbd9596d 100644
--- a/lib/common/options.c
+++ b/lib/common/options.c
@@ -1,1567 +1,1572 @@
 /*
  * Copyright 2004-2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include <crm/crm.h>
 #include <crm/common/xml.h>
 
 void
 pcmk__cli_help(char cmd)
 {
     if (cmd == 'v' || cmd == '$') {
         printf("Pacemaker %s\n", PACEMAKER_VERSION);
         printf("Written by Andrew Beekhof and "
                "the Pacemaker project contributors\n");
 
     } else if (cmd == '!') {
         printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
     }
 
     crm_exit(CRM_EX_OK);
     while(1); // above does not return
 }
 
 
 /*
  * Option metadata
  */
 
 static const pcmk__cluster_option_t cluster_options[] = {
     /* name, old name, type, allowed values,
      * default value, validator,
      * flags,
      * short description,
      * long description
      */
     {
         PCMK_OPT_DC_VERSION, NULL, PCMK_VALUE_VERSION, NULL,
         NULL, NULL,
         pcmk__opt_controld|pcmk__opt_generated,
         N_("Pacemaker version on cluster node elected Designated Controller "
             "(DC)"),
         N_("Includes a hash which identifies the exact revision the code was "
             "built from. Used for diagnostic purposes."),
     },
     {
         PCMK_OPT_CLUSTER_INFRASTRUCTURE, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_controld|pcmk__opt_generated,
         N_("The messaging layer on which Pacemaker is currently running"),
         N_("Used for informational and diagnostic purposes."),
     },
     {
         PCMK_OPT_CLUSTER_NAME, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_controld,
         N_("An arbitrary name for the cluster"),
         N_("This optional value is mostly for users' convenience as desired "
             "in administration, but may also be used in Pacemaker "
             "configuration rules via the #cluster-name node attribute, and "
             "by higher-level tools and resource agents."),
     },
     {
         PCMK_OPT_DC_DEADTIME, NULL, PCMK_VALUE_DURATION, NULL,
         "20s", pcmk__valid_interval_spec,
         pcmk__opt_controld,
         N_("How long to wait for a response from other nodes during start-up"),
         N_("The optimal value will depend on the speed and load of your "
             "network and the type of switches used."),
     },
     {
         PCMK_OPT_CLUSTER_RECHECK_INTERVAL, NULL, PCMK_VALUE_DURATION, NULL,
         "15min", pcmk__valid_interval_spec,
         pcmk__opt_controld,
         N_("Polling interval to recheck cluster state and evaluate rules "
             "with date specifications"),
         N_("Pacemaker is primarily event-driven, and looks ahead to know when "
             "to recheck cluster state for failure-timeout settings and most "
             "time-based rules. However, it will also recheck the cluster after "
             "this amount of inactivity, to evaluate rules with date "
             "specifications and serve as a fail-safe for certain types of "
             "scheduler bugs. A value of 0 disables polling. A positive value "
             "sets an interval in seconds, unless other units are specified "
             "(for example, \"5min\")."),
     },
     {
         PCMK_OPT_FENCE_REACTION, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_STOP ", " PCMK_VALUE_PANIC,
         PCMK_VALUE_STOP, NULL,
         pcmk__opt_controld,
         N_("How a cluster node should react if notified of its own fencing"),
         N_("A cluster node may receive notification of a \"succeeded\" "
             "fencing that targeted it if fencing is misconfigured, or if "
             "fabric fencing is in use that doesn't cut cluster communication. "
             "Use \"stop\" to attempt to immediately stop Pacemaker and stay "
             "stopped, or \"panic\" to attempt to immediately reboot the local "
             "node, falling back to stop on failure."),
     },
     {
         PCMK_OPT_ELECTION_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
         "2min", pcmk__valid_interval_spec,
         pcmk__opt_controld|pcmk__opt_advanced,
         N_("Declare an election failed if it is not decided within this much "
             "time. If you need to adjust this value, it probably indicates "
             "the presence of a bug."),
         NULL,
     },
     {
         PCMK_OPT_SHUTDOWN_ESCALATION, NULL, PCMK_VALUE_DURATION, NULL,
         "20min", pcmk__valid_interval_spec,
         pcmk__opt_controld|pcmk__opt_advanced,
         N_("Exit immediately if shutdown does not complete within this much "
             "time. If you need to adjust this value, it probably indicates "
             "the presence of a bug."),
         NULL,
     },
     {
         PCMK_OPT_JOIN_INTEGRATION_TIMEOUT, "crmd-integration-timeout",
             PCMK_VALUE_DURATION, NULL,
         "3min", pcmk__valid_interval_spec,
         pcmk__opt_controld|pcmk__opt_advanced,
         N_("If you need to adjust this value, it probably indicates "
             "the presence of a bug."),
         NULL,
     },
     {
         PCMK_OPT_JOIN_FINALIZATION_TIMEOUT, "crmd-finalization-timeout",
             PCMK_VALUE_DURATION, NULL,
         "30min", pcmk__valid_interval_spec,
         pcmk__opt_controld|pcmk__opt_advanced,
         N_("If you need to adjust this value, it probably indicates "
             "the presence of a bug."),
         NULL,
     },
     {
         PCMK_OPT_TRANSITION_DELAY, "crmd-transition-delay", PCMK_VALUE_DURATION,
             NULL,
         "0s", pcmk__valid_interval_spec,
         pcmk__opt_controld|pcmk__opt_advanced,
         N_("Enabling this option will slow down cluster recovery under all "
             "conditions"),
         N_("Delay cluster recovery for this much time to allow for additional "
             "events to occur. Useful if your configuration is sensitive to "
             "the order in which ping updates arrive."),
     },
     {
         PCMK_OPT_NO_QUORUM_POLICY, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_STOP ", " PCMK_VALUE_FREEZE ", " PCMK_VALUE_IGNORE
                 ", " PCMK_VALUE_DEMOTE ", " PCMK_VALUE_FENCE ", "
                 PCMK_VALUE_FENCE_LEGACY,
         PCMK_VALUE_STOP, pcmk__valid_no_quorum_policy,
         pcmk__opt_schedulerd,
         N_("What to do when the cluster does not have quorum"),
         NULL,
     },
     {
         PCMK_OPT_SHUTDOWN_LOCK, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether to lock resources to a cleanly shut down node"),
         N_("When true, resources active on a node when it is cleanly shut down "
             "are kept \"locked\" to that node (not allowed to run elsewhere) "
             "until they start again on that node after it rejoins (or for at "
             "most shutdown-lock-limit, if set). Stonith resources and "
             "Pacemaker Remote connections are never locked. Clone and bundle "
             "instances and the promoted role of promotable clones are "
             "currently never locked, though support could be added in a future "
             "release."),
     },
     {
         PCMK_OPT_SHUTDOWN_LOCK_LIMIT, NULL, PCMK_VALUE_DURATION, NULL,
         "0", pcmk__valid_interval_spec,
         pcmk__opt_schedulerd,
         N_("Do not lock resources to a cleanly shut down node longer than "
            "this"),
         N_("If shutdown-lock is true and this is set to a nonzero time "
             "duration, shutdown locks will expire after this much time has "
             "passed since the shutdown was initiated, even if the node has not "
             "rejoined."),
     },
     {
         PCMK_OPT_ENABLE_ACL, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_based,
         N_("Enable Access Control Lists (ACLs) for the CIB"),
         NULL,
     },
     {
         PCMK_OPT_SYMMETRIC_CLUSTER, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether resources can run on any node by default"),
         NULL,
     },
     {
         PCMK_OPT_MAINTENANCE_MODE, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether the cluster should refrain from monitoring, starting, and "
             "stopping resources"),
         NULL,
     },
     {
         PCMK_OPT_START_FAILURE_IS_FATAL, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether a start failure should prevent a resource from being "
             "recovered on the same node"),
         N_("When true, the cluster will immediately ban a resource from a node "
             "if it fails to start there. When false, the cluster will instead "
             "check the resource's fail count against its migration-threshold.")
     },
     {
         PCMK_OPT_ENABLE_STARTUP_PROBES, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether the cluster should check for active resources during "
             "start-up"),
         NULL,
     },
 
     // Fencing-related options
     {
         PCMK_OPT_STONITH_ENABLED, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd|pcmk__opt_advanced,
         N_("Whether nodes may be fenced as part of recovery"),
         N_("If false, unresponsive nodes are immediately assumed to be "
             "harmless, and resources that were active on them may be recovered "
             "elsewhere. This can result in a \"split-brain\" situation, "
             "potentially leading to data loss and/or service unavailability."),
     },
     {
         PCMK_OPT_STONITH_ACTION, NULL, PCMK_VALUE_SELECT,
             PCMK_ACTION_REBOOT ", " PCMK_ACTION_OFF ", " PCMK__ACTION_POWEROFF,
         PCMK_ACTION_REBOOT, pcmk__is_fencing_action,
         pcmk__opt_schedulerd,
         N_("Action to send to fence device when a node needs to be fenced "
             "(\"poweroff\" is a deprecated alias for \"off\")"),
         NULL,
     },
     {
         PCMK_OPT_STONITH_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
         "60s", pcmk__valid_interval_spec,
         pcmk__opt_schedulerd,
         N_("How long to wait for on, off, and reboot fence actions to complete "
             "by default"),
         NULL,
     },
     {
         PCMK_OPT_HAVE_WATCHDOG, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_schedulerd|pcmk__opt_generated,
         N_("Whether watchdog integration is enabled"),
         N_("This is set automatically by the cluster according to whether SBD "
             "is detected to be in use. User-configured values are ignored. "
             "The value `true` is meaningful if diskless SBD is used and "
             "`stonith-watchdog-timeout` is nonzero. In that case, if fencing "
             "is required, watchdog-based self-fencing will be performed via "
             "SBD without requiring a fencing resource explicitly configured."),
     },
     {
         /* @COMPAT Currently, unparsable values default to -1 (auto-calculate),
          * while missing values default to 0 (disable). All values are accepted
          * (unless the controller finds that the value conflicts with the
          * SBD_WATCHDOG_TIMEOUT).
          *
          * At a compatibility break: properly validate as a timeout, let
          * either negative values or a particular string like "auto" mean auto-
          * calculate, and use 0 as the single default for when the option either
          * is unset or fails to validate.
          */
         PCMK_OPT_STONITH_WATCHDOG_TIMEOUT, NULL, PCMK_VALUE_TIMEOUT, NULL,
         "0", NULL,
         pcmk__opt_controld,
         N_("How long before nodes can be assumed to be safely down when "
            "watchdog-based self-fencing via SBD is in use"),
         N_("If this is set to a positive value, lost nodes are assumed to "
            "achieve self-fencing using watchdog-based SBD within this much "
            "time. This does not require a fencing resource to be explicitly "
            "configured, though a fence_watchdog resource can be configured, to "
            "limit use to specific nodes. If this is set to 0 (the default), "
            "the cluster will never assume watchdog-based self-fencing. If this "
            "is set to a negative value, the cluster will use twice the local "
            "value of the `SBD_WATCHDOG_TIMEOUT` environment variable if that "
            "is positive, or otherwise treat this as 0. WARNING: When used, "
            "this timeout must be larger than `SBD_WATCHDOG_TIMEOUT` on all "
            "nodes that use watchdog-based SBD, and Pacemaker will refuse to "
            "start on any of those nodes where this is not true for the local "
            "value or SBD is not active. When this is set to a negative value, "
            "`SBD_WATCHDOG_TIMEOUT` must be set to the same value on all nodes "
            "that use SBD, otherwise data corruption or loss could occur."),
     },
     {
         PCMK_OPT_STONITH_MAX_ATTEMPTS, NULL, PCMK_VALUE_SCORE, NULL,
         "10", pcmk__valid_positive_int,
         pcmk__opt_controld,
         N_("How many times fencing can fail before it will no longer be "
             "immediately re-attempted on a target"),
         NULL,
     },
     {
         PCMK_OPT_CONCURRENT_FENCING, NULL, PCMK_VALUE_BOOLEAN, NULL,
-        PCMK__CONCURRENT_FENCING_DEFAULT, pcmk__valid_boolean,
+#if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
+        PCMK_VALUE_TRUE,
+#else
+        PCMK_VALUE_FALSE,
+#endif
+        pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Allow performing fencing operations in parallel"),
         NULL,
     },
     {
         PCMK_OPT_STARTUP_FENCING, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd|pcmk__opt_advanced,
         N_("Whether to fence unseen nodes at start-up"),
         N_("Setting this to false may lead to a \"split-brain\" situation, "
             "potentially leading to data loss and/or service unavailability."),
     },
     {
         PCMK_OPT_PRIORITY_FENCING_DELAY, NULL, PCMK_VALUE_DURATION, NULL,
         "0", pcmk__valid_interval_spec,
         pcmk__opt_schedulerd,
         N_("Apply fencing delay targeting the lost nodes with the highest "
             "total resource priority"),
         N_("Apply specified delay for the fencings that are targeting the lost "
             "nodes with the highest total resource priority in case we don't "
             "have the majority of the nodes in our cluster partition, so that "
             "the more significant nodes potentially win any fencing match, "
             "which is especially meaningful under split-brain of 2-node "
             "cluster. A promoted resource instance takes the base priority + 1 "
             "on calculation if the base priority is not 0. Any static/random "
             "delays that are introduced by `pcmk_delay_base/max` configured "
             "for the corresponding fencing resources will be added to this "
             "delay. This delay should be significantly greater than, safely "
             "twice, the maximum `pcmk_delay_base/max`. By default, priority "
             "fencing delay is disabled."),
     },
     {
         PCMK_OPT_NODE_PENDING_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
         "0", pcmk__valid_interval_spec,
         pcmk__opt_schedulerd,
         N_("How long to wait for a node that has joined the cluster to join "
            "the controller process group"),
         N_("Fence nodes that do not join the controller process group within "
            "this much time after joining the cluster, to allow the cluster "
            "to continue managing resources. A value of 0 means never fence "
            "pending nodes. Setting the value to 2h means fence nodes after "
            "2 hours."),
     },
     {
         PCMK_OPT_CLUSTER_DELAY, NULL, PCMK_VALUE_DURATION, NULL,
         "60s", pcmk__valid_interval_spec,
         pcmk__opt_schedulerd,
         N_("Maximum time for node-to-node communication"),
         N_("The node elected Designated Controller (DC) will consider an action "
             "failed if it does not get a response from the node executing the "
             "action within this time (after considering the action's own "
             "timeout). The \"correct\" value will depend on the speed and "
             "load of your network and cluster nodes.")
     },
 
     // Limits
     {
         PCMK_OPT_LOAD_THRESHOLD, NULL, PCMK_VALUE_PERCENTAGE, NULL,
         "80%", pcmk__valid_percentage,
         pcmk__opt_controld,
         N_("Maximum amount of system load that should be used by cluster "
             "nodes"),
         N_("The cluster will slow down its recovery process when the amount of "
             "system resources used (currently CPU) approaches this limit"),
     },
     {
         PCMK_OPT_NODE_ACTION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
         "0", pcmk__valid_int,
         pcmk__opt_controld,
         N_("Maximum number of jobs that can be scheduled per node (defaults to "
             "2x cores)"),
         NULL,
     },
     {
         PCMK_OPT_BATCH_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
         "0", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("Maximum number of jobs that the cluster may execute in parallel "
             "across all nodes"),
         N_("The \"correct\" value will depend on the speed and load of your "
             "network and cluster nodes. If set to 0, the cluster will "
             "impose a dynamically calculated limit when any node has a "
             "high load."),
     },
     {
         PCMK_OPT_MIGRATION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
         "-1", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The number of live migration actions that the cluster is allowed "
             "to execute in parallel on a node (-1 means no limit)"),
         NULL,
     },
     {
         /* @TODO This is actually ignored if not strictly positive. We should
          * overhaul value types in Pacemaker Explained. There are lots of
          * inaccurate ranges (assumptions of 32-bit width, "nonnegative" when
          * positive is required, etc.).
          *
          * Maybe a single integer type with the allowed range specified would be
          * better.
          *
          * Drop the PCMK_VALUE_NONNEGATIVE_INTEGER constant if we do this before
          * a release.
          */
         PCMK_OPT_CLUSTER_IPC_LIMIT, NULL, PCMK_VALUE_NONNEGATIVE_INTEGER, NULL,
         "500", pcmk__valid_positive_int,
         pcmk__opt_based,
         N_("Maximum IPC message backlog before disconnecting a cluster daemon"),
         N_("Raise this if log has \"Evicting client\" messages for cluster "
             "daemon PIDs (a good value is the number of resources in the "
             "cluster multiplied by the number of nodes)."),
     },
 
     // Orphans and stopping
     {
         PCMK_OPT_STOP_ALL_RESOURCES, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether the cluster should stop all active resources"),
         NULL,
     },
     {
         PCMK_OPT_STOP_ORPHAN_RESOURCES, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether to stop resources that were removed from the "
             "configuration"),
         NULL,
     },
     {
         PCMK_OPT_STOP_ORPHAN_ACTIONS, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, pcmk__valid_boolean,
         pcmk__opt_schedulerd,
         N_("Whether to cancel recurring actions removed from the "
             "configuration"),
         NULL,
     },
     {
         PCMK__OPT_REMOVE_AFTER_STOP, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, pcmk__valid_boolean,
         pcmk__opt_schedulerd|pcmk__opt_deprecated,
         N_("Whether to remove stopped resources from the executor"),
         N_("Values other than default are poorly tested and potentially "
             "dangerous."),
     },
 
     // Storing inputs
     {
         PCMK_OPT_PE_ERROR_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
         "-1", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The number of scheduler inputs resulting in errors to save"),
         N_("Zero to disable, -1 to store unlimited."),
     },
     {
         PCMK_OPT_PE_WARN_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
         "5000", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The number of scheduler inputs resulting in warnings to save"),
         N_("Zero to disable, -1 to store unlimited."),
     },
     {
         PCMK_OPT_PE_INPUT_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
         "4000", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The number of scheduler inputs without errors or warnings to save"),
         N_("Zero to disable, -1 to store unlimited."),
     },
 
     // Node health
     {
         PCMK_OPT_NODE_HEALTH_STRATEGY, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_NONE ", " PCMK_VALUE_MIGRATE_ON_RED ", "
                 PCMK_VALUE_ONLY_GREEN ", " PCMK_VALUE_PROGRESSIVE ", "
                 PCMK_VALUE_CUSTOM,
         PCMK_VALUE_NONE, pcmk__validate_health_strategy,
         pcmk__opt_schedulerd,
         N_("How cluster should react to node health attributes"),
         N_("Requires external entities to create node attributes (named with "
             "the prefix \"#health\") with values \"red\", \"yellow\", or "
             "\"green\".")
     },
     {
         PCMK_OPT_NODE_HEALTH_BASE, NULL, PCMK_VALUE_SCORE, NULL,
         "0", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("Base health score assigned to a node"),
         N_("Only used when \"node-health-strategy\" is set to "
             "\"progressive\"."),
     },
     {
         PCMK_OPT_NODE_HEALTH_GREEN, NULL, PCMK_VALUE_SCORE, NULL,
         "0", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The score to use for a node health attribute whose value is "
             "\"green\""),
         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
             "\"progressive\"."),
     },
     {
         PCMK_OPT_NODE_HEALTH_YELLOW, NULL, PCMK_VALUE_SCORE, NULL,
         "0", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The score to use for a node health attribute whose value is "
             "\"yellow\""),
         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
             "\"progressive\"."),
     },
     {
         PCMK_OPT_NODE_HEALTH_RED, NULL, PCMK_VALUE_SCORE, NULL,
         "-INFINITY", pcmk__valid_int,
         pcmk__opt_schedulerd,
         N_("The score to use for a node health attribute whose value is "
             "\"red\""),
         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
             "\"progressive\".")
     },
 
     // Placement strategy
     {
         PCMK_OPT_PLACEMENT_STRATEGY, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_DEFAULT ", " PCMK_VALUE_UTILIZATION ", "
                 PCMK_VALUE_MINIMAL ", " PCMK_VALUE_BALANCED,
         PCMK_VALUE_DEFAULT, pcmk__valid_placement_strategy,
         pcmk__opt_schedulerd,
         N_("How the cluster should allocate resources to nodes"),
         NULL,
     },
 
     { NULL, },
 };
 
 static const pcmk__cluster_option_t fencing_params[] = {
     /* name, old name, type, allowed values,
      * default value, validator,
      * flags,
      * short description,
      * long description
      */
     {
         PCMK_STONITH_HOST_ARGUMENT, NULL, PCMK_VALUE_STRING, NULL,
         "port", NULL,
         pcmk__opt_advanced,
         N_("An alternate parameter to supply instead of 'port'"),
         N_("Some devices do not support the standard 'port' parameter or may "
             "provide additional ones. Use this to specify an alternate, device-"
             "specific, parameter that should indicate the machine to be "
             "fenced. A value of \"none\" can be used to tell the cluster not "
             "to supply any additional parameters."),
     },
     {
         PCMK_STONITH_HOST_MAP, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("A mapping of node names to port numbers for devices that do not "
             "support node names."),
         N_("For example, \"node1:1;node2:2,3\" would tell the cluster to use "
             "port 1 for node1 and ports 2 and 3 for node2."),
     },
     {
         PCMK_STONITH_HOST_LIST, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("Nodes targeted by this device"),
         N_("Comma-separated list of nodes that can be targeted by this device "
            "(for example, \"node1,node2,node3\"). If pcmk_host_check is "
            "\"static-list\", either this or pcmk_host_map must be set."),
     },
     {
         PCMK_STONITH_HOST_CHECK, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_DYNAMIC_LIST ", " PCMK_VALUE_STATIC_LIST ", "
             PCMK_VALUE_STATUS ", " PCMK_VALUE_NONE,
         NULL, NULL,
         pcmk__opt_none,
         N_("How to determine which nodes can be targeted by the device"),
         N_("Use \"dynamic-list\" to query the device via the 'list' command; "
             "\"static-list\" to check the pcmk_host_list attribute; "
             "\"status\" to query the device via the 'status' command; or "
             "\"none\" to assume every device can fence every node. "
             "The default value is \"static-list\" if pcmk_host_map or "
             "pcmk_host_list is set; otherwise \"dynamic-list\" if the device "
             "supports the list operation; otherwise \"status\" if the device "
             "supports the status operation; otherwise \"none\""),
     },
     {
         PCMK_STONITH_DELAY_MAX, NULL, PCMK_VALUE_DURATION, NULL,
         "0s", NULL,
         pcmk__opt_none,
         N_("Enable a delay of no more than the time specified before executing "
             "fencing actions."),
         N_("Enable a delay of no more than the time specified before executing "
             "fencing actions. Pacemaker derives the overall delay by taking "
             "the value of pcmk_delay_base and adding a random delay value such "
             "that the sum is kept below this maximum."),
     },
     {
         PCMK_STONITH_DELAY_BASE, NULL, PCMK_VALUE_STRING, NULL,
         "0s", NULL,
         pcmk__opt_none,
         N_("Enable a base delay for fencing actions and specify base delay "
             "value."),
         N_("This enables a static delay for fencing actions, which can help "
             "avoid \"death matches\" where two nodes try to fence each other "
             "at the same time. If pcmk_delay_max is also used, a random delay "
             "will be added such that the total delay is kept below that value. "
             "This can be set to a single time value to apply to any node "
             "targeted by this device (useful if a separate device is "
             "configured for each target), or to a node map (for example, "
             "\"node1:1s;node2:5\") to set a different value for each target."),
     },
     {
         PCMK_STONITH_ACTION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
         "1", NULL,
         pcmk__opt_none,
         N_("The maximum number of actions can be performed in parallel on this "
             "device"),
         N_("Cluster property concurrent-fencing=\"true\" needs to be "
             "configured first. Then use this to specify the maximum number of "
             "actions can be performed in parallel on this device. A value of "
             "-1 means an unlimited number of actions can be performed in "
             "parallel."),
     },
     {
         "pcmk_reboot_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_REBOOT, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'reboot'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'reboot' action."),
     },
     {
         "pcmk_reboot_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'reboot' actions instead "
             "of stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'reboot' actions."),
     },
     {
         "pcmk_reboot_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'reboot' command within the "
             "timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'reboot' action before giving up."),
     },
     {
         "pcmk_off_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_OFF, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'off'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'off' action."),
     },
     {
         "pcmk_off_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'off' actions instead of "
             "stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'off' actions."),
     },
     {
         "pcmk_off_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'off' command within the "
             "timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'off' action before giving up."),
     },
     {
         "pcmk_on_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_ON, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'on'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'on' action."),
     },
     {
         "pcmk_on_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'on' actions instead of "
             "stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'on' actions."),
     },
     {
         "pcmk_on_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'on' command within the "
             "timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'on' action before giving up."),
     },
     {
         "pcmk_list_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_LIST, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'list'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'list' action."),
     },
     {
         "pcmk_list_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'list' actions instead of "
             "stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'list' actions."),
     },
     {
         "pcmk_list_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'list' command within the "
             "timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'list' action before giving up."),
     },
     {
         "pcmk_monitor_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_MONITOR, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'monitor'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'monitor' action."),
     },
     {
         "pcmk_monitor_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'monitor' actions instead "
             "of stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'monitor' actions."),
     },
     {
         "pcmk_monitor_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'monitor' command within "
             "the timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'monitor' action before giving up."),
     },
     {
         "pcmk_status_action", NULL, PCMK_VALUE_STRING, NULL,
         PCMK_ACTION_STATUS, NULL,
         pcmk__opt_advanced,
         N_("An alternate command to run instead of 'status'"),
         N_("Some devices do not support the standard commands or may provide "
             "additional ones. Use this to specify an alternate, device-"
             "specific, command that implements the 'status' action."),
     },
     {
         "pcmk_status_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_advanced,
         N_("Specify an alternate timeout to use for 'status' actions instead "
             "of stonith-timeout"),
         N_("Some devices need much more/less time to complete than normal. "
             "Use this to specify an alternate, device-specific, timeout for "
             "'status' actions."),
     },
     {
         "pcmk_status_retries", NULL, PCMK_VALUE_INTEGER, NULL,
         "2", NULL,
         pcmk__opt_advanced,
         N_("The maximum number of times to try the 'status' command within "
             "the timeout period"),
         N_("Some devices do not support multiple connections. Operations may "
             "\"fail\" if the device is busy with another task. In that case, "
             "Pacemaker will automatically retry the operation if there is time "
             "remaining. Use this option to alter the number of times Pacemaker "
             "tries a 'status' action before giving up."),
     },
 
     { NULL, },
 };
 
 static const pcmk__cluster_option_t primitive_meta[] = {
     /* name, old name, type, allowed values,
      * default value, validator,
      * flags,
      * short description,
      * long description
      */
     {
         PCMK_META_PRIORITY, NULL, PCMK_VALUE_SCORE, NULL,
         "0", NULL,
         pcmk__opt_none,
         N_("Resource assignment priority"),
         N_("If not all resources can be active, the cluster will stop "
             "lower-priority resources in order to keep higher-priority ones "
             "active."),
     },
     {
         PCMK_META_CRITICAL, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, NULL,
         pcmk__opt_none,
         N_("Default value for influence in colocation constraints"),
         N_("Use this value as the default for influence in all colocation "
             "constraints involving this resource, as well as in the implicit "
             "colocation constraints created if this resource is in a group."),
     },
     {
         PCMK_META_TARGET_ROLE, NULL, PCMK_VALUE_SELECT,
             PCMK_ROLE_STOPPED ", " PCMK_ROLE_STARTED ", "
             PCMK_ROLE_UNPROMOTED ", " PCMK_ROLE_PROMOTED,
         PCMK_ROLE_STARTED, NULL,
         pcmk__opt_none,
         N_("State the cluster should attempt to keep this resource in"),
         N_("\"Stopped\" forces the resource to be stopped. "
             "\"Started\" allows the resource to be started (and in the case of "
             "promotable clone resources, promoted if appropriate). "
             "\"Unpromoted\" allows the resource to be started, but only in the "
             "unpromoted role if the resource is promotable. "
             "\"Promoted\" is equivalent to \"Started\"."),
     },
     {
         PCMK_META_IS_MANAGED, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, NULL,
         pcmk__opt_none,
         N_("Whether the cluster is allowed to actively change the resource's "
             "state"),
         N_("If false, the cluster will not start, stop, promote, or demote the "
             "resource on any node. Recurring actions for the resource are "
             "unaffected. If true, a true value for the maintenance-mode "
             "cluster option, the maintenance node attribute, or the "
             "maintenance resource meta-attribute overrides this."),
     },
     {
         PCMK_META_MAINTENANCE, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, NULL,
         pcmk__opt_none,
         N_("If true, the cluster will not schedule any actions involving the "
             "resource"),
         N_("If true, the cluster will not start, stop, promote, or demote the "
             "resource on any node, and will pause any recurring monitors "
             "(except those specifying role as \"Stopped\"). If false, a true "
             "value for the maintenance-mode cluster option or maintenance node "
             "attribute overrides this."),
     },
     {
         PCMK_META_RESOURCE_STICKINESS, NULL, PCMK_VALUE_SCORE, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("Score to add to the current node when a resource is already "
             "active"),
         N_("Score to add to the current node when a resource is already "
             "active. This allows running resources to stay where they are, "
             "even if they would be placed elsewhere if they were being started "
             "from a stopped state. "
             "The default is 1 for individual clone instances, and 0 for all "
             "other resources."),
     },
     {
         PCMK_META_REQUIRES, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_NOTHING ", " PCMK_VALUE_QUORUM ", "
             PCMK_VALUE_FENCING ", " PCMK_VALUE_UNFENCING,
         NULL, NULL,
         pcmk__opt_none,
         N_("Conditions under which the resource can be started"),
         N_("Conditions under which the resource can be started. "
             "\"nothing\" means the cluster can always start this resource. "
             "\"quorum\" means the cluster can start this resource only if a "
             "majority of the configured nodes are active. "
             "\"fencing\" means the cluster can start this resource only if a "
             "majority of the configured nodes are active and any failed or "
             "unknown nodes have been fenced. "
             "\"unfencing\" means the cluster can start this resource only if "
             "a majority of the configured nodes are active and any failed or "
             "unknown nodes have been fenced, and only on nodes that have been "
             "unfenced. "
             "The default is \"quorum\" for resources with a class of stonith; "
             "otherwise, \"unfencing\" if unfencing is active in the cluster; "
             "otherwise, \"fencing\" if the stonith-enabled cluster option is "
             "true; "
             "otherwise, \"quorum\"."),
     },
     {
         PCMK_META_MIGRATION_THRESHOLD, NULL, PCMK_VALUE_SCORE, NULL,
         PCMK_VALUE_INFINITY, NULL,
         pcmk__opt_none,
         N_("Number of failures on a node before the resource becomes "
             "ineligible to run there."),
         N_("Number of failures that may occur for this resource on a node, "
             "before that node is marked ineligible to host this resource. A "
             "value of 0 indicates that this feature is disabled (the node will "
             "never be marked ineligible). By contrast, the cluster treats "
             "\"INFINITY\" (the default) as a very large but finite number. "
             "This option has an effect only if the failed operation specifies "
             "its on-fail attribute as \"restart\" (the default), and "
             "additionally for failed start operations, if the "
             "start-failure-is-fatal cluster property is set to false."),
     },
     {
         PCMK_META_FAILURE_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
         "0", NULL,
         pcmk__opt_none,
         N_("Number of seconds before acting as if a failure had not occurred"),
         N_("Number of seconds after a failed action for this resource before "
             "acting as if the failure had not occurred, and potentially "
             "allowing the resource back to the node on which it failed. "
             "A value of 0 indicates that this feature is disabled."),
     },
     {
         PCMK_META_MULTIPLE_ACTIVE, NULL, PCMK_VALUE_SELECT,
             PCMK_VALUE_BLOCK ", " PCMK_VALUE_STOP_ONLY ", "
             PCMK_VALUE_STOP_START ", " PCMK_VALUE_STOP_UNEXPECTED,
         PCMK_VALUE_STOP_START, NULL,
         pcmk__opt_none,
         N_("What to do if the cluster finds the resource active on more than "
             "one node"),
         N_("What to do if the cluster finds the resource active on more than "
             "one node. "
             "\"block\" means to mark the resource as unmanaged. "
             "\"stop_only\" means to stop all active instances of this resource "
             "and leave them stopped. "
             "\"stop_start\" means to stop all active instances of this "
             "resource and start the resource in one location only. "
             "\"stop_unexpected\" means to stop all active instances of this "
             "resource except where the resource should be active. (This should "
             "be used only when extra instances are not expected to disrupt "
             "existing instances, and the resource agent's monitor of an "
             "existing instance is capable of detecting any problems that could "
             "be caused. Note that any resources ordered after this one will "
             "still need to be restarted.)"),
     },
     {
         PCMK_META_ALLOW_MIGRATE, NULL, PCMK_VALUE_BOOLEAN, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("Whether the cluster should try to \"live migrate\" this resource "
             "when it needs to be moved"),
         N_("Whether the cluster should try to \"live migrate\" this resource "
             "when it needs to be moved. "
             "The default is true for ocf:pacemaker:remote resources, and false "
             "otherwise."),
     },
     {
         PCMK_META_ALLOW_UNHEALTHY_NODES, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_FALSE, NULL,
         pcmk__opt_none,
         N_("Whether the resource should be allowed to run on a node even if "
             "the node's health score would otherwise prevent it"),
         NULL,
     },
     {
         PCMK_META_CONTAINER_ATTRIBUTE_TARGET, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("Where to check user-defined node attributes"),
         N_("Whether to check user-defined node attributes on the physical host "
             "where a container is running or on the local node. This is "
             "usually set for a bundle resource and inherited by the bundle's "
             "primitive resource. "
             "A value of \"host\" means to check user-defined node attributes "
             "on the underlying physical host. Any other value means to check "
             "user-defined node attributes on the local node (for a bundled "
             "primitive resource, this is the bundle node)."),
     },
     {
         PCMK_META_REMOTE_NODE, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("Name of the Pacemaker Remote guest node this resource is "
             "associated with, if any"),
         N_("Name of the Pacemaker Remote guest node this resource is "
             "associated with, if any. If specified, this both enables the "
             "resource as a guest node and defines the unique name used to "
             "identify the guest node. The guest must be configured to run the "
             "Pacemaker Remote daemon when it is started. "
             "WARNING: This value cannot overlap with any resource or node "
             "IDs."),
     },
     {
         PCMK_META_REMOTE_ADDR, NULL, PCMK_VALUE_STRING, NULL,
         NULL, NULL,
         pcmk__opt_none,
         N_("If remote-node is specified, the IP address or hostname used to "
             "connect to the guest via Pacemaker Remote"),
         N_("If remote-node is specified, the IP address or hostname used to "
             "connect to the guest via Pacemaker Remote. The Pacemaker Remote "
             "daemon on the guest must be configured to accept connections on "
             "this address. "
             "The default is the value of the remote-node meta-attribute."),
     },
     {
         PCMK_META_REMOTE_PORT, NULL, PCMK_VALUE_PORT, NULL,
         "3121", NULL,
         pcmk__opt_none,
         N_("If remote-node is specified, port on the guest used for its "
             "Pacemaker Remote connection"),
         N_("If remote-node is specified, the port on the guest used for its "
             "Pacemaker Remote connection. The Pacemaker Remote daemon on the "
             "guest must be configured to listen on this port."),
     },
     {
         PCMK_META_REMOTE_CONNECT_TIMEOUT, NULL, PCMK_VALUE_TIMEOUT, NULL,
         "60s", NULL,
         pcmk__opt_none,
         N_("If remote-node is specified, how long before a pending Pacemaker "
             "Remote guest connection times out."),
         NULL,
     },
     {
         PCMK_META_REMOTE_ALLOW_MIGRATE, NULL, PCMK_VALUE_BOOLEAN, NULL,
         PCMK_VALUE_TRUE, NULL,
         pcmk__opt_none,
         N_("If remote-node is specified, this acts as the allow-migrate "
             "meta-attribute for the implicit remote connection resource "
             "(ocf:pacemaker:remote)."),
         NULL,
     },
 
     { NULL, },
 };
 
 /*
  * Environment variable option handling
  */
 
 /*!
  * \internal
  * \brief Get the value of a Pacemaker environment variable option
  *
  * If an environment variable option is set, with either a PCMK_ or (for
  * backward compatibility) HA_ prefix, log and return the value.
  *
  * \param[in] option  Environment variable name (without prefix)
  *
  * \return Value of environment variable option, or NULL in case of
  *         option name too long or value not found
  */
 const char *
 pcmk__env_option(const char *option)
 {
     const char *const prefixes[] = {"PCMK_", "HA_"};
     char env_name[NAME_MAX];
     const char *value = NULL;
 
     CRM_CHECK(!pcmk__str_empty(option), return NULL);
 
     for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
         int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
 
         if (rv < 0) {
             crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
                     strerror(errno));
             return NULL;
         }
 
         if (rv >= sizeof(env_name)) {
             crm_trace("\"%s%s\" is too long", prefixes[i], option);
             continue;
         }
 
         value = getenv(env_name);
         if (value != NULL) {
             crm_trace("Found %s = %s", env_name, value);
             return value;
         }
     }
 
     crm_trace("Nothing found for %s", option);
     return NULL;
 }
 
 /*!
  * \brief Set or unset a Pacemaker environment variable option
  *
  * Set an environment variable option with a \c "PCMK_" prefix and optionally
  * an \c "HA_" prefix for backward compatibility.
  *
  * \param[in] option  Environment variable name (without prefix)
  * \param[in] value   New value (or NULL to unset)
  * \param[in] compat  If false and \p value is not \c NULL, set only
  *                    \c "PCMK_<option>"; otherwise, set (or unset) both
  *                    \c "PCMK_<option>" and \c "HA_<option>"
  *
  * \note \p compat is ignored when \p value is \c NULL. A \c NULL \p value
  *       means we're unsetting \p option. \c pcmk__get_env_option() checks for
  *       both prefixes, so we want to clear them both.
  */
 void
 pcmk__set_env_option(const char *option, const char *value, bool compat)
 {
     // @COMPAT Drop support for "HA_" options eventually
     const char *const prefixes[] = {"PCMK_", "HA_"};
     char env_name[NAME_MAX];
 
     CRM_CHECK(!pcmk__str_empty(option) && (strchr(option, '=') == NULL),
               return);
 
     for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
         int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
 
         if (rv < 0) {
             crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
                     strerror(errno));
             return;
         }
 
         if (rv >= sizeof(env_name)) {
             crm_trace("\"%s%s\" is too long", prefixes[i], option);
             continue;
         }
 
         if (value != NULL) {
             crm_trace("Setting %s to %s", env_name, value);
             rv = setenv(env_name, value, 1);
         } else {
             crm_trace("Unsetting %s", env_name);
             rv = unsetenv(env_name);
         }
 
         if (rv < 0) {
             crm_err("Failed to %sset %s: %s", (value != NULL)? "" : "un",
                     env_name, strerror(errno));
         }
 
         if (!compat && (value != NULL)) {
             // For set, don't proceed to HA_<option> unless compat is enabled
             break;
         }
     }
 }
 
 /*!
  * \internal
  * \brief Check whether Pacemaker environment variable option is enabled
  *
  * Given a Pacemaker environment variable option that can either be boolean
  * or a list of daemon names, return true if the option is enabled for a given
  * daemon.
  *
  * \param[in] daemon   Daemon name (can be NULL)
  * \param[in] option   Pacemaker environment variable name
  *
  * \return true if variable is enabled for daemon, otherwise false
  */
 bool
 pcmk__env_option_enabled(const char *daemon, const char *option)
 {
     const char *value = pcmk__env_option(option);
 
     return (value != NULL)
         && (crm_is_true(value)
             || ((daemon != NULL) && (strstr(value, daemon) != NULL)));
 }
 
 
 /*
  * Cluster option handling
  */
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid interval specification
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid interval specification, or \c false
  *         otherwise
  */
 bool
 pcmk__valid_interval_spec(const char *value)
 {
     return pcmk_parse_interval_spec(value, NULL) == pcmk_rc_ok;
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid boolean value
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid boolean value, or \c false otherwise
  */
 bool
 pcmk__valid_boolean(const char *value)
 {
     return crm_str_to_boolean(value, NULL) == 1;
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid integer
  *
  * Valid values include \c INFINITY, \c -INFINITY, and all 64-bit integers.
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid integer, or \c false otherwise
  */
 bool
 pcmk__valid_int(const char *value)
 {
     return (value != NULL)
            && (pcmk_str_is_infinity(value)
                || pcmk_str_is_minus_infinity(value)
                || (pcmk__scan_ll(value, NULL, 0LL) == pcmk_rc_ok));
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid positive integer
  *
  * Valid values include \c INFINITY and all 64-bit positive integers.
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid positive integer, or \c false
  *         otherwise
  */
 bool
 pcmk__valid_positive_int(const char *value)
 {
     long long num = 0LL;
 
     return pcmk_str_is_infinity(value)
            || ((pcmk__scan_ll(value, &num, 0LL) == pcmk_rc_ok)
                && (num > 0));
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid
  *        \c PCMK__OPT_NO_QUORUM_POLICY value
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid \c PCMK__OPT_NO_QUORUM_POLICY value,
  *         or \c false otherwise
  */
 bool
 pcmk__valid_no_quorum_policy(const char *value)
 {
     return pcmk__strcase_any_of(value,
                                 PCMK_VALUE_STOP, PCMK_VALUE_FREEZE,
                                 PCMK_VALUE_IGNORE, PCMK_VALUE_DEMOTE,
                                 PCMK_VALUE_FENCE, PCMK_VALUE_FENCE_LEGACY,
                                 NULL);
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid percentage
  *
  * Valid values include long integers, with an optional trailing string
  * beginning with '%'.
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid percentage value, or \c false
  *         otherwise
  */
 bool
 pcmk__valid_percentage(const char *value)
 {
     char *end = NULL;
     float number = strtof(value, &end);
 
     return ((end == NULL) || (end[0] == '%')) && (number >= 0);
 }
 
 /*!
  * \internal
  * \brief Check whether a string represents a valid placement strategy
  *
  * \param[in] value  String to validate
  *
  * \return \c true if \p value is a valid placement strategy, or \c false
  *         otherwise
  */
 bool
 pcmk__valid_placement_strategy(const char *value)
 {
     return pcmk__strcase_any_of(value,
                                 PCMK_VALUE_DEFAULT, PCMK_VALUE_UTILIZATION,
                                 PCMK_VALUE_MINIMAL, PCMK_VALUE_BALANCED, NULL);
 }
 
 /*!
  * \internal
  * \brief Check a table of configured options for a particular option
  *
  * \param[in,out] table   Name/value pairs for configured options
  * \param[in]     option  Option to look up
  *
  * \return Option value (from supplied options table or default value)
  */
 static const char *
 cluster_option_value(GHashTable *table, const pcmk__cluster_option_t *option)
 {
     const char *value = NULL;
 
     CRM_ASSERT((option != NULL) && (option->name != NULL));
 
     if (table != NULL) {
         value = g_hash_table_lookup(table, option->name);
 
         if ((value == NULL) && (option->alt_name != NULL)) {
             value = g_hash_table_lookup(table, option->alt_name);
             if (value != NULL) {
                 pcmk__config_warn("Support for legacy name '%s' for cluster "
                                   "option '%s' is deprecated and will be "
                                   "removed in a future release",
                                   option->alt_name, option->name);
 
                 // Inserting copy with current name ensures we only warn once
                 pcmk__insert_dup(table, option->name, value);
             }
         }
 
         if ((value != NULL) && (option->is_valid != NULL)
             && !option->is_valid(value)) {
 
             pcmk__config_err("Using default value for cluster option '%s' "
                              "because '%s' is invalid", option->name, value);
             value = NULL;
         }
 
         if (value != NULL) {
             return value;
         }
     }
 
     // No value found, use default
     value = option->default_value;
 
     if (value == NULL) {
         crm_trace("No value or default provided for cluster option '%s'",
                   option->name);
         return NULL;
     }
 
     CRM_CHECK((option->is_valid == NULL) || option->is_valid(value),
               crm_err("Bug: default value for cluster option '%s' is invalid",
                       option->name);
               return NULL);
 
     crm_trace("Using default value '%s' for cluster option '%s'",
               value, option->name);
     if (table != NULL) {
         pcmk__insert_dup(table, option->name, value);
     }
     return value;
 }
 
 /*!
  * \internal
  * \brief Get the value of a cluster option
  *
  * \param[in,out] options  Name/value pairs for configured options
  * \param[in]     name     (Primary) option name to look for
  *
  * \return Option value
  */
 const char *
 pcmk__cluster_option(GHashTable *options, const char *name)
 {
     for (const pcmk__cluster_option_t *option = cluster_options;
          option->name != NULL; option++) {
 
         if (pcmk__str_eq(name, option->name, pcmk__str_casei)) {
             return cluster_option_value(options, option);
         }
     }
     CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
     return NULL;
 }
 
 /*!
  * \internal
  * \brief Output cluster option metadata as OCF-like XML
  *
  * \param[in,out] out         Output object
  * \param[in]     name        Fake resource agent name for the option list
  * \param[in]     desc_short  Short description of the option list
  * \param[in]     desc_long   Long description of the option list
  * \param[in]     filter      Group of <tt>enum pcmk__opt_flags</tt>; output an
  *                            option only if its \c flags member has all these
  *                            flags set
  * \param[in]     all         If \c true, output all options; otherwise, exclude
  *                            advanced and deprecated options unless
  *                            \c pcmk__opt_advanced and \c pcmk__opt_deprecated
  *                            flags (respectively) are set in \p filter. This is
  *                            always treated as true for XML output objects.
  *
  * \return Standard Pacemaker return code
  */
 int
 pcmk__output_cluster_options(pcmk__output_t *out, const char *name,
                              const char *desc_short, const char *desc_long,
                              uint32_t filter, bool all)
 {
     return out->message(out, "option-list", name, desc_short, desc_long, filter,
                         cluster_options, all);
 }
 
 /*!
  * \internal
  * \brief Output primitive resource meta-attributes as OCF-like XML
  *
  * \param[in,out] out         Output object
  * \param[in]     name        Fake resource agent name for the option list
  * \param[in]     desc_short  Short description of the option list
  * \param[in]     desc_long   Long description of the option list
  * \param[in]     all         If \c true, output all options; otherwise, exclude
  *                            advanced and deprecated options. This is always
  *                            treated as true for XML output objects.
  *
  * \return Standard Pacemaker return code
  */
 int
 pcmk__output_primitive_meta(pcmk__output_t *out, const char *name,
                             const char *desc_short, const char *desc_long,
                             bool all)
 {
     return out->message(out, "option-list", name, desc_short, desc_long,
                         pcmk__opt_none, primitive_meta, all);
 }
 
 /*!
  * \internal
  * \brief Output fence device common parameter metadata as OCF-like XML
  *
  * These are parameters that are available for all fencing resources, regardless
  * of type. They are processed by Pacemaker, rather than by the fence agent or
  * the fencing library.
  *
  * \param[in,out] out         Output object
  * \param[in]     name        Fake resource agent name for the option list
  * \param[in]     desc_short  Short description of the option list
  * \param[in]     desc_long   Long description of the option list
  * \param[in]     all         If \c true, output all options; otherwise, exclude
  *                            advanced and deprecated options. This is always
  *                            treated as true for XML output objects.
  *
  * \return Standard Pacemaker return code
  */
 int
 pcmk__output_fencing_params(pcmk__output_t *out, const char *name,
                           const char *desc_short, const char *desc_long,
                           bool all)
 {
     return out->message(out, "option-list", name, desc_short, desc_long,
                         pcmk__opt_none, fencing_params, all);
 }
 
 /*!
  * \internal
  * \brief Output a list of cluster options for a daemon
  *
  * \brief[in,out] out         Output object
  * \brief[in]     name        Daemon name
  * \brief[in]     desc_short  Short description of the option list
  * \brief[in]     desc_long   Long description of the option list
  * \brief[in]     filter      <tt>enum pcmk__opt_flags</tt> flag corresponding
  *                            to daemon
  *
  * \return Standard Pacemaker return code
  */
 int
 pcmk__daemon_metadata(pcmk__output_t *out, const char *name,
                       const char *desc_short, const char *desc_long,
                       enum pcmk__opt_flags filter)
 {
     // @COMPAT Drop this function when we drop daemon metadata
     pcmk__output_t *tmp_out = NULL;
     xmlNode *top = NULL;
     const xmlNode *metadata = NULL;
     GString *metadata_s = NULL;
 
     int rc = pcmk__output_new(&tmp_out, "xml", "/dev/null", NULL);
 
     if (rc != pcmk_rc_ok) {
         return rc;
     }
 
     pcmk__output_set_legacy_xml(tmp_out);
 
     if (filter == pcmk__opt_fencing) {
         pcmk__output_fencing_params(tmp_out, name, desc_short, desc_long, true);
     } else {
         pcmk__output_cluster_options(tmp_out, name, desc_short, desc_long,
                                      (uint32_t) filter, true);
     }
 
     tmp_out->finish(tmp_out, CRM_EX_OK, false, (void **) &top);
     metadata = pcmk__xe_first_child(top, PCMK_XE_RESOURCE_AGENT, NULL, NULL);
 
     metadata_s = g_string_sized_new(16384);
     pcmk__xml_string(metadata, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
                      metadata_s, 0);
 
     out->output_xml(out, PCMK_XE_METADATA, metadata_s->str);
 
     pcmk__output_free(tmp_out);
     free_xml(top);
     g_string_free(metadata_s, TRUE);
     return pcmk_rc_ok;
 }
 
 void
 pcmk__validate_cluster_options(GHashTable *options)
 {
     for (const pcmk__cluster_option_t *option = cluster_options;
          option->name != NULL; option++) {
 
         cluster_option_value(options, option);
     }
 }
diff --git a/lib/pengine/status.c b/lib/pengine/status.c
index 1a1390d95c..4bbf278745 100644
--- a/lib/pengine/status.c
+++ b/lib/pengine/status.c
@@ -1,523 +1,523 @@
 /*
  * Copyright 2004-2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 #include <crm/common/xml.h>
 #include <crm/common/cib_internal.h>
 
 #include <glib.h>
 
 #include <crm/pengine/internal.h>
 #include <pe_status_private.h>
 
 /*!
  * \brief Create a new object to hold scheduler data
  *
  * \return New, initialized scheduler data on success, else NULL (and set errno)
  * \note Only pcmk_scheduler_t objects created with this function (as opposed
  *       to statically declared or directly allocated) should be used with the
  *       functions in this library, to allow for future extensions to the
  *       data type. The caller is responsible for freeing the memory with
  *       pe_free_working_set() when the instance is no longer needed.
  */
 pcmk_scheduler_t *
 pe_new_working_set(void)
 {
     pcmk_scheduler_t *scheduler = calloc(1, sizeof(pcmk_scheduler_t));
 
     if (scheduler != NULL) {
         set_working_set_defaults(scheduler);
     }
     return scheduler;
 }
 
 /*!
  * \brief Free scheduler data
  *
  * \param[in,out] scheduler  Scheduler data to free
  */
 void
 pe_free_working_set(pcmk_scheduler_t *scheduler)
 {
     if (scheduler != NULL) {
         pe_reset_working_set(scheduler);
         scheduler->priv = NULL;
         free(scheduler);
     }
 }
 
 #define XPATH_DEPRECATED_RULES                          \
     "//" PCMK_XE_OP_DEFAULTS "//" PCMK_XE_EXPRESSION    \
     "|//" PCMK_XE_OP "//" PCMK_XE_EXPRESSION
 
 /*!
  * \internal
  * \brief Log a warning for deprecated rule syntax in operations
  *
  * \param[in] scheduler  Scheduler data
  */
 static void
 check_for_deprecated_rules(pcmk_scheduler_t *scheduler)
 {
     // @COMPAT Drop this function when support for the syntax is dropped
     xmlNode *deprecated = get_xpath_object(XPATH_DEPRECATED_RULES,
                                            scheduler->input, LOG_NEVER);
 
     if (deprecated != NULL) {
         pcmk__warn_once(pcmk__wo_op_attr_expr,
                         "Support for rules with node attribute expressions in "
                         PCMK_XE_OP " or " PCMK_XE_OP_DEFAULTS " is deprecated "
                         "and will be dropped in a future release");
     }
 }
 
 /*
  * Unpack everything
  * At the end you'll have:
  *  - A list of nodes
  *  - A list of resources (each with any dependencies on other resources)
  *  - A list of constraints between resources and nodes
  *  - A list of constraints between start/stop actions
  *  - A list of nodes that need to be stonith'd
  *  - A list of nodes that need to be shutdown
  *  - A list of the possible stop/start actions (without dependencies)
  */
 gboolean
 cluster_status(pcmk_scheduler_t * scheduler)
 {
     const char *new_version = NULL;
     xmlNode *section = NULL;
 
     if ((scheduler == NULL) || (scheduler->input == NULL)) {
         return FALSE;
     }
 
     new_version = crm_element_value(scheduler->input, PCMK_XA_CRM_FEATURE_SET);
 
     if (pcmk__check_feature_set(new_version) != pcmk_rc_ok) {
         pcmk__config_err("Can't process CIB with feature set '%s' greater than our own '%s'",
                          new_version, CRM_FEATURE_SET);
         return FALSE;
     }
 
     crm_trace("Beginning unpack");
 
     if (scheduler->failed != NULL) {
         free_xml(scheduler->failed);
     }
     scheduler->failed = pcmk__xe_create(NULL, "failed-ops");
 
     if (scheduler->now == NULL) {
         scheduler->now = crm_time_new(NULL);
     }
 
     if (scheduler->dc_uuid == NULL) {
         scheduler->dc_uuid = crm_element_value_copy(scheduler->input,
                                                     PCMK_XA_DC_UUID);
     }
 
     if (pcmk__xe_attr_is_true(scheduler->input, PCMK_XA_HAVE_QUORUM)) {
         pcmk__set_scheduler_flags(scheduler, pcmk_sched_quorate);
     } else {
         pcmk__clear_scheduler_flags(scheduler, pcmk_sched_quorate);
     }
 
     scheduler->op_defaults = get_xpath_object("//" PCMK_XE_OP_DEFAULTS,
                                               scheduler->input, LOG_NEVER);
     check_for_deprecated_rules(scheduler);
 
     scheduler->rsc_defaults = get_xpath_object("//" PCMK_XE_RSC_DEFAULTS,
                                                scheduler->input, LOG_NEVER);
 
     section = get_xpath_object("//" PCMK_XE_CRM_CONFIG, scheduler->input,
                                LOG_TRACE);
     unpack_config(section, scheduler);
 
    if (!pcmk_any_flags_set(scheduler->flags,
                            pcmk_sched_location_only|pcmk_sched_quorate)
        && (scheduler->no_quorum_policy != pcmk_no_quorum_ignore)) {
         pcmk__sched_warn("Fencing and resource management disabled "
                          "due to lack of quorum");
     }
 
     section = get_xpath_object("//" PCMK_XE_NODES, scheduler->input, LOG_TRACE);
     unpack_nodes(section, scheduler);
 
     section = get_xpath_object("//" PCMK_XE_RESOURCES, scheduler->input,
                                LOG_TRACE);
     if (!pcmk_is_set(scheduler->flags, pcmk_sched_location_only)) {
         unpack_remote_nodes(section, scheduler);
     }
     unpack_resources(section, scheduler);
 
     section = get_xpath_object("//" PCMK_XE_FENCING_TOPOLOGY, scheduler->input,
                                LOG_TRACE);
     pcmk__unpack_fencing_topology(section, scheduler);
 
     section = get_xpath_object("//" PCMK_XE_TAGS, scheduler->input, LOG_NEVER);
     unpack_tags(section, scheduler);
 
     if (!pcmk_is_set(scheduler->flags, pcmk_sched_location_only)) {
         section = get_xpath_object("//" PCMK_XE_STATUS, scheduler->input,
                                    LOG_TRACE);
         unpack_status(section, scheduler);
     }
 
     if (!pcmk_is_set(scheduler->flags, pcmk_sched_no_counts)) {
         for (GList *item = scheduler->resources; item != NULL;
              item = item->next) {
             ((pcmk_resource_t *) (item->data))->fns->count(item->data);
         }
         crm_trace("Cluster resource count: %d (%d disabled, %d blocked)",
                   scheduler->ninstances, scheduler->disabled_resources,
                   scheduler->blocked_resources);
     }
 
     pcmk__set_scheduler_flags(scheduler, pcmk_sched_have_status);
     return TRUE;
 }
 
 /*!
  * \internal
  * \brief Free a list of pcmk_resource_t
  *
  * \param[in,out] resources  List to free
  *
  * \note When the scheduler's resource list is freed, that includes the original
  *       storage for the uname and id of any Pacemaker Remote nodes in the
  *       scheduler's node list, so take care not to use those afterward.
  * \todo Refactor pcmk_node_t to strdup() the node name.
  */
 static void
 pe_free_resources(GList *resources)
 {
     pcmk_resource_t *rsc = NULL;
     GList *iterator = resources;
 
     while (iterator != NULL) {
         rsc = (pcmk_resource_t *) iterator->data;
         iterator = iterator->next;
         rsc->fns->free(rsc);
     }
     if (resources != NULL) {
         g_list_free(resources);
     }
 }
 
 static void
 pe_free_actions(GList *actions)
 {
     GList *iterator = actions;
 
     while (iterator != NULL) {
         pe_free_action(iterator->data);
         iterator = iterator->next;
     }
     if (actions != NULL) {
         g_list_free(actions);
     }
 }
 
 static void
 pe_free_nodes(GList *nodes)
 {
     for (GList *iterator = nodes; iterator != NULL; iterator = iterator->next) {
         pcmk_node_t *node = (pcmk_node_t *) iterator->data;
 
         // Shouldn't be possible, but to be safe ...
         if (node == NULL) {
             continue;
         }
         if (node->details == NULL) {
             free(node);
             continue;
         }
 
         /* This is called after pe_free_resources(), which means that we can't
          * use node->details->uname for Pacemaker Remote nodes.
          */
         crm_trace("Freeing node %s", (pcmk__is_pacemaker_remote_node(node)?
                   "(guest or remote)" : pcmk__node_name(node)));
 
         if (node->details->attrs != NULL) {
             g_hash_table_destroy(node->details->attrs);
         }
         if (node->details->utilization != NULL) {
             g_hash_table_destroy(node->details->utilization);
         }
         if (node->details->digest_cache != NULL) {
             g_hash_table_destroy(node->details->digest_cache);
         }
         g_list_free(node->details->running_rsc);
         g_list_free(node->details->allocated_rsc);
         free(node->details);
         free(node);
     }
     if (nodes != NULL) {
         g_list_free(nodes);
     }
 }
 
 static void
 pe__free_ordering(GList *constraints)
 {
     GList *iterator = constraints;
 
     while (iterator != NULL) {
         pcmk__action_relation_t *order = iterator->data;
 
         iterator = iterator->next;
 
         free(order->task1);
         free(order->task2);
         free(order);
     }
     if (constraints != NULL) {
         g_list_free(constraints);
     }
 }
 
 static void
 pe__free_location(GList *constraints)
 {
     GList *iterator = constraints;
 
     while (iterator != NULL) {
         pcmk__location_t *cons = iterator->data;
 
         iterator = iterator->next;
 
         g_list_free_full(cons->nodes, free);
         free(cons->id);
         free(cons);
     }
     if (constraints != NULL) {
         g_list_free(constraints);
     }
 }
 
 /*!
  * \brief Reset scheduler data to defaults without freeing it or constraints
  *
  * \param[in,out] scheduler  Scheduler data to reset
  *
  * \deprecated This function is deprecated as part of the API;
  *             pe_reset_working_set() should be used instead.
  */
 void
 cleanup_calculations(pcmk_scheduler_t *scheduler)
 {
     if (scheduler == NULL) {
         return;
     }
 
     pcmk__clear_scheduler_flags(scheduler, pcmk_sched_have_status);
     if (scheduler->config_hash != NULL) {
         g_hash_table_destroy(scheduler->config_hash);
     }
 
     if (scheduler->singletons != NULL) {
         g_hash_table_destroy(scheduler->singletons);
     }
 
     if (scheduler->tickets) {
         g_hash_table_destroy(scheduler->tickets);
     }
 
     if (scheduler->template_rsc_sets) {
         g_hash_table_destroy(scheduler->template_rsc_sets);
     }
 
     if (scheduler->tags) {
         g_hash_table_destroy(scheduler->tags);
     }
 
     free(scheduler->dc_uuid);
 
     crm_trace("deleting resources");
     pe_free_resources(scheduler->resources);
 
     crm_trace("deleting actions");
     pe_free_actions(scheduler->actions);
 
     crm_trace("deleting nodes");
     pe_free_nodes(scheduler->nodes);
 
     pe__free_param_checks(scheduler);
     g_list_free(scheduler->stop_needed);
     free_xml(scheduler->graph);
     crm_time_free(scheduler->now);
     free_xml(scheduler->input);
     free_xml(scheduler->failed);
 
     set_working_set_defaults(scheduler);
 
     CRM_CHECK(scheduler->ordering_constraints == NULL,;
         );
     CRM_CHECK(scheduler->placement_constraints == NULL,;
         );
 }
 
 /*!
  * \brief Reset scheduler data to default state without freeing it
  *
  * \param[in,out] scheduler  Scheduler data to reset
  */
 void
 pe_reset_working_set(pcmk_scheduler_t *scheduler)
 {
     if (scheduler == NULL) {
         return;
     }
 
     crm_trace("Deleting %d ordering constraints",
               g_list_length(scheduler->ordering_constraints));
     pe__free_ordering(scheduler->ordering_constraints);
     scheduler->ordering_constraints = NULL;
 
     crm_trace("Deleting %d location constraints",
               g_list_length(scheduler->placement_constraints));
     pe__free_location(scheduler->placement_constraints);
     scheduler->placement_constraints = NULL;
 
     crm_trace("Deleting %d colocation constraints",
               g_list_length(scheduler->colocation_constraints));
     g_list_free_full(scheduler->colocation_constraints, free);
     scheduler->colocation_constraints = NULL;
 
     crm_trace("Deleting %d ticket constraints",
               g_list_length(scheduler->ticket_constraints));
     g_list_free_full(scheduler->ticket_constraints, free);
     scheduler->ticket_constraints = NULL;
 
     cleanup_calculations(scheduler);
 }
 
 void
 set_working_set_defaults(pcmk_scheduler_t *scheduler)
 {
     void *priv = scheduler->priv;
 
     memset(scheduler, 0, sizeof(pcmk_scheduler_t));
 
     scheduler->priv = priv;
     scheduler->order_id = 1;
     scheduler->action_id = 1;
     scheduler->no_quorum_policy = pcmk_no_quorum_stop;
 
     scheduler->flags = 0x0ULL;
 
     pcmk__set_scheduler_flags(scheduler,
                               pcmk_sched_symmetric_cluster
+#if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
+                              |pcmk_sched_concurrent_fencing
+#endif
                               |pcmk_sched_stop_removed_resources
                               |pcmk_sched_cancel_removed_actions);
-    if (!strcmp(PCMK__CONCURRENT_FENCING_DEFAULT, PCMK_VALUE_TRUE)) {
-        pcmk__set_scheduler_flags(scheduler, pcmk_sched_concurrent_fencing);
-    }
 }
 
 pcmk_resource_t *
 pe_find_resource(GList *rsc_list, const char *id)
 {
     return pe_find_resource_with_flags(rsc_list, id, pcmk_rsc_match_history);
 }
 
 pcmk_resource_t *
 pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
 {
     GList *rIter = NULL;
 
     for (rIter = rsc_list; id && rIter; rIter = rIter->next) {
         pcmk_resource_t *parent = rIter->data;
 
         pcmk_resource_t *match =
             parent->fns->find_rsc(parent, id, NULL, flags);
         if (match != NULL) {
             return match;
         }
     }
     crm_trace("No match for %s", id);
     return NULL;
 }
 
 /*!
  * \brief Find a node by name or ID in a list of nodes
  *
  * \param[in] nodes      List of nodes (as pcmk_node_t*)
  * \param[in] id         If not NULL, ID of node to find
  * \param[in] node_name  If not NULL, name of node to find
  *
  * \return Node from \p nodes that matches \p id if any,
  *         otherwise node from \p nodes that matches \p uname if any,
  *         otherwise NULL
  */
 pcmk_node_t *
 pe_find_node_any(const GList *nodes, const char *id, const char *uname)
 {
     pcmk_node_t *match = NULL;
 
     if (id != NULL) {
         match = pe_find_node_id(nodes, id);
     }
     if ((match == NULL) && (uname != NULL)) {
         match = pcmk__find_node_in_list(nodes, uname);
     }
     return match;
 }
 
 /*!
  * \brief Find a node by ID in a list of nodes
  *
  * \param[in] nodes  List of nodes (as pcmk_node_t*)
  * \param[in] id     ID of node to find
  *
  * \return Node from \p nodes that matches \p id if any, otherwise NULL
  */
 pcmk_node_t *
 pe_find_node_id(const GList *nodes, const char *id)
 {
     for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
         pcmk_node_t *node = (pcmk_node_t *) iter->data;
 
         /* @TODO Whether node IDs should be considered case-sensitive should
          * probably depend on the node type, so functionizing the comparison
          * would be worthwhile
          */
         if (pcmk__str_eq(node->details->id, id, pcmk__str_casei)) {
             return node;
         }
     }
     return NULL;
 }
 
 // Deprecated functions kept only for backward API compatibility
 // LCOV_EXCL_START
 
 #include <crm/pengine/status_compat.h>
 
 /*!
  * \brief Find a node by name in a list of nodes
  *
  * \param[in] nodes      List of nodes (as pcmk_node_t*)
  * \param[in] node_name  Name of node to find
  *
  * \return Node from \p nodes that matches \p node_name if any, otherwise NULL
  */
 pcmk_node_t *
 pe_find_node(const GList *nodes, const char *node_name)
 {
     return pcmk__find_node_in_list(nodes, node_name);
 }
 
 // LCOV_EXCL_STOP
 // End deprecated API
diff --git a/lib/pengine/tests/status/set_working_set_defaults_test.c b/lib/pengine/tests/status/set_working_set_defaults_test.c
index 546cd8aad0..2fea780ae3 100644
--- a/lib/pengine/tests/status/set_working_set_defaults_test.c
+++ b/lib/pengine/tests/status/set_working_set_defaults_test.c
@@ -1,50 +1,48 @@
 /*
  * Copyright 2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <crm/common/unittest_internal.h>
 
 #include <crm/common/scheduler.h>
 #include <crm/pengine/internal.h>
 #include <crm/pengine/status.h>
 
 #include "mock_private.h"
 
 static void
 check_defaults(void **state) {
     uint32_t flags;
     pcmk_scheduler_t *scheduler = pcmk__assert_alloc(1,
                                                      sizeof(pcmk_scheduler_t));
 
     set_working_set_defaults(scheduler);
 
     flags = pcmk_sched_symmetric_cluster
+#if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
+            |pcmk_sched_concurrent_fencing
+#endif
             |pcmk_sched_stop_removed_resources
             |pcmk_sched_cancel_removed_actions;
 
-    if (!strcmp(PCMK__CONCURRENT_FENCING_DEFAULT, PCMK_VALUE_TRUE)) {
-        flags |= pcmk_sched_concurrent_fencing;
-    }
-
-
     assert_null(scheduler->priv);
     assert_int_equal(scheduler->order_id, 1);
     assert_int_equal(scheduler->action_id, 1);
     assert_int_equal(scheduler->no_quorum_policy, pcmk_no_quorum_stop);
     assert_int_equal(scheduler->flags, flags);
 
     /* Avoid calling pe_free_working_set here so we don't artificially
      * inflate the coverage numbers.
      */
     free(scheduler);
 }
 
 PCMK__UNIT_TEST(NULL, NULL,
                 cmocka_unit_test(check_defaults))