Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/configure.ac b/configure.ac
index 6fadea4c9e..782b9e51f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,2154 +1,2153 @@
dnl
dnl autoconf for Pacemaker
dnl
dnl Copyright 2009-2025 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.28)
AS_IF([test x"${PKG_CONFIG}" != x""], [],
[AC_MSG_FAILURE([Could not find required build tool pkg-config (0.28 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 ==============================================
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 within Pacemaker
dnl @COMPAT This should be --with-systemd
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([deprecated-libs],
[AS_HELP_STRING([--enable-deprecated-libs],
[Build and install deprecated C libraries @<:@yes@:>@])]
)
yes_no_try "$enable_deprecated_libs" "yes"
enable_deprecated_libs=$?
AM_CONDITIONAL([BUILD_DEPRECATED_LIBS],
[test $enable_deprecated_libs -ne $DISABLED])
# 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 values
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 @COMPAT This should be --enable-cibsecrets option
AC_ARG_WITH([cibsecrets],
[AS_HELP_STRING([--with-cibsecrets],
[support separate file for CIB secrets @<:@no@:>@])]
)
yes_no_try "$with_cibsecrets" "no"
with_cibsecrets=$?
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], m4_normalize([
default value for concurrent-fencing cluster option (deprecated)
@<:@true@:>@]))],
)
AS_CASE([$with_concurrent_fencing_default],
[""], [with_concurrent_fencing_default="true"],
[true], [],
[false], [PCMK_FEATURES="$PCMK_FEATURES concurrent-fencing-default-false"],
[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" ]
)
dnl --with-* options: directory locations
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([PCMK_OCF_ROOT], [resource-agents], [ocfrootdir], [],
[PCMK_OCF_ROOT="/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@:>@]))],
[ PCMK_OCF_ROOT="$withval" ]
)
dnl Get default from resource-agents if possible
PKG_CHECK_VAR([PCMK__OCF_RA_PATH], [resource-agents], [ocfrapath], [],
[PCMK__OCF_RA_PATH="$PCMK_OCF_ROOT/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@:>@]))],
[ PCMK__OCF_RA_PATH="$withval" ]
)
OCF_RA_INSTALL_DIR="$PCMK_OCF_ROOT/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.6])
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(PCMK__VALGRIND_EXEC, valgrind, /usr/bin/valgrind)
AC_DEFINE_UNQUOTED(PCMK__VALGRIND_EXEC, "$PCMK__VALGRIND_EXEC", 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 x"$enable_nls" = x"yes"], [PCMK_FEATURES="$PCMK_FEATURES nls"])
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 PCMK_OCF_ROOT
AC_SUBST(PCMK_OCF_ROOT)
AC_DEFINE_UNQUOTED([PCMK_OCF_ROOT], ["$PCMK_OCF_ROOT"],
[OCF root directory for resource agents and libraries])
expand_path_option PCMK__OCF_RA_PATH
AC_SUBST(PCMK__OCF_RA_PATH)
AC_DEFINE_UNQUOTED([PCMK__OCF_RA_PATH], ["$PCMK__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
PCMK_SCHEMA_DIR="${datadir}/pacemaker"
AC_DEFINE_UNQUOTED([PCMK_SCHEMA_DIR], ["$PCMK_SCHEMA_DIR"],
[Location for the Pacemaker Relax-NG Schema])
AC_SUBST(PCMK_SCHEMA_DIR)
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)
PCMK__PERSISTENT_DATA_DIR="${localstatedir}/lib/pacemaker"
AC_DEFINE_UNQUOTED([PCMK__PERSISTENT_DATA_DIR], ["$PCMK__PERSISTENT_DATA_DIR"],
[Location to store directory produced by Pacemaker daemons])
AC_SUBST(PCMK__PERSISTENT_DATA_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)
PCMK_SCHEDULER_INPUT_DIR="${localstatedir}/lib/pacemaker/pengine"
AC_DEFINE_UNQUOTED([PCMK_SCHEDULER_INPUT_DIR], ["$PCMK_SCHEDULER_INPUT_DIR"],
[Where to keep scheduler outputs])
AC_SUBST(PCMK_SCHEDULER_INPUT_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)
PCMK__OCF_TMP_DIR="${runstatedir}/resource-agents"
AC_DEFINE_UNQUOTED([PCMK__OCF_TMP_DIR], ["$PCMK__OCF_TMP_DIR"],
[Where resource agents should keep state files])
AC_SUBST(PCMK__OCF_TMP_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)
# Fedora >=42 makes /usr/sbin a symlink to /usr/bin. It updates the RPM macros
# to set _sbindir to "${_exec_prefix}/bin", the same value as _bindir.
# Previously it was set to "${_exec_prefix}/sbin". (Note that because of the
# symlink, paths beginning with /usr/sbin remain valid.)
#
# This causes problems with bundle resources. Pacemaker automatically generates
# a configuration for the bundle's container resource. If the bundle contains a
# primitive and the container's run-command attribute is unset, the generated
# container resource has its run_cmd attribute set to
# SBIN_DIR "/" PCMK__SERVER_REMOTED, which is intended as a reasonable default.
# If SBIN_DIR becomes "/usr/bin" instead of "/usr/sbin", at least two problems
# can occur:
# 1. The container resource's digest changes compared to the digest in the
# resource history entry. Pacemaker interprets this as a configuration
# change and restarts the container resource.
# 2. If the container is running a different OS distro or an older version of
# Fedora, then the new /usr/bin/pacemaker-remoted path may be invalid; the
# executable was installed at /usr/sbin/pacemaker-remoted, which is NOT a
# symlink to /usr/bin path. In this case, the container fails to start.
#
# We override the value only for the SBIN_DIR constant, which is used only for
# the sbd path and the default pacemaker-remoted path. There is no need to
# override sbindir, which would affect installation directories.
#
# There is no more specific way than the below, to detect whether the build
# system has this /usr/sbin vs. /usr/bin change in effect. Thus corner cases are
# possible when sbindir/bindir are manually specified or in distros with
# atypical defaults.
#
# At time of writing, autoconf is unchanged. However, we perform the override
# here instead of in the spec file, in case autoconf changes in the future.
#
# Note that other distros (for example, RHEL) are likely to incorporate these
# changes in the future.
#
# References:
# * https://fedoraproject.org/wiki/Changes/Unify_bin_and_sbin
# * https://bodhi.fedoraproject.org/updates/FEDORA-2025-da0a082e66
# * https://discussion.fedoraproject.org/t/144562
AS_IF([test x"$sbindir" = x"$bindir" \
&& test x"$sbindir" = x"${exec_prefix}/bin"],
[SBIN_DIR="${exec_prefix}/sbin"],
[SBIN_DIR="$sbindir"])
AC_DEFINE_UNQUOTED([SBIN_DIR], ["$SBIN_DIR"], [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 SBIN_DIR
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_PROG([HELP2MAN], [help2man])
AC_PATH_PROG([SPHINX], [sphinx-build])
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([BUILD_SPHINX_DOCS], [test x"${SPHINX}" != 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_SEARCH_LIBS([socket], [socket])
save_LIBS="$LIBS"
DL_LIBS=""
LIBS=""
AC_SEARCH_LIBS([dlopen], [dl],
[test "$ac_cv_search_dlopen" = "none required" || DL_LIBS="$LIBS"])
AC_SUBST(DL_LIBS)
LIBS="$save_LIBS"
save_LIBS="$LIBS"
PAM_LIBS=""
LIBS=""
AC_SEARCH_LIBS([pam_start], [pam],
[test "$ac_cv_search_pam_start" = "none required" || PAM_LIBS="$LIBS"])
AC_SUBST(PAM_LIBS)
LIBS="$save_LIBS"
PKG_CHECK_MODULES([UUID], [uuid],
[CPPFLAGS="${CPPFLAGS} ${UUID_CFLAGS}"
LIBS="${LIBS} ${UUID_LIBS}"])
# 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])
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0 >= 2.9.2],
[CPPFLAGS="${CPPFLAGS} ${LIBXML2_CFLAGS}"
LIBS="${LIBS} ${LIBXML2_LIBS}"])
AC_PATH_PROGS(XMLLINT_PATH, xmllint, /usr/bin/xmllint)
AC_DEFINE_UNQUOTED(XMLLINT_PATH, "$XMLLINT_PATH", xmllint command)
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])
AS_IF([test x"$ac_cv_lib_pam_pam_start" = x"yes"],
AS_IF([test x"$ac_cv_header_security_pam_appl_h" = x"yes" dnl
|| test x"$ac_cv_header_pam_pam_appl_h" = x"yes"],
[PCMK_FEATURES="$PCMK_FEATURES pam"]))
# 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>]])
dnl ========================================================================
dnl Functions
dnl ========================================================================
REQUIRE_FUNC([alphasort])
REQUIRE_FUNC([getopt])
REQUIRE_FUNC([scandir])
REQUIRE_FUNC([sched_getscheduler])
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])
save_LIBS="$LIBS"
found_curses=0
CURSES_LIBS=""
LIBS=""
AC_SEARCH_LIBS([printw], [ncurses curses],
[test "$ac_cv_search_printw" = "none required" || CURSES_LIBS="$LIBS"
found_curses=1],
[found_curses=0])
LIBS="$save_LIBS"
dnl Check for printw() prototype compatibility
AS_IF([test $found_curses -eq 1 && cc_supports_flag -Wcast-qual], [
ac_save_LIBS="$LIBS"
LIBS="$CURSES_LIBS"
# 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>
#elif defined(HAVE_CURSES_CURSES_H)
# include <curses/curses.h>
#endif
],
[printw((const char *)"Test");]
)],
[AC_MSG_RESULT([yes])
PCMK_FEATURES="$PCMK_FEATURES ncurses"
],
[
found_curses=0
CURSES_LIBS=""
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/)
]))
]
)
LIBS="$ac_save_LIBS"
cc_restore_flags
])
AC_DEFINE_UNQUOTED([PCMK__ENABLE_CURSES], [$found_curses], [have ncurses library])
AC_SUBST(CURSES_LIBS)
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])
]
)
AM_CONDITIONAL([BUILD_PROFILING], [test "$with_profiling" = "$REQUIRED"])
dnl ========================================================================
dnl Cluster infrastructure - LibQB
dnl ========================================================================
PKG_CHECK_MODULES([libqb], [libqb >= 1.0.1])
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)
dnl also defines QB_FEATURE_LOG_HIRES_TIMESTAMPS
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],
[
save_LIBS="$LIBS"
STONITH_LIBS=""
LIBS=""
AC_SEARCH_LIBS([PILLoadPlugin], [pils],
[test "$ac_cv_search_PILLoadPlugin" = "none required" || STONITH_LIBS="$LIBS"])
LIBS=""
AC_SEARCH_LIBS([G_main_add_IPC_Channel], [plumb],
[test "$ac_cv_search_G_main_add_IPC_Channel" = "none required" || STONITH_LIBS="$STONITH_LIBS $LIBS"])
AC_SUBST(STONITH_LIBS)
LIBS="$save_LIBS"
PCMK_FEATURES="$PCMK_FEATURES lha"
])
AM_CONDITIONAL([BUILD_LHA_SUPPORT], [test x"$ac_cv_header_stonith_stonith_h" = x"yes"])
dnl ===============================
dnl Detect DBus and systemd support
dnl ===============================
HAVE_dbus=0
PC_NAME_DBUS=""
PKG_CHECK_MODULES([DBUS],[dbus-1 >= 1.5.12],
[
HAVE_dbus=1
PC_NAME_DBUS="dbus-1"
CPPFLAGS="${CPPFLAGS} ${DBUS_CFLAGS}"
],[])
AC_DEFINE_UNQUOTED(HAVE_DBUS, $HAVE_dbus, Support dbus)
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)
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])
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"
PCMK__CIB_SECRETS_DIR="${localstatedir}/lib/pacemaker/lrm/secrets"
AC_DEFINE_UNQUOTED([PCMK__CIB_SECRETS_DIR], ["$PCMK__CIB_SECRETS_DIR"],
[Location for CIB secrets])
AC_SUBST([PCMK__CIB_SECRETS_DIR])
]
)
AC_DEFINE_UNQUOTED([PCMK__ENABLE_CIBSECRETS], [$with_cibsecrets], [Support CIB secrets])
AM_CONDITIONAL([BUILD_CIBSECRETS], [test $with_cibsecrets -eq $REQUIRED])
dnl ========================================================================
dnl GnuTLS
dnl ========================================================================
PKG_CHECK_MODULES(GNUTLS, [gnutls >= 3.4.6],
[CPPFLAGS="${CPPFLAGS} ${GNUTLS_CFLAGS}"
LIBS="${LIBS} ${GNUTLS_LIBS}"])
# --- 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/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-regression],
[cts/cts-scheduler],
[cts/cts-schemas],
[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.service \
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/digest/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/messages/Makefile \
lib/common/tests/nodes/Makefile \
lib/common/tests/nvpair/Makefile \
lib/common/tests/options/Makefile \
lib/common/tests/output/Makefile \
lib/common/tests/patchset/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/xml_comment/Makefile \
lib/common/tests/xml_element/Makefile \
lib/common/tests/xml_idref/Makefile \
lib/common/tests/xpath/Makefile \
lib/fencing/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/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 = ${PCMK_OCF_ROOT}])
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/include/crm/common/unittest_internal.h b/include/crm/common/unittest_internal.h
index 2283389080..d8d3297c84 100644
--- a/include/crm/common/unittest_internal.h
+++ b/include/crm/common/unittest_internal.h
@@ -1,218 +1,217 @@
/*
- * Copyright 2022-2024 the Pacemaker project contributors
+ * Copyright 2022-2025 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 PCMK__CRM_COMMON_UNITTEST_INTERNAL__H
#define PCMK__CRM_COMMON_UNITTEST_INTERNAL__H
#include <signal.h>
#include <stdarg.h>
-#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cmocka.h>
#include <crm/common/xml.h>
#ifdef __cplusplus
extern "C" {
#endif
/* internal unit testing related utilities */
#if (PCMK__WITH_COVERAGE == 1)
/* This function isn't exposed anywhere. The following prototype was taken from
* /usr/lib/gcc/x86_64-redhat-linux/??/include/gcov.h
*/
extern void __gcov_dump(void);
#else
#define __gcov_dump()
#endif
/*!
* \internal
* \brief Assert that the XML output from an API function is valid
*
* \param[in] xml The XML output of some public pacemaker API function
*
* Run the given XML through xmllint and attempt to validate it against the
* api-result.rng schema file. Assert if validation fails.
*
* \note PCMK_schema_directory needs to be set to the directory containing
* the built schema files before calling this function. Typically,
* this will be done in Makefile.am.
*/
void pcmk__assert_validates(xmlNode *xml);
/*!
* \internal
* \brief Perform setup for a group of unit tests that will manipulate XML
*
* This function is suitable for being passed as the first argument to the
* \c PCMK__UNIT_TEST macro.
*
* \param[in] state The cmocka state object, currently unused by this
* function
*/
int pcmk__xml_test_setup_group(void **state);
int pcmk__xml_test_teardown_group(void **state);
/*!
* \internal
* \brief Copy the given CIB file to a temporary file so it can be modified
* as part of doing unit tests, returning the full temporary file or
* \c NULL on error.
*
* This function should be called as part of the process of setting up any
* single unit test that would access and modify a CIB. That is, it should
* be called from whatever function is the second argument to
* cmocka_unit_test_setup_teardown.
*
* \param[in] in_file The filename of the input CIB file, which must
* exist in the \c $PCMK_CTS_CLI_DIR directory. This
* should only be the filename, not the complete
* path.
*/
char *pcmk__cib_test_copy_cib(const char *in_file);
/*!
* \internal
* \brief Clean up whatever was done by a previous call to
* \c pcmk__cib_test_copy_cib.
*
* This function should be called as part of the process of tearing down
* any single unit test that accessed a CIB. That is, it should be called
* from whatever function is the third argument to
* \c cmocka_unit_test_setup_teardown.
*
* \param[in] out_path The complete path to the temporary CIB location.
* This is the return value of
* \c pcmk__cib_test_copy_cib.
*/
void pcmk__cib_test_cleanup(char *out_path);
void pcmk__test_init_logging(const char *name, const char *filename);
/*!
* \internal
* \brief Assert that a statement aborts through pcmk__assert().
*
* \param[in] stmt Statement to execute; can be an expression.
*
* A cmocka-like assert macro for use in unit testing. This one verifies that a
* statement aborts through pcmk__assert(), erroring out if that is not the
* case.
*
* This macro works by running the statement in a forked child process with core
* dumps disabled (pcmk__assert() calls \c abort(), which will write out a core
* dump). The parent waits for the child to exit and checks why. If the child
* received a \c SIGABRT, the test passes. For all other cases, the test fails.
*
* \note If cmocka's expect_*() or will_return() macros are called along with
* pcmk__assert_asserts(), they must be called within a block that is
* passed as the \c stmt argument. That way, the values are added only to
* the child's queue. Otherwise, values added to the parent's queue will
* never be popped, and the test will fail.
*/
#define pcmk__assert_asserts(stmt) \
do { \
pid_t p = fork(); \
if (p == 0) { \
struct rlimit cores = { 0, 0 }; \
setrlimit(RLIMIT_CORE, &cores); \
stmt; \
__gcov_dump(); \
_exit(0); \
} else if (p > 0) { \
int wstatus = 0; \
if (waitpid(p, &wstatus, 0) == -1) { \
fail_msg("waitpid failed"); \
} \
if (!(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)) { \
fail_msg("statement terminated in child without asserting"); \
} \
} else { \
fail_msg("unable to fork for assert test"); \
} \
} while (0);
/*!
* \internal
* \brief Assert that a statement aborts
*
* This is exactly the same as pcmk__assert_asserts (pcmk__assert() is
* implemented with abort()), but given a different name for clarity.
*/
#define pcmk__assert_aborts(stmt) pcmk__assert_asserts(stmt)
/*!
* \internal
* \brief Assert that a statement exits with the expected exit status.
*
* \param[in] stmt Statement to execute; can be an expression.
* \param[in] rc The expected exit status.
*
* This functions just like \c pcmk__assert_asserts, except that it tests for
* an expected exit status. Abnormal termination or incorrect exit status is
* treated as a failure of the test.
*
* In the event that stmt does not exit at all, the special code \c CRM_EX_NONE
* will be returned. It is expected that this code is not used anywhere, thus
* always causing an error.
*/
#define pcmk__assert_exits(rc, stmt) \
do { \
pid_t p = fork(); \
if (p == 0) { \
struct rlimit cores = { 0, 0 }; \
setrlimit(RLIMIT_CORE, &cores); \
stmt; \
__gcov_dump(); \
_exit(CRM_EX_NONE); \
} else if (p > 0) { \
int wstatus = 0; \
if (waitpid(p, &wstatus, 0) == -1) { \
fail_msg("waitpid failed"); \
} \
if (!WIFEXITED(wstatus)) { \
fail_msg("statement terminated abnormally"); \
} else if (WEXITSTATUS(wstatus) != rc) { \
fail_msg("statement exited with %d, not expected %d", WEXITSTATUS(wstatus), rc); \
} \
} else { \
fail_msg("unable to fork for assert test"); \
} \
} while (0);
/* Generate the main function of most unit test files. Typically, group_setup
* and group_teardown will be NULL. The rest of the arguments are a list of
* calls to cmocka_unit_test or cmocka_unit_test_setup_teardown to run the
* individual unit tests.
*/
#define PCMK__UNIT_TEST(group_setup, group_teardown, ...) \
int \
main(int argc, char **argv) \
{ \
const struct CMUnitTest t[] = { \
__VA_ARGS__ \
}; \
cmocka_set_message_output(CM_OUTPUT_TAP); \
return cmocka_run_group_tests(t, group_setup, group_teardown); \
}
#ifdef __cplusplus
}
#endif
#endif // PCMK__CRM_COMMON_UNITTEST_INTERNAL__H
diff --git a/lib/common/mock.c b/lib/common/mock.c
index 43c6e8fb52..08f025b1dd 100644
--- a/lib/common/mock.c
+++ b/lib/common/mock.c
@@ -1,462 +1,461 @@
/*
- * Copyright 2021-2024 the Pacemaker project contributors
+ * Copyright 2021-2025 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 <errno.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
-#include <sys/types.h>
+#include <sys/types.h> // pid_t, size_t
#include <sys/utsname.h>
#include <unistd.h>
#include <grp.h>
#include <cmocka.h>
#include <crm/common/unittest_internal.h>
#include "mock_private.h"
/* This file is only used when running "make check". It is built into
* libcrmcommon_test.a, not into libcrmcommon.so. It is used to support
* constructing mock versions of library functions for unit testing.
*
* HOW TO ADD A MOCKED FUNCTION:
*
* - In this file, declare a bool pcmk__mock_X variable, and define a __wrap_X
* function with the same prototype as the actual function that performs the
* desired behavior if pcmk__mock_X is true and calls __real_X otherwise.
* You can use cmocka's mock_type() and mock_ptr_type() to pass extra
* information to the mocked function (see existing examples for details).
*
* - In mock_private.h, add declarations for extern bool pcmk__mock_X and the
* __real_X and __wrap_X function prototypes.
*
* - In mk/tap.mk, add the function name to the WRAPPED variable.
*
* HOW TO USE A MOCKED FUNCTION:
*
* - #include "mock_private.h" in your test file.
*
* - Write your test cases using pcmk__mock_X and cmocka's will_return() as
* needed per the comments for the mocked function below. See existing test
* cases for examples.
*/
// LCOV_EXCL_START
/* abort()
*
* Always mock abort - there's no pcmk__mock_abort tuneable to control this.
* Because abort calls _exit(), which doesn't run any of the things registered
* with atexit(), coverage numbers do not get written out. This most noticably
* affects places where we are testing that things abort when they should.
*
* The solution is this wrapper that is always enabled when we are running
* unit tests (mock.c does not get included for the regular libcrmcommon.so).
* All it does is dump coverage data and call the real abort().
*/
_Noreturn void
__wrap_abort(void)
{
#if (PCMK__WITH_COVERAGE == 1)
__gcov_dump();
#endif
__real_abort();
}
/* calloc()
*
* If pcmk__mock_calloc is set to true, later calls to calloc() will return
* NULL and must be preceded by:
*
* expect_*(__wrap_calloc, nmemb[, ...]);
* expect_*(__wrap_calloc, size[, ...]);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*/
bool pcmk__mock_calloc = false;
void *
__wrap_calloc(size_t nmemb, size_t size)
{
if (!pcmk__mock_calloc) {
return __real_calloc(nmemb, size);
}
check_expected(nmemb);
check_expected(size);
return NULL;
}
/* getenv()
*
* If pcmk__mock_getenv is set to true, later calls to getenv() must be preceded
* by:
*
* expect_*(__wrap_getenv, name[, ...]);
* will_return(__wrap_getenv, return_value);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*/
bool pcmk__mock_getenv = false;
char *
__wrap_getenv(const char *name)
{
if (!pcmk__mock_getenv) {
return __real_getenv(name);
}
check_expected_ptr(name);
return mock_ptr_type(char *);
}
/* realloc()
*
* If pcmk__mock_realloc is set to true, later calls to realloc() will return
* NULL and must be preceded by:
*
* expect_*(__wrap_realloc, ptr[, ...]);
* expect_*(__wrap_realloc, size[, ...]);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*/
bool pcmk__mock_realloc = false;
void *
__wrap_realloc(void *ptr, size_t size)
{
if (!pcmk__mock_realloc) {
return __real_realloc(ptr, size);
}
check_expected_ptr(ptr);
check_expected(size);
return NULL;
}
/* setenv()
*
* If pcmk__mock_setenv is set to true, later calls to setenv() must be preceded
* by:
*
* expect_*(__wrap_setenv, name[, ...]);
* expect_*(__wrap_setenv, value[, ...]);
* expect_*(__wrap_setenv, overwrite[, ...]);
* will_return(__wrap_setenv, errno_to_set);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*
* The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
*/
bool pcmk__mock_setenv = false;
int
__wrap_setenv(const char *name, const char *value, int overwrite)
{
if (!pcmk__mock_setenv) {
return __real_setenv(name, value, overwrite);
}
check_expected_ptr(name);
check_expected_ptr(value);
check_expected(overwrite);
errno = mock_type(int);
return (errno == 0)? 0 : -1;
}
/* unsetenv()
*
* If pcmk__mock_unsetenv is set to true, later calls to unsetenv() must be
* preceded by:
*
* expect_*(__wrap_unsetenv, name[, ...]);
* will_return(__wrap_setenv, errno_to_set);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*
* The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
*/
bool pcmk__mock_unsetenv = false;
int
__wrap_unsetenv(const char *name)
{
if (!pcmk__mock_unsetenv) {
return __real_unsetenv(name);
}
check_expected_ptr(name);
errno = mock_type(int);
return (errno == 0)? 0 : -1;
}
/* getpid()
*
* If pcmk__mock_getpid is set to true, later calls to getpid() must be preceded
* by:
*
* will_return(__wrap_getpid, return_value);
*/
bool pcmk__mock_getpid = false;
pid_t
__wrap_getpid(void)
{
return pcmk__mock_getpid? mock_type(pid_t) : __real_getpid();
}
/* setgrent(), getgrent() and endgrent()
*
* If pcmk__mock_grent is set to true, getgrent() will behave as if the only
* groups on the system are:
*
* - grp0 (user0, user1)
* - grp1 (user1)
* - grp2 (user2, user1)
*/
bool pcmk__mock_grent = false;
// Index of group that will be returned next from getgrent()
static int group_idx = 0;
// Data used for testing
static const char* grp0_members[] = {
"user0", "user1", NULL
};
static const char* grp1_members[] = {
"user1", NULL
};
static const char* grp2_members[] = {
"user2", "user1", NULL
};
/* An array of "groups" (a struct from grp.h)
*
* The members of the groups are initalized here to some testing data, casting
* away the consts to make the compiler happy and simplify initialization. We
* never actually change these variables during the test!
*
* string literal = const char* (cannot be changed b/c ? )
* vs. char* (it's getting casted to this)
*/
static const int NUM_GROUPS = 3;
static struct group groups[] = {
{(char*)"grp0", (char*)"", 0, (char**)grp0_members},
{(char*)"grp1", (char*)"", 1, (char**)grp1_members},
{(char*)"grp2", (char*)"", 2, (char**)grp2_members},
};
// This function resets the group_idx to 0.
void
__wrap_setgrent(void) {
if (pcmk__mock_grent) {
group_idx = 0;
} else {
__real_setgrent();
}
}
/* This function returns the next group entry in the list of groups, or
* NULL if there aren't any left.
* group_idx is a global variable which keeps track of where you are in the list
*/
struct group *
__wrap_getgrent(void) {
if (pcmk__mock_grent) {
if (group_idx >= NUM_GROUPS) {
return NULL;
}
return &groups[group_idx++];
} else {
return __real_getgrent();
}
}
void
__wrap_endgrent(void) {
if (!pcmk__mock_grent) {
__real_endgrent();
}
}
/* fopen()
*
* If pcmk__mock_fopen is set to true, later calls to fopen() must be
* preceded by:
*
* expect_*(__wrap_fopen, pathname[, ...]);
* expect_*(__wrap_fopen, mode[, ...]);
* will_return(__wrap_fopen, errno_to_set);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*
* This has two mocked functions, since fopen() is sometimes actually fopen64().
*/
bool pcmk__mock_fopen = false;
FILE *
__wrap_fopen(const char *pathname, const char *mode)
{
if (pcmk__mock_fopen) {
check_expected_ptr(pathname);
check_expected_ptr(mode);
errno = mock_type(int);
if (errno != 0) {
return NULL;
} else {
return __real_fopen(pathname, mode);
}
} else {
return __real_fopen(pathname, mode);
}
}
#ifdef HAVE_FOPEN64
FILE *
__wrap_fopen64(const char *pathname, const char *mode)
{
if (pcmk__mock_fopen) {
check_expected_ptr(pathname);
check_expected_ptr(mode);
errno = mock_type(int);
if (errno != 0) {
return NULL;
} else {
return __real_fopen64(pathname, mode);
}
} else {
return __real_fopen64(pathname, mode);
}
}
#endif
/* getpwnam_r()
*
* If pcmk__mock_getpwnam_r is set to true, later calls to getpwnam_r() must be
* preceded by:
*
* expect_*(__wrap_getpwnam_r, name[, ...]);
* expect_*(__wrap_getpwnam_r, pwd[, ...]);
* expect_*(__wrap_getpwnam_r, buf[, ...]);
* expect_*(__wrap_getpwnam_r, buflen[, ...]);
* expect_*(__wrap_getpwnam_r, result[, ...]);
* will_return(__wrap_getpwnam_r, return_value);
* will_return(__wrap_getpwnam_r, ptr_to_result_struct);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*/
bool pcmk__mock_getpwnam_r = false;
int
__wrap_getpwnam_r(const char *name, struct passwd *pwd, char *buf,
size_t buflen, struct passwd **result)
{
if (pcmk__mock_getpwnam_r) {
int retval = mock_type(int);
check_expected_ptr(name);
check_expected_ptr(pwd);
check_expected_ptr(buf);
check_expected(buflen);
check_expected_ptr(result);
*result = mock_ptr_type(struct passwd *);
return retval;
} else {
return __real_getpwnam_r(name, pwd, buf, buflen, result);
}
}
/*
* If pcmk__mock_readlink is set to true, later calls to readlink() must be
* preceded by:
*
* expect_*(__wrap_readlink, path[, ...]);
* expect_*(__wrap_readlink, buf[, ...]);
* expect_*(__wrap_readlink, bufsize[, ...]);
* will_return(__wrap_readlink, errno_to_set);
* will_return(__wrap_readlink, link_contents);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*
* The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
*/
bool pcmk__mock_readlink = false;
ssize_t
__wrap_readlink(const char *restrict path, char *restrict buf,
size_t bufsize)
{
if (pcmk__mock_readlink) {
const char *contents = NULL;
check_expected_ptr(path);
check_expected_ptr(buf);
check_expected(bufsize);
errno = mock_type(int);
contents = mock_ptr_type(const char *);
if (errno == 0) {
strncpy(buf, contents, bufsize - 1);
return strlen(contents);
}
return -1;
} else {
return __real_readlink(path, buf, bufsize);
}
}
/* strdup()
*
* If pcmk__mock_strdup is set to true, later calls to strdup() will return
* NULL and must be preceded by:
*
* expect_*(__wrap_strdup, s[, ...]);
*
* expect_* functions: https://api.cmocka.org/group__cmocka__param.html
*/
bool pcmk__mock_strdup = false;
char *
__wrap_strdup(const char *s)
{
if (!pcmk__mock_strdup) {
return __real_strdup(s);
}
check_expected_ptr(s);
return NULL;
}
// LCOV_EXCL_STOP
diff --git a/lib/pacemaker/pcmk_status.c b/lib/pacemaker/pcmk_status.c
index e111456279..6fc1af7a11 100644
--- a/lib/pacemaker/pcmk_status.c
+++ b/lib/pacemaker/pcmk_status.c
@@ -1,283 +1,282 @@
/*
- * Copyright 2004-2024 the Pacemaker project contributors
+ * Copyright 2004-2025 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 <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
#include <crm/cib/internal.h>
#include <crm/common/output.h>
#include <crm/common/results.h>
#include <crm/fencing/internal.h>
#include <crm/pengine/internal.h>
#include <crm/stonith-ng.h> // stonith__register_messages()
#include <pacemaker.h>
#include <pacemaker-internal.h>
static stonith_t *
fencing_connect(void)
{
stonith_t *st = stonith_api_new();
int rc = pcmk_rc_ok;
if (st == NULL) {
return NULL;
}
rc = st->cmds->connect(st, crm_system_name, NULL);
if (rc == pcmk_rc_ok) {
return st;
} else {
stonith_api_delete(st);
return NULL;
}
}
/*!
* \internal
* \brief Output the cluster status given a fencer and CIB connection
*
* \param[in,out] scheduler Scheduler object (will be reset)
* \param[in,out] stonith Fencer connection
* \param[in,out] cib CIB connection
* \param[in] current_cib Current CIB XML
* \param[in] pcmkd_state \p pacemakerd state
* \param[in] fence_history How much of the fencing history to output
* \param[in] show Group of \p pcmk_section_e flags
* \param[in] show_opts Group of \p pcmk_show_opt_e flags
* \param[in] only_node If a node name or tag, include only the
* matching node(s) (if any) in the output.
* If \p "*" or \p NULL, include all nodes
* in the output.
* \param[in] only_rsc If a resource ID or tag, include only the
* matching resource(s) (if any) in the
* output. If \p "*" or \p NULL, include all
* resources in the output.
* \param[in] neg_location_prefix Prefix denoting a ban in a constraint ID
*
* \return Standard Pacemaker return code
*/
int
pcmk__output_cluster_status(pcmk_scheduler_t *scheduler, stonith_t *stonith,
cib_t *cib, xmlNode *current_cib,
enum pcmk_pacemakerd_state pcmkd_state,
enum pcmk__fence_history fence_history,
uint32_t show, uint32_t show_opts,
const char *only_node, const char *only_rsc,
const char *neg_location_prefix)
{
xmlNode *cib_copy = pcmk__xml_copy(NULL, current_cib);
stonith_history_t *stonith_history = NULL;
int history_rc = 0;
GList *unames = NULL;
GList *resources = NULL;
pcmk__output_t *out = NULL;
int rc = pcmk_rc_ok;
if ((scheduler == NULL) || (scheduler->priv->out == NULL)) {
return EINVAL;
}
out = scheduler->priv->out;
rc = pcmk__update_configured_schema(&cib_copy, false);
if (rc != pcmk_rc_ok) {
cib__clean_up_connection(&cib);
pcmk__xml_free(cib_copy);
out->err(out, "Upgrade failed: %s", pcmk_rc_str(rc));
return rc;
}
/* get the stonith-history if there is evidence we need it */
if (fence_history != pcmk__fence_history_none) {
history_rc = pcmk__get_fencing_history(stonith, &stonith_history,
fence_history);
}
pcmk_reset_scheduler(scheduler);
scheduler->input = cib_copy;
cluster_status(scheduler);
/* Unpack constraints if any section will need them
* (tickets may be referenced in constraints but not granted yet,
* and bans need negative location constraints) */
if (pcmk_is_set(show, pcmk_section_bans)
|| pcmk_is_set(show, pcmk_section_tickets)) {
pcmk__unpack_constraints(scheduler);
}
unames = pe__build_node_name_list(scheduler, only_node);
resources = pe__build_rsc_list(scheduler, only_rsc);
/* Always print DC if NULL. */
if (scheduler->dc_node == NULL) {
show |= pcmk_section_dc;
}
out->message(out, "cluster-status",
scheduler, pcmkd_state, pcmk_rc2exitc(history_rc),
stonith_history, fence_history, show, show_opts,
neg_location_prefix, unames, resources);
g_list_free_full(unames, free);
g_list_free_full(resources, free);
stonith_history_free(stonith_history);
stonith_history = NULL;
return rc;
}
int
pcmk_status(xmlNodePtr *xml)
{
cib_t *cib = NULL;
pcmk__output_t *out = NULL;
int rc = pcmk_rc_ok;
uint32_t show_opts = pcmk_show_pending
|pcmk_show_inactive_rscs
|pcmk_show_timing;
cib = cib_new();
if (cib == NULL) {
return pcmk_rc_cib_corrupt;
}
rc = pcmk__xml_output_new(&out, xml);
if (rc != pcmk_rc_ok) {
cib_delete(cib);
return rc;
}
pcmk__register_lib_messages(out);
pe__register_messages(out);
stonith__register_messages(out);
rc = pcmk__status(out, cib, pcmk__fence_history_full, pcmk_section_all,
show_opts, NULL, NULL, NULL, 0);
pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
cib_delete(cib);
return rc;
}
/*!
* \internal
* \brief Query and output the cluster status
*
* The operation is considered a success if we're able to get the \p pacemakerd
* state. If possible, we'll also try to connect to the fencer and CIB and
* output their respective status information.
*
* \param[in,out] out Output object
* \param[in,out] cib CIB connection
* \param[in] fence_history How much of the fencing history to output
* \param[in] show Group of \p pcmk_section_e flags
* \param[in] show_opts Group of \p pcmk_show_opt_e flags
* \param[in] only_node If a node name or tag, include only the
* matching node(s) (if any) in the output.
* If \p "*" or \p NULL, include all nodes
* in the output.
* \param[in] only_rsc If a resource ID or tag, include only the
* matching resource(s) (if any) in the
* output. If \p "*" or \p NULL, include all
* resources in the output.
* \param[in] neg_location_prefix Prefix denoting a ban in a constraint ID
* \param[in] timeout_ms How long to wait for a reply from the
* \p pacemakerd API. If 0,
* \p pcmk_ipc_dispatch_sync will be used.
* If positive, \p pcmk_ipc_dispatch_main
* will be used, and a new mainloop will be
* created for this purpose (freed before
* return).
*
* \return Standard Pacemaker return code
*/
int
pcmk__status(pcmk__output_t *out, cib_t *cib,
enum pcmk__fence_history fence_history, uint32_t show,
uint32_t show_opts, const char *only_node, const char *only_rsc,
const char *neg_location_prefix, unsigned int timeout_ms)
{
xmlNode *current_cib = NULL;
int rc = pcmk_rc_ok;
stonith_t *stonith = NULL;
enum pcmk_pacemakerd_state pcmkd_state = pcmk_pacemakerd_state_invalid;
time_t last_updated = 0;
pcmk_scheduler_t *scheduler = NULL;
if (cib == NULL) {
return ENOTCONN;
}
if (cib->variant == cib_native) {
rc = pcmk__pacemakerd_status(out, crm_system_name, timeout_ms, false,
&pcmkd_state);
if (rc != pcmk_rc_ok) {
return rc;
}
last_updated = time(NULL);
switch (pcmkd_state) {
case pcmk_pacemakerd_state_running:
case pcmk_pacemakerd_state_shutting_down:
case pcmk_pacemakerd_state_remote:
/* Fencer and CIB may still be available while shutting down or
* running on a Pacemaker Remote node
*/
break;
default:
// Fencer and CIB are definitely unavailable
out->message(out, "pacemakerd-health",
NULL, pcmkd_state, NULL, last_updated);
return rc;
}
if (fence_history != pcmk__fence_history_none) {
stonith = fencing_connect();
}
}
rc = cib__signon_query(out, &cib, &current_cib);
if (rc != pcmk_rc_ok) {
if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
// Invalid at this point means we didn't query the pcmkd state
out->message(out, "pacemakerd-health",
NULL, pcmkd_state, NULL, last_updated);
}
goto done;
}
scheduler = pcmk_new_scheduler();
pcmk__mem_assert(scheduler);
scheduler->priv->out = out;
if ((cib->variant == cib_native) && pcmk_is_set(show, pcmk_section_times)) {
// Currently used only in the times section
pcmk__query_node_name(out, 0, &(scheduler->priv->local_node_name), 0);
}
rc = pcmk__output_cluster_status(scheduler, stonith, cib, current_cib,
pcmkd_state, fence_history, show,
show_opts, only_node, only_rsc,
neg_location_prefix);
if (rc != pcmk_rc_ok) {
out->err(out, "Error outputting status info from the fencer or CIB");
}
done:
pcmk_free_scheduler(scheduler);
stonith_api_delete(stonith);
pcmk__xml_free(current_cib);
return pcmk_rc_ok;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 3:33 AM (6 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009947
Default Alt Text
(116 KB)

Event Timeline