diff --git a/configure.ac b/configure.ac index f7093175b6..bf9ffa7676 100644 --- a/configure.ac +++ b/configure.ac @@ -1,1723 +1,1727 @@ dnl dnl autoconf for Pacemaker dnl dnl License: GNU General Public License (GPL) dnl =============================================== dnl Bootstrap dnl =============================================== AC_PREREQ(2.59) dnl Suggested structure: dnl information on the package dnl checks for programs dnl checks for libraries dnl checks for header files dnl checks for types dnl checks for structures dnl checks for compiler characteristics dnl checks for library functions dnl checks for system services AC_INIT(pacemaker, 1.1.7, pacemaker@oss.clusterlabs.org) CRM_DTD_VERSION="1.2" PCMK_FEATURES="" HB_PKG=heartbeat AC_CONFIG_AUX_DIR(.) AC_CANONICAL_HOST dnl Where #defines go (e.g. `AC_CHECK_HEADERS' below) dnl dnl Internal header: include/config.h dnl - Contains ALL defines dnl - include/config.h.in is generated automatically by autoheader dnl - NOT to be included in any header files except lha_internal.h dnl (which is also not to be included in any other header files) dnl dnl External header: include/crm_config.h dnl - Contains a subset of defines checked here dnl - Manually edit include/crm_config.h.in to have configure include dnl new defines dnl - Should not include HAVE_* defines dnl - Safe to include anywhere AM_CONFIG_HEADER(include/config.h include/crm_config.h) ALL_LINGUAS="en fr" AC_ARG_WITH(version, [ --with-version=version Override package version (if you're a packager needing to pretend) ], [ PACKAGE_VERSION="$withval" ]) AC_ARG_WITH(pkg-name, [ --with-pkg-name=name Override package name (if you're a packager needing to pretend) ], [ PACKAGE_NAME="$withval" ]) AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION) AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$PACKAGE_VERSION", Current pacemaker version) PACKAGE_SERIES=`echo $PACKAGE_VERSION | awk -F. '{ print $1"."$2 }'` AC_SUBST(PACKAGE_SERIES) AC_SUBST(PACKAGE_VERSION) dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from dnl normal compilation. When a failure occurs, it will then display the full dnl command line dnl Wrap in m4_ifdef to avoid breaking on older platforms m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) dnl Example 2.4. Silent Custom Rule to Generate a File dnl %-bar.pc: %.pc dnl $(AM_V_GEN)$(LN_S) $(notdir $^) $@ CC_IN_CONFIGURE=yes export CC_IN_CONFIGURE LDD=ldd dnl ======================================================================== dnl Compiler characteristics dnl ======================================================================== AC_PROG_CC dnl Can force other with environment variable "CC". AM_PROG_CC_C_O AC_PROG_CC_STDC gl_EARLY gl_INIT AC_LIBTOOL_DLOPEN dnl Enable dlopen support... AC_LIBLTDL_CONVENIENCE dnl make libltdl a convenience lib AC_PROG_LIBTOOL AC_PROG_YACC AM_PROG_LEX AC_C_STRINGIZE AC_TYPE_SIZE_T AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_STRUCT_TIMEZONE dnl =============================================== dnl Helpers dnl =============================================== cc_supports_flag() { local CFLAGS="$@" 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 } try_extract_header_define() { AC_MSG_CHECKING(if $2 in $1 exists. If not defaulting to $3) Cfile=$srcdir/extract_define.$2.${$} printf "#include \n" > ${Cfile}.c printf "#include <%s>\n" $1 >> ${Cfile}.c printf "int main(int argc, char **argv) {\n" >> ${Cfile}.c printf "#ifdef %s\n" $2 >> ${Cfile}.c printf "printf(\"%%s\", %s);\n" $2 >> ${Cfile}.c printf "#endif \n return 0; }\n" >> ${Cfile}.c $CC $CFLAGS ${Cfile}.c -o ${Cfile} value=`${Cfile}` if test x"${value}" == x""; then value=$3 fi AC_MSG_RESULT($value) printf $value rm -rf ${Cfile}.c ${Cfile} ${Cfile}.dSYM ${Cfile}.gcno } extract_header_define() { AC_MSG_CHECKING(for $2 in $1) Cfile=$srcdir/extract_define.$2.${$} printf "#include \n" > ${Cfile}.c printf "#include <%s>\n" $1 >> ${Cfile}.c printf "int main(int argc, char **argv) { printf(\"%%s\", %s); return 0; }\n" $2 >> ${Cfile}.c $CC $CFLAGS ${Cfile}.c -o ${Cfile} value=`${Cfile}` AC_MSG_RESULT($value) printf $value rm -rf ${Cfile}.c ${Cfile} ${Cfile}.dSYM ${Cfile}.gcno } dnl =============================================== dnl Configure Options dnl =============================================== dnl Some systems, like Solaris require a custom package name AC_ARG_WITH(pkgname, [ --with-pkgname=name name for pkg (typically for Solaris) ], [ PKGNAME="$withval" ], [ PKGNAME="LXHAhb" ], ) AC_SUBST(PKGNAME) AC_ARG_ENABLE([ansi], [ --enable-ansi force GCC to compile to ANSI/ANSI standard for older compilers. [default=no]]) AC_ARG_ENABLE([fatal-warnings], [ --enable-fatal-warnings very pedantic and fatal warnings for gcc [default=yes]]) AC_ARG_ENABLE([quiet], [ --enable-quiet Supress make output unless there is an error [default=no]]) AC_ARG_ENABLE([thread-safe], [ --enable-thread-safe Enable some client libraries to be thread safe. [default=no]]) AC_ARG_ENABLE([bundled-ltdl], [ --enable-bundled-ltdl Configure, build and install the standalone ltdl library bundled with ${PACKAGE} [default=no]]) LTDL_LIBS="" AC_ARG_ENABLE([no-stack], [ --enable-no-stack Only build the Policy Engine and pieces needed to support it [default=no]]) AC_ARG_WITH(ais, [ --with-ais Support the Corosync messaging and membership layer ], [ SUPPORT_CS=$withval ], [ SUPPORT_CS=try ], ) AC_ARG_WITH(corosync, [ --with-corosync Support the Corosync messaging and membership layer ], [ SUPPORT_CS=$withval ] dnl initialized in AC_ARG_WITH(ais...) already, dnl don't reset to try if it was given as --without-ais ) AC_ARG_WITH(heartbeat, [ --with-heartbeat Support the Heartbeat messaging and membership layer ], [ SUPPORT_HEARTBEAT=$withval ], [ SUPPORT_HEARTBEAT=try ], ) AC_ARG_WITH(cman, [ --with-cman Support the consumption of membership and quorum from cman ], [ SUPPORT_CMAN=$withval ], [ SUPPORT_CMAN=try ], ) AC_ARG_WITH(cpg, [ --with-cs-quorum Support the consumption of membership and quorum from corosync ], [ SUPPORT_CS_QUORUM=$withval ], [ SUPPORT_CS_QUORUM=try ], ) AC_ARG_WITH(snmp, [ --with-snmp Support the SNMP protocol ], [ SUPPORT_SNMP=$withval ], [ SUPPORT_SNMP=try ], ) AC_ARG_WITH(esmtp, [ --with-esmtp Support the sending mail notifications with the esmtp library ], [ SUPPORT_ESMTP=$withval ], [ SUPPORT_ESMTP=try ], ) AC_ARG_WITH(acl, [ --with-acl Support CIB ACL ], [ SUPPORT_ACL=$withval ], [ SUPPORT_ACL=no ], ) CSPREFIX="" AC_ARG_WITH(ais-prefix, [ --with-ais-prefix=DIR Prefix used when Corosync was installed [$prefix]], [ CSPREFIX=$withval ], [ CSPREFIX=$prefix ]) LCRSODIR="" AC_ARG_WITH(lcrso-dir, [ --with-lcrso-dir=DIR Corosync lcrso files. ], [ LCRSODIR="$withval" ]) INITDIR="" AC_ARG_WITH(initdir, [ --with-initdir=DIR directory for init (rc) scripts [${INITDIR}]], [ INITDIR="$withval" ]) SUPPORT_PROFILING=0 AC_ARG_WITH(profiling, [ --with-profiling Support gprof profiling ], [ SUPPORT_PROFILING=$withval ]) SUPPORT_GCOV=0 AC_ARG_WITH(gcov, [ --with-gcov Support gcov coverage testing ], [ SUPPORT_GCOV=$withval ]) PUBLICAN_BRAND="common" AC_ARG_WITH(brand, [ --with-brand=brand Brand to use for generated documentation [$PUBLICAN_BRAND]], [ PUBLICAN_BRAND="$withval" ]) AC_SUBST(PUBLICAN_BRAND) dnl =============================================== dnl General Processing dnl =============================================== AC_SUBST(HB_PKG) INIT_EXT="" echo Our Host OS: $host_os/$host AC_MSG_NOTICE(Sanitizing prefix: ${prefix}) case $prefix in NONE) prefix=/usr dnl Fix default variables - "prefix" variable if not specified if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi ;; esac AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix}) case $exec_prefix in dnl For consistency with Heartbeat, map NONE->$prefix NONE) exec_prefix=$prefix;; prefix) exec_prefix=$prefix;; esac AC_MSG_NOTICE(Sanitizing ais_prefix: ${CSPREFIX}) case $CSPREFIX in dnl For consistency with Heartbeat, map NONE->$prefix NONE) CSPREFIX=$prefix;; prefix) CSPREFIX=$prefix;; esac AC_MSG_NOTICE(Sanitizing INITDIR: ${INITDIR}) case $INITDIR in prefix) INITDIR=$prefix;; "") AC_MSG_CHECKING(which init (rc) directory to use) for initdir in /etc/init.d /etc/rc.d/init.d /sbin/init.d \ /usr/local/etc/rc.d /etc/rc.d do if test -d $initdir then INITDIR=$initdir break fi done AC_MSG_RESULT($INITDIR);; esac AC_SUBST(INITDIR) AC_MSG_NOTICE(Sanitizing libdir: ${libdir}) case $libdir in dnl For consistency with Heartbeat, map NONE->$prefix *prefix*|NONE) AC_MSG_CHECKING(which lib directory to use) for aDir in lib64 lib do trydir="${exec_prefix}/${aDir}" if test -d ${trydir} then libdir=${trydir} break fi done AC_MSG_RESULT($libdir); ;; esac dnl Expand autoconf variables so that we dont end up with '${prefix}' dnl in #defines and python scripts dnl NOTE: Autoconf deliberately leaves them unexpanded to allow dnl make exec_prefix=/foo install dnl No longer being able to do this seems like no great loss to me... eval prefix="`eval echo ${prefix}`" eval exec_prefix="`eval echo ${exec_prefix}`" eval bindir="`eval echo ${bindir}`" eval sbindir="`eval echo ${sbindir}`" eval libexecdir="`eval echo ${libexecdir}`" eval datadir="`eval echo ${datadir}`" eval sysconfdir="`eval echo ${sysconfdir}`" eval sharedstatedir="`eval echo ${sharedstatedir}`" eval localstatedir="`eval echo ${localstatedir}`" eval libdir="`eval echo ${libdir}`" eval includedir="`eval echo ${includedir}`" eval oldincludedir="`eval echo ${oldincludedir}`" eval infodir="`eval echo ${infodir}`" eval mandir="`eval echo ${mandir}`" dnl Home-grown variables eval INITDIR="${INITDIR}" eval docdir="`eval echo ${docdir}`" if test x"${docdir}" = x""; then docdir=${datadir}/doc/${PACKAGE}-${VERSION} #docdir=${datadir}/doc/packages/${PACKAGE} fi AC_SUBST(docdir) for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \ sharedstatedir localstatedir libdir includedir oldincludedir infodir \ mandir INITDIR docdir do dirname=`eval echo '${'${j}'}'` if test ! -d "$dirname" then AC_MSG_WARN([$j directory ($dirname) does not exist!]) fi done dnl This OS-based decision-making is poor autotools practice; dnl feature-based mechanisms are strongly preferred. dnl dnl So keep this section to a bare minimum; regard as a "necessary evil". case "$host_os" in *bsd*) LIBS="-L/usr/local/lib" CPPFLAGS="$CPPFLAGS -I/usr/local/include" INIT_EXT=".sh" ;; *solaris*) ;; *linux*) AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform) CFLAGS="$CFLAGS -I${prefix}/include" ;; darwin*) AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform) LIBS="$LIBS -L${prefix}/lib" CFLAGS="$CFLAGS -I${prefix}/include" ;; esac dnl Eventually remove this CFLAGS="$CFLAGS -I${prefix}/include/heartbeat" AC_SUBST(INIT_EXT) AC_MSG_NOTICE(Host CPU: $host_cpu) case "$host_cpu" in ppc64|powerpc64) case $CFLAGS in *powerpc64*) ;; *) if test "$GCC" = yes; then CFLAGS="$CFLAGS -m64" fi ;; esac esac AC_MSG_CHECKING(which format is needed to print uint64_t) ac_save_CFLAGS=$CFLAGS CFLAGS="-Wall -Werror" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include #include #include ], [ int max = 512; uint64_t bignum = 42; char *buffer = malloc(max); const char *random = "random"; snprintf(buffer, max-1, "", bignum, random); fprintf(stderr, "Result: %s\n", buffer); ] )], [U64T="%lu"], [U64T="%llu"] ) CFLAGS=$ac_save_CFLAGS AC_MSG_RESULT($U64T) AC_DEFINE_UNQUOTED(U64T, "$U64T", Correct printf format for logging uint64_t) dnl =============================================== dnl Program Paths dnl =============================================== PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin" export PATH dnl Replacing AC_PROG_LIBTOOL with AC_CHECK_PROG because LIBTOOL dnl was NOT being expanded all the time thus causing things to fail. AC_CHECK_PROGS(LIBTOOL, glibtool libtool libtool15 libtool13) AM_PATH_PYTHON AC_CHECK_PROGS(MAKE, gmake make) AC_PATH_PROGS(HTML2TXT, lynx w3m) AC_PATH_PROGS(HELP2MAN, help2man) AC_PATH_PROGS(POD2MAN, pod2man, pod2man) AC_PATH_PROGS(ASCIIDOC, asciidoc) AC_PATH_PROGS(PUBLICAN, publican) AC_PATH_PROGS(INKSCAPE, inkscape) AC_PATH_PROGS(XSLTPROC, xsltproc) AC_PATH_PROGS(FOP, fop) AC_PATH_PROGS(SSH, ssh, /usr/bin/ssh) AC_PATH_PROGS(SCP, scp, /usr/bin/scp) AC_PATH_PROGS(TAR, tar) AC_PATH_PROGS(MD5, md5) AC_PATH_PROGS(TEST, test) AC_PATH_PROGS(PKGCONFIG, pkg-config) AC_PATH_PROGS(XML2CONFIG, xml2-config) AC_PATH_PROGS(VALGRIND_BIN, valgrind, /usr/bin/valgrind) AC_DEFINE_UNQUOTED(VALGRIND_BIN, "$VALGRIND_BIN", Valgrind command) dnl Disable these until we decide if the stonith config file should be supported dnl AC_PATH_PROGS(BISON, bison) dnl AC_PATH_PROGS(FLEX, flex) dnl AC_PATH_PROGS(HAVE_YACC, $YACC) if test x"${LIBTOOL}" = x""; then AC_MSG_ERROR(You need (g)libtool installed in order to build ${PACKAGE}) fi if test x"${MAKE}" = x""; then AC_MSG_ERROR(You need (g)make installed in order to build ${PACKAGE}) fi AM_CONDITIONAL(BUILD_HELP, test x"${HELP2MAN}" != x"") if test x"${HELP2MAN}" != x""; then PCMK_FEATURES="$PCMK_FEATURES generated-manpages" fi MANPAGE_XSLT="" if test x"${XSLTPROC}" != x""; then AC_MSG_CHECKING(docbook to manpage transform) XSLT=`find ${datadir} -name docbook.xsl` for xsl in $XSLT; do dname=`dirname $xsl` bname=`basename $dname` if test "$bname" = "manpages"; then MANPAGE_XSLT="$xsl" break fi done fi AC_MSG_RESULT($MANPAGE_XSLT) AC_SUBST(MANPAGE_XSLT) AM_CONDITIONAL(BUILD_XML_HELP, test x"${MANPAGE_XSLT}" != x"") if test x"${MANPAGE_XSLT}" != x""; then PCMK_FEATURES="$PCMK_FEATURES agent-manpages" fi AM_CONDITIONAL(BUILD_ASCIIDOC, test x"${ASCIIDOC}" != x"") if test x"${ASCIIDOC}" != x""; then PCMK_FEATURES="$PCMK_FEATURES ascii-docs" fi SUPPORT_STONITH_CONFIG=0 if test x"${HAVE_YACC}" != x"" -a x"${FLEX}" != x"" -a x"${BISON}" != x""; then SUPPORT_STONITH_CONFIG=1 PCMK_FEATURES="$PCMK_FEATURES st-conf" fi AM_CONDITIONAL(BUILD_STONITH_CONFIG, test $SUPPORT_STONITH_CONFIG = 1) AC_DEFINE_UNQUOTED(SUPPORT_STONITH_CONFIG, $SUPPORT_STONITH_CONFIG, Support a stand-alone stonith config file in addition to the CIB) AM_CONDITIONAL(BUILD_DOCBOOK, test x"${PUBLICAN}" != x"" -a x"${INKSCAPE}" != x"") if test x"${PUBLICAN}" != x"" -a x"${INKSCAPE}" != x""; then AC_MSG_NOTICE(Enabling publican) PCMK_FEATURES="$PCMK_FEATURES publican-docs" fi dnl ======================================================================== dnl checks for library functions to replace them dnl dnl NoSuchFunctionName: dnl is a dummy function which no system supplies. It is here to make dnl the system compile semi-correctly on OpenBSD which doesn't know dnl how to create an empty archive dnl dnl scandir: Only on BSD. dnl System-V systems may have it, but hidden and/or deprecated. dnl A replacement function is supplied for it. dnl dnl setenv: is some bsdish function that should also be avoided (use dnl putenv instead) dnl On the other hand, putenv doesn't provide the right API for the dnl code and has memory leaks designed in (sigh...) Fortunately this dnl A replacement function is supplied for it. dnl dnl strerror: returns a string that corresponds to an errno. dnl A replacement function is supplied for it. dnl dnl unsetenv: is some bsdish function that should also be avoided (No dnl replacement) dnl A replacement function is supplied for it. dnl dnl strnlen: is a gnu function similar to strlen, but safer. dnl We wrote a tolearably-fast replacement function for it. dnl dnl strndup: is a gnu function similar to strdup, but safer. dnl We wrote a tolearably-fast replacement function for it. dnl dnl daemon: is a GNU function. The daemon() function is for programs wishing to dnl detach themselves from the controlling terminal and run in the dnl background as system daemon dnl A replacement function is supplied for it. AC_REPLACE_FUNCS(alphasort inet_pton NoSuchFunctionName scandir setenv strerror strchrnul unsetenv strnlen strndup daemon) dnl =============================================== dnl Libraries dnl =============================================== AC_CHECK_LIB(socket, socket) dnl -lsocket AC_CHECK_LIB(c, dlopen) dnl if dlopen is in libc... AC_CHECK_LIB(dl, dlopen) dnl -ldl (for Linux) AC_CHECK_LIB(rt, sched_getscheduler) dnl -lrt (for Tru64) AC_CHECK_LIB(gnugetopt, getopt_long) dnl -lgnugetopt ( if available ) AC_CHECK_LIB(pam, pam_start) dnl -lpam (if available) AC_CHECK_LIB(uuid, uuid_parse) dnl libuuid if test "x$ac_cv_lib_uuid_uuid_parse" != x""yes; then AC_MSG_ERROR(You do not have the libuuid development package installed) fi if test x"${PKGCONFIG}" = x""; then AC_MSG_ERROR(You need pkgconfig installed in order to build ${PACKAGE}) fi if test "x${enable_thread_safe}" = "xyes"; then GPKGNAME="gthread-2.0" else GPKGNAME="glib-2.0" fi if $PKGCONFIG --exists $GPKGNAME then GLIBCONFIG="$PKGCONFIG $GPKGNAME" else set -x echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH $PKGCONFIG --exists $GPKGNAME; echo $? $PKGCONFIG --cflags $GPKGNAME; echo $? $PKGCONFIG $GPKGNAME; echo $? set +x AC_MSG_ERROR(You need glib2-devel installed in order to build ${PACKAGE}) fi AC_MSG_RESULT(using $GLIBCONFIG) USE_GHASH_COMPAT=0 AC_CHECK_LIB(glib-2.0, g_hash_table_get_values) if test "x$ac_cv_lib_glib_2_0_g_hash_table_get_values" != x""yes; then AC_MSG_WARN(Your version of Glib is too old, you should have at least 2.14) USE_GHASH_COMPAT=1 fi AC_DEFINE_UNQUOTED(USE_GHASH_COMPAT, $USE_GHASH_COMPAT, Use g_hash_table compatibility functions) AC_SUBST(USE_GHASH_COMPAT) if $PKGCONFIG --exists systemd then systemdunitdir=`$PKGCONFIG --variable=systemdsystemunitdir systemd` AC_SUBST(systemdunitdir) fi AM_CONDITIONAL(HAVE_SYSTEMD, test -n "$systemdunitdir" -a "x$systemdunitdir" != xno) # # Where is dlopen? # if test "$ac_cv_lib_c_dlopen" = yes; then LIBADD_DL="" elif test "$ac_cv_lib_dl_dlopen" = yes; then LIBADD_DL=-ldl else LIBADD_DL=${lt_cv_dlopen_libs} fi dnl dnl Check for location of gettext dnl dnl On at least Solaris 2.x, where it is in libc, specifying lintl causes dnl grief. Ensure minimal result, not the sum of all possibilities. dnl And do libc first. dnl Known examples: dnl c: Linux, Solaris 2.6+ dnl intl: BSD, AIX AC_CHECK_LIB(c, gettext) if test x$ac_cv_lib_c_gettext != xyes; then AC_CHECK_LIB(intl, gettext) fi if test x$ac_cv_lib_c_gettext != xyes -a x$ac_cv_lib_intl_gettext != xyes; then AC_MSG_ERROR(You need gettext installed in order to build ${PACKAGE}) fi if test "X$GLIBCONFIG" != X; then AC_MSG_CHECKING(for special glib includes: ) GLIBHEAD=`$GLIBCONFIG --cflags` AC_MSG_RESULT($GLIBHEAD) CPPFLAGS="$CPPFLAGS $GLIBHEAD" AC_MSG_CHECKING(for glib library flags) GLIBLIB=`$GLIBCONFIG --libs` AC_MSG_RESULT($GLIBLIB) LIBS="$LIBS $GLIBLIB" fi dnl ======================================================================== dnl Headers dnl ======================================================================== AC_HEADER_STDC AC_CHECK_HEADERS(arpa/inet.h) AC_CHECK_HEADERS(asm/types.h) AC_CHECK_HEADERS(assert.h) AC_CHECK_HEADERS(auth-client.h) AC_CHECK_HEADERS(ctype.h) AC_CHECK_HEADERS(dirent.h) AC_CHECK_HEADERS(errno.h) AC_CHECK_HEADERS(fcntl.h) AC_CHECK_HEADERS(getopt.h) AC_CHECK_HEADERS(glib.h) AC_CHECK_HEADERS(grp.h) AC_CHECK_HEADERS(limits.h) AC_CHECK_HEADERS(linux/errqueue.h) AC_CHECK_HEADERS(malloc.h) AC_CHECK_HEADERS(netdb.h) AC_CHECK_HEADERS(netinet/in.h) AC_CHECK_HEADERS(netinet/ip.h) AC_CHECK_HEADERS(pam/pam_appl.h) AC_CHECK_HEADERS(pthread.h) AC_CHECK_HEADERS(pwd.h) AC_CHECK_HEADERS(security/pam_appl.h) AC_CHECK_HEADERS(sgtty.h) AC_CHECK_HEADERS(signal.h) AC_CHECK_HEADERS(stdarg.h) AC_CHECK_HEADERS(stddef.h) AC_CHECK_HEADERS(stdio.h) AC_CHECK_HEADERS(stdlib.h) AC_CHECK_HEADERS(string.h) AC_CHECK_HEADERS(strings.h) AC_CHECK_HEADERS(sys/dir.h) AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/param.h) AC_CHECK_HEADERS(sys/poll.h) AC_CHECK_HEADERS(sys/resource.h) AC_CHECK_HEADERS(sys/select.h) AC_CHECK_HEADERS(sys/socket.h) AC_CHECK_HEADERS(sys/sockio.h) AC_CHECK_HEADERS(sys/stat.h) AC_CHECK_HEADERS(sys/time.h) AC_CHECK_HEADERS(sys/timeb.h) AC_CHECK_HEADERS(sys/types.h) AC_CHECK_HEADERS(sys/uio.h) AC_CHECK_HEADERS(sys/un.h) AC_CHECK_HEADERS(sys/utsname.h) AC_CHECK_HEADERS(sys/wait.h) AC_CHECK_HEADERS(time.h) AC_CHECK_HEADERS(unistd.h) AC_CHECK_HEADERS(winsock.h) dnl These headers need prerequisits before the tests will pass dnl AC_CHECK_HEADERS(net/if.h) dnl AC_CHECK_HEADERS(netinet/icmp6.h) dnl AC_CHECK_HEADERS(netinet/ip6.h) dnl AC_CHECK_HEADERS(netinet/ip_icmp.h) AC_MSG_CHECKING(for special libxml2 includes) if test "x$XML2CONFIG" = "x"; then AC_MSG_ERROR(libxml2 config not found) else XML2HEAD="`$XML2CONFIG --cflags`" AC_MSG_RESULT($XML2HEAD) AC_CHECK_LIB(xml2, xmlReadMemory) AC_CHECK_LIB(xslt, xsltApplyStylesheet) fi CPPFLAGS="$CPPFLAGS $XML2HEAD" AC_CHECK_HEADERS(libxml/xpath.h) AC_CHECK_HEADERS(libxslt/xslt.h) if test "$ac_cv_header_libxml_xpath_h" != "yes"; then AC_MSG_ERROR(The libxml developement headers were not found) fi if test "$ac_cv_header_libxslt_xslt_h" != "yes"; then AC_MSG_ERROR(The libxslt developement headers were not found) fi dnl ======================================================================== dnl Structures dnl ======================================================================== AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[[#include ]]) AC_CHECK_MEMBERS([lrm_op_t.rsc_deleted],,,[[#include ]]) dnl ======================================================================== dnl Functions dnl ======================================================================== AC_CHECK_FUNCS(g_log_set_default_handler) AC_CHECK_FUNCS(getopt, AC_DEFINE(HAVE_DECL_GETOPT, 1, [Have getopt function])) AC_CHECK_FUNCS(nanosleep, AC_DEFINE(HAVE_DECL_NANOSLEEP, 1, [Have nanosleep function])) dnl ======================================================================== dnl ltdl dnl ======================================================================== AC_CHECK_LIB(ltdl, lt_dlopen, [LTDL_foo=1]) if test "x${enable_bundled_ltdl}" = "xyes"; then if test $ac_cv_lib_ltdl_lt_dlopen = yes; then AC_MSG_NOTICE([Disabling usage of installed ltdl]) fi ac_cv_lib_ltdl_lt_dlopen=no fi LIBLTDL_DIR="" if test $ac_cv_lib_ltdl_lt_dlopen != yes ; then AC_MSG_NOTICE([Installing local ltdl]) LIBLTDL_DIR=libltdl ( cd $srcdir ; $TAR -xvf libltdl.tar ) if test "$?" -ne 0; then AC_MSG_ERROR([$TAR of libltdl.tar in $srcdir failed]) fi AC_CONFIG_SUBDIRS(libltdl) else LIBS="$LIBS -lltdl" AC_MSG_NOTICE([Using installed ltdl]) INCLTDL="" LIBLTDL="" fi AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AC_SUBST(LIBLTDL_DIR) dnl ======================================================================== dnl bzip2 dnl ======================================================================== AC_CHECK_HEADERS(bzlib.h) AC_CHECK_LIB(bz2, BZ2_bzBuffToBuffCompress) if test x$ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress != xyes ; then AC_MSG_ERROR(BZ2 libraries not found) fi if test x$ac_cv_header_bzlib_h != xyes; then AC_MSG_ERROR(BZ2 Development headers not found) fi 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 ncurse takes precedence. dnl AC_CHECK_HEADERS(curses.h) AC_CHECK_HEADERS(curses/curses.h) AC_CHECK_HEADERS(ncurses.h) AC_CHECK_HEADERS(ncurses/ncurses.h) dnl Although n-library is preferred, only look for it if the n-header was found. CURSESLIBS='' if test "$ac_cv_header_ncurses_h" = "yes"; then AC_CHECK_LIB(ncurses, printw, [CURSESLIBS='-lncurses'; AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) fi if test "$ac_cv_header_ncurses_ncurses_h" = "yes"; then AC_CHECK_LIB(ncurses, printw, [CURSESLIBS='-lncurses'; AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) fi dnl Only look for non-n-library if there was no n-library. if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_h" = "yes"; then AC_CHECK_LIB(curses, printw, [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)] ) fi dnl Only look for non-n-library if there was no n-library. if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_curses_h" = "yes"; then AC_CHECK_LIB(curses, printw, [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)] ) fi if test "x$CURSESLIBS" != "x"; then PCMK_FEATURES="$PCMK_FEATURES ncurses" fi dnl Check for printw() prototype compatibility if test X"$CURSESLIBS" != X"" && cc_supports_flag -Wcast-qual && cc_supports_flag -Werror; then AC_MSG_CHECKING(whether printw() requires argument of "const char *") ac_save_LIBS=$LIBS LIBS="$CURSESLIBS $LIBS" ac_save_CFLAGS=$CFLAGS CFLAGS="-Wcast-qual -Werror" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #if defined(HAVE_CURSES_H) # include #elif defined(HAVE_NCURSES_H) # include #endif ], [printw((const char *)"Test");] )], [ac_cv_compatible_printw=yes], [ac_cv_compatible_printw=no] ) LIBS=$ac_save_LIBS CFLAGS=$ac_save_CFLAGS AC_MSG_RESULT([$ac_cv_compatible_printw]) if test "$ac_cv_compatible_printw" = no; then AC_MSG_WARN([The printw() function of your ncurses or curses library is old, we will disable usage of the library. If you want to use this library anyway, please update to newer version of the library, ncurses 5.4 or later is recommended. You can get the library from http://www.gnu.org/software/ncurses/.]) AC_MSG_NOTICE([Disabling curses]) AC_DEFINE(HAVE_INCOMPATIBLE_PRINTW, 1, [Do we have incompatible printw() in curses library?]) fi fi AC_SUBST(CURSESLIBS) dnl ======================================================================== dnl Profiling and GProf dnl ======================================================================== case $SUPPORT_PROFILING in 1|yes|true) SUPPORT_PROFILING=1 dnl Enable gprof #LIBS="$LIBS -pg" #CFLAGS="$CFLAGS -pg" dnl Disable various compiler optimizations CFLAGS="$CFLAGS -fno-omit-frame-pointer" #CFLAGS="$CFLAGS -fno-inline-functions -fno-inline-functions-called-once -fno-optimize-sibling-calls" dnl CFLAGS="$CFLAGS -fno-default-inline -fno-inline" dnl Update features PCMK_FEATURES="$PCMK_FEATURES gprof" ;; *) SUPPORT_PROFILING=0;; esac AC_DEFINE_UNQUOTED(SUPPORT_PROFILING, $SUPPORT_PROFILING, Support for gprof profiling) case $SUPPORT_GCOV in 1|yes|true) SUPPORT_GCOV=1 dnl Enable gprof #LIBS="$LIBS -pg" #CFLAGS="$CFLAGS -pg" dnl Disable various compiler optimizations CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage -fno-inline" dnl Turn off optimization so code coverage tool dnl can get accurate line numbers AC_MSG_NOTICE(Old CFLAGS: $CFLAGS) CFLAGS=`echo $CFLAGS | sed -e 's/-O.\ //g' -e 's/-Wp,-D_FORTIFY_SOURCE=.\ //g'` CFLAGS="$CFLAGS -O0" AC_MSG_NOTICE(New CFLAGS: $CFLAGS) dnl Update features PCMK_FEATURES="$PCMK_FEATURES gcov" ;; *) SUPPORT_PROFILING=0;; esac AC_DEFINE_UNQUOTED(SUPPORT_GCOV, $SUPPORT_GCOV, Support for gcov coverage testing) dnl ======================================================================== dnl Cluster infrastructure - Heartbeat / LibQB dnl ======================================================================== dnl Compatability checks AC_CHECK_MEMBERS([struct lrm_ops.fail_rsc],,,[[#include ]]) if test x${enable_no_stack} = xyes; then SUPPORT_HEARTBEAT=no SUPPORT_CS=no fi PKG_CHECK_MODULES(libqb, libqb, HAVE_libqb=1, HAVE_libqb=0) AC_CHECK_HEADERS(qb/qbipc_common.h) AC_CHECK_LIB(qb, qb_ipcc_is_connected) AC_CHECK_FUNCS(qb_ipcc_is_connected) LIBQB_LOG=1 PCMK_FEATURES="$PCMK_FEATURES libqb-logging" if test $ac_cv_lib_qb_qb_ipcc_is_connected != yes; then AC_MSG_FAILURE(Version of IPC in libqb is not new enough) fi AC_DEFINE_UNQUOTED(LIBQB_LOGGING, $LIBQB_LOG, Use libqb for logging) AC_DEFINE_UNQUOTED(LIBQB_IPC, 0, Use libqb for IPC) LIBS="$LIBS $libqb_LIBS" AC_CHECK_HEADERS(hb_config.h) AC_CHECK_HEADERS(glue_config.h) AC_CHECK_HEADERS(agent_config.h) GLUE_HEADER=none if test "$ac_cv_header_glue_config_h" = "yes"; then GLUE_HEADER=glue_config.h elif test "$ac_cv_header_hb_config_h" = "yes"; then GLUE_HEADER=hb_config.h else AC_MSG_WARN(cluster-glue development headers were not found) fi dnl =============================================== dnl Variables needed for substitution dnl =============================================== CRM_DTD_DIRECTORY="${datadir}/pacemaker" AC_DEFINE_UNQUOTED(CRM_DTD_DIRECTORY,"$CRM_DTD_DIRECTORY", Location for the Pacemaker Relax-NG Schema) AC_SUBST(CRM_DTD_DIRECTORY) AC_DEFINE_UNQUOTED(CRM_DTD_VERSION,"$CRM_DTD_VERSION", Current version of the Pacemaker Relax-NG Schema) AC_SUBST(CRM_DTD_VERSION) +CRM_CORE_DIR=`try_extract_header_define $GLUE_HEADER HA_COREDIR ${localstatedir}/lib/heartbeat/cores` +AC_DEFINE_UNQUOTED(CRM_CORE_DIR,"$CRM_CORE_DIR", Location to store core files produced by Pacemaker daemons) +AC_SUBST(CRM_CORE_DIR) + CRM_DAEMON_USER=`try_extract_header_define $GLUE_HEADER HA_CCMUSER hacluster` AC_DEFINE_UNQUOTED(CRM_DAEMON_USER,"$CRM_DAEMON_USER", User to run Pacemaker daemons as) AC_SUBST(CRM_DAEMON_USER) CRM_DAEMON_GROUP=`try_extract_header_define $GLUE_HEADER HA_APIGROUP haclient` AC_DEFINE_UNQUOTED(CRM_DAEMON_GROUP,"$CRM_DAEMON_GROUP", Group to run Pacemaker daemons as) AC_SUBST(CRM_DAEMON_GROUP) CRM_STATE_DIR=${localstatedir}/run/crm AC_DEFINE_UNQUOTED(CRM_STATE_DIR,"$CRM_STATE_DIR", Where to keep state files and sockets) AC_SUBST(CRM_STATE_DIR) CRM_BLACKBOX_DIR=${localstatedir}/lib/pacemaker AC_DEFINE_UNQUOTED(CRM_BLACKBOX_DIR,"$CRM_BLACKBOX_DIR", Where to keep blackbox dumps) AC_SUBST(CRM_BLACKBOX_DIR) PE_STATE_DIR="${localstatedir}/lib/pengine" AC_DEFINE_UNQUOTED(PE_STATE_DIR,"$PE_STATE_DIR", Where to keep PEngine outputs) AC_SUBST(PE_STATE_DIR) dnl Eventually move out of the heartbeat dir tree and create compatability code CRM_CONFIG_DIR="${localstatedir}/lib/heartbeat/crm" AC_DEFINE_UNQUOTED(CRM_CONFIG_DIR,"$CRM_CONFIG_DIR", Where to keep CIB 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) HB_DAEMON_DIR=`try_extract_header_define $GLUE_HEADER HA_LIBHBDIR $libdir/heartbeat` AC_DEFINE_UNQUOTED(HB_DAEMON_DIR,"$HB_DAEMON_DIR", Location for Heartbeat expects Pacemaker daemons to be in) AC_SUBST(HB_DAEMON_DIR) dnl Needed so that the Corosync plugin can clear out the directory as Heartbeat does HA_STATE_DIR=`try_extract_header_define $GLUE_HEADER HA_VARRUNDIR ${localstatedir}/run` AC_DEFINE_UNQUOTED(HA_STATE_DIR,"$HA_STATE_DIR", Where Heartbeat keeps state files and sockets) AC_SUBST(HA_STATE_DIR) CRM_RSCTMP_DIR=`try_extract_header_define agent_config.h HA_RSCTMPDIR $HA_STATE_DIR/heartbeat/rsctmp` AC_MSG_CHECKING(Scratch dir for resource agents) AC_MSG_RESULT($CRM_RSCTMP_DIR) AC_DEFINE_UNQUOTED(CRM_RSCTMP_DIR,"$CRM_RSCTMP_DIR", Where resource agents should keep state files) AC_SUBST(CRM_RSCTMP_DIR) dnl Needed for the location of hostcache in CTS.py HA_VARLIBHBDIR=`try_extract_header_define $GLUE_HEADER HA_VARLIBHBDIR ${localstatedir}/lib/heartbeat` AC_SUBST(HA_VARLIBHBDIR) AC_DEFINE_UNQUOTED(UUID_FILE,"$localstatedir/lib/heartbeat/hb_uuid", Location of Heartbeat's UUID file) OCF_ROOT_DIR=`try_extract_header_define $GLUE_HEADER OCF_ROOT_DIR /usr/lib/ocf` if test "X$OCF_ROOT_DIR" = X; then AC_MSG_ERROR(Could not locate OCF directory) fi AC_SUBST(OCF_ROOT_DIR) OCF_RA_DIR=`try_extract_header_define $GLUE_HEADER OCF_RA_DIR $OCF_ROOT_DIR/resource.d` AC_DEFINE_UNQUOTED(OCF_RA_DIR,"$OCF_RA_DIR", Location for OCF RAs) AC_SUBST(OCF_RA_DIR) RH_STONITH_DIR="$sbindir" AC_DEFINE_UNQUOTED(RH_STONITH_DIR,"$RH_STONITH_DIR", Location for Red Hat Stonith agents) RH_STONITH_PREFIX="fence_" AC_DEFINE_UNQUOTED(RH_STONITH_PREFIX,"$RH_STONITH_PREFIX", Prefix for Red Hat Stonith agents) AC_PATH_PROGS(GIT, git false) AC_MSG_CHECKING(build version) BUILD_VERSION=$Format:%H$ if test $BUILD_VERSION != ":%H$"; then AC_MSG_RESULT(archive hash: $BUILD_VERSION) elif test -x $GIT -a -d .git; then BUILD_VERSION=`$GIT log --pretty="format:%h" -n 1` AC_MSG_RESULT(git hash: $BUILD_VERSION) else # 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(directory based hash: $BUILD_VERSION) fi AC_DEFINE_UNQUOTED(BUILD_VERSION, "$BUILD_VERSION", Build version) AC_SUBST(BUILD_VERSION) STACKS="" CLUSTERLIBS="" dnl ======================================================================== dnl Cluster stack - Heartbeat dnl ======================================================================== case $SUPPORT_HEARTBEAT in 1|yes|true|try) AC_MSG_CHECKING(for heartbeat support) dnl On Debian, AC_CHECK_LIBS fail if a library has any unresolved symbols dnl So check for all the depenancies (so they're added to LIBS) before checking for -lplumb AC_CHECK_LIB(pils, PILLoadPlugin) AC_CHECK_LIB(plumb, G_main_add_IPC_Channel) AC_CHECK_LIB(hbclient, ll_cluster_new, [SUPPORT_HEARTBEAT=1], [if $SUPPORT_HEARTBEAT != try; then AC_MSG_FAILURE(Unable to support Heartbeat: client libraries not found) fi]) if test $SUPPORT_HEARTBEAT = 1 ; then STACKS="$STACKS heartbeat" AC_DEFINE_UNQUOTED(CCM_LIBRARY, "libccmclient.so.1", Library to load for ccm support) AC_DEFINE_UNQUOTED(HEARTBEAT_LIBRARY, "libhbclient.so.1", Library to load for heartbeat support) else SUPPORT_HEARTBEAT=0 fi ;; *) SUPPORT_HEARTBEAT=0;; esac AM_CONDITIONAL(BUILD_HEARTBEAT_SUPPORT, test $SUPPORT_HEARTBEAT = 1) AC_DEFINE_UNQUOTED(SUPPORT_HEARTBEAT, $SUPPORT_HEARTBEAT, Support the Heartbeat messaging and membership layer) AC_SUBST(SUPPORT_HEARTBEAT) dnl ======================================================================== dnl Cluster stack - Corosync dnl ======================================================================== dnl Normalize the values case $SUPPORT_CS in 1|yes|true) SUPPORT_CS=yes missingisfatal=1;; try) missingisfatal=0;; *) SUPPORT_CS=no;; esac AC_MSG_CHECKING(for native corosync) COROSYNC_LIBS="" CS_USES_LIBQB=0 PCMK_SERVICE_ID=9 LCRSODIR="$libdir" if test $SUPPORT_CS = no; then AC_MSG_RESULT(no (disabled)) SUPPORT_CS=0 else AC_MSG_RESULT($SUPPORT_CS, with '$CSPREFIX') PKG_CHECK_MODULES(cpg, libcpg) dnl Fatal PKG_CHECK_MODULES(cfg, libcfg) dnl Fatal PKG_CHECK_MODULES(cmap, libcmap, HAVE_cmap=1, HAVE_cmap=0) PKG_CHECK_MODULES(cman, libcman, HAVE_cman=1, HAVE_cman=0) PKG_CHECK_MODULES(confdb, libconfdb, HAVE_confdb=1, HAVE_confdb=0) PKG_CHECK_MODULES(fenced, libfenced, HAVE_fenced=1, HAVE_fenced=0) PKG_CHECK_MODULES(quorum, libquorum, HAVE_quorum=1, HAVE_quorum=0) PKG_CHECK_MODULES(oldipc, libcoroipcc, HAVE_oldipc=1, HAVE_oldipc=0) if test $HAVE_oldipc = 1; then SUPPORT_CS=1 CFLAGS="$CFLAGS $oldipc_FLAGS $cpg_FLAGS $cfg_FLAGS" COROSYNC_LIBS="$COROSYNC_LIBS $oldipc_LIBS $cpg_LIBS $cfg_LIBS" elif test $HAVE_libqb = 1; then SUPPORT_CS=1 CS_USES_LIBQB=1 CFLAGS="$CFLAGS $libqb_FLAGS $cpg_FLAGS $cfg_FLAGS" COROSYNC_LIBS="$COROSYNC_LIBS $libqb_LIBS $cpg_LIBS $cfg_LIBS" AC_CHECK_LIB(corosync_common, cs_strerror) else aisreason="corosync/libqb IPC libraries not found by pkg_config" fi AC_DEFINE_UNQUOTED(HAVE_CONFDB, $HAVE_confdb, Have the old herarchial Corosync config API) AC_DEFINE_UNQUOTED(HAVE_CMAP, $HAVE_cmap, Have the new non-herarchial Corosync config API) fi if test $SUPPORT_CS = 1 -a x$HAVE_oldipc = x0 ; then dnl Support for plugins was removed about the time the IPC was dnl moved to libqb. dnl The only option now is the built-in quorum API CFLAGS="$CFLAGS $cmap_CFLAGS $quorum_CFLAGS" COROSYNC_LIBS="$COROSYNC_LIBS $cmap_LIBS $quorum_LIBS" STACKS="$STACKS corosync-native" AC_DEFINE_UNQUOTED(SUPPORT_CS_QUORUM, 1, Support the consumption of membership and quorum from corosync) fi if test $SUPPORT_CS = 1 -a x$HAVE_confdb = x1; then dnl Need confdb to support cman and the plugins LCRSODIR=`$PKGCONFIG corosync --variable=lcrsodir` STACKS="$STACKS corosync-plugin" COROSYNC_LIBS="$COROSYNC_LIBS $confdb_LIBS" if test $SUPPORT_CMAN != no; then if test $HAVE_cman = 1 -a $HAVE_fenced = 1; then SUPPORT_CMAN=1 STACKS="$STACKS cman" CFLAGS="$CFLAGS $cman_FLAGS $fenced_FLAGS" COROSYNC_LIBS="$COROSYNC_LIBS $cman_LIBS $fenced_LIBS" fi fi fi dnl Normalize SUPPORT_CS and SUPPORT_CMAN for use with #if directives if test $SUPPORT_CMAN != 1; then SUPPORT_CMAN=0 fi if test $SUPPORT_CS = 1; then CLUSTERLIBS="$CLUSTERLIBS $COROSYNC_LIBS" elif test $SUPPORT_CS != 0; then SUPPORT_CS=0 if test $missingisfatal = 0; then AC_MSG_WARN(Unable to support Corosync: $aisreason) else AC_MSG_FAILURE(Unable to support Corosync: $aisreason) fi fi AC_DEFINE_UNQUOTED(SUPPORT_COROSYNC, $SUPPORT_CS, Support the Corosync messaging and membership layer) AC_DEFINE_UNQUOTED(SUPPORT_CMAN, $SUPPORT_CMAN, Support the consumption of membership and quorum from cman) AC_DEFINE_UNQUOTED(CS_USES_LIBQB, $CS_USES_LIBQB, Does corosync use libqb for its ipc) AC_DEFINE_UNQUOTED(PCMK_SERVICE_ID, $PCMK_SERVICE_ID, Corosync service number) AM_CONDITIONAL(BUILD_CS_SUPPORT, test $SUPPORT_CS = 1) AM_CONDITIONAL(BUILD_CS_PLUGIN, test $HAVE_confdb = 1) dnl confdb went away at about the same time as plugins AC_SUBST(SUPPORT_CMAN) AC_SUBST(SUPPORT_CS) dnl dnl Cluster stack - Sanity dnl if test x${enable_no_stack} = xyes; then AC_MSG_NOTICE(No cluster stack supported. Just building the Policy Engine) PCMK_FEATURES="$PCMK_FEATURES no-cluster-stack" else AC_MSG_CHECKING(for supported stacks) if test x"$STACKS" = x; then AC_MSG_FAILURE(You must support at least one cluster stack (heartbeat or corosync) ) fi AC_MSG_RESULT($STACKS) PCMK_FEATURES="$PCMK_FEATURES $STACKS" fi AC_SUBST(CLUSTERLIBS) AC_SUBST(LCRSODIR) dnl ======================================================================== dnl SNMP dnl ======================================================================== case $SUPPORT_SNMP in 1|yes|true) missingisfatal=1;; try) missingisfatal=0;; *) SUPPORT_SNMP=no;; esac SNMPLIBS="" AC_MSG_CHECKING(for snmp support) if test $SUPPORT_SNMP = no; then AC_MSG_RESULT(no (disabled)) SUPPORT_SNMP=0 else SNMPCONFIG="" AC_MSG_RESULT($SUPPORT_SNMP) AC_CHECK_HEADERS(net-snmp/net-snmp-config.h) if test "x${ac_cv_header_net_snmp_net_snmp_config_h}" != "xyes"; then SUPPORT_SNMP="no" fi if test $SUPPORT_SNMP != no; then AC_PATH_PROGS(SNMPCONFIG, net-snmp-config) if test "X${SNMPCONFIG}" = "X"; then AC_MSG_RESULT(You need the net_snmp development package to continue.) SUPPORT_SNMP=no fi fi if test $SUPPORT_SNMP != no; then AC_MSG_CHECKING(for special snmp libraries) SNMPLIBS=`$SNMPCONFIG --agent-libs` AC_MSG_RESULT($SNMPLIBS) fi if test $SUPPORT_SNMP != no; then savedLibs=$LIBS LIBS="$LIBS $SNMPLIBS" dnl On many systems libcrypto is needed when linking against libsnmp. dnl Check to see if it exists, and if so use it. dnl AC_CHECK_LIB(crypto, CRYPTO_free, CRYPTOLIB="-lcrypto",) dnl AC_SUBST(CRYPTOLIB) AC_CHECK_FUNCS(netsnmp_transport_open_client) if test $ac_cv_func_netsnmp_transport_open_client != yes; then AC_CHECK_FUNCS(netsnmp_tdomain_transport) if test $ac_cv_func_netsnmp_tdomain_transport != yes; then SUPPORT_SNMP=no else AC_DEFINE_UNQUOTED(NETSNMPV53, 1, [Use the older 5.3 version of the net-snmp API]) fi fi LIBS=$savedLibs fi if test $SUPPORT_SNMP = no; then SNMPLIBS="" SUPPORT_SNMP=0 if test $missingisfatal = 0; then AC_MSG_WARN(Unable to support SNMP) else AC_MSG_FAILURE(Unable to support SNMP) fi else SUPPORT_SNMP=1 fi fi if test $SUPPORT_SNMP = 1; then PCMK_FEATURES="$PCMK_FEATURES snmp" fi AC_SUBST(SNMPLIBS) AM_CONDITIONAL(ENABLE_SNMP, test "$SUPPORT_SNMP" = "1") AC_DEFINE_UNQUOTED(ENABLE_SNMP, $SUPPORT_SNMP, Build in support for sending SNMP traps) dnl ======================================================================== dnl ESMTP dnl ======================================================================== case $SUPPORT_ESMTP in 1|yes|true) missingisfatal=1;; try) missingisfatal=0;; *) SUPPORT_ESMTP=no;; esac ESMTPLIB="" AC_MSG_CHECKING(for esmtp support) if test $SUPPORT_ESMTP = no; then AC_MSG_RESULT(no (disabled)) SUPPORT_ESMTP=0 else ESMTPCONFIG="" AC_MSG_RESULT($SUPPORT_ESMTP) AC_CHECK_HEADERS(libesmtp.h) if test "x${ac_cv_header_libesmtp_h}" != "xyes"; then ENABLE_ESMTP="no" fi if test $SUPPORT_ESMTP != no; then AC_PATH_PROGS(ESMTPCONFIG, libesmtp-config) if test "X${ESMTPCONFIG}" = "X"; then AC_MSG_RESULT(You need the libesmtp development package to continue.) SUPPORT_ESMTP=no fi fi if test $SUPPORT_ESMTP != no; then AC_MSG_CHECKING(for special esmtp libraries) ESMTPLIBS=`$ESMTPCONFIG --libs | tr '\n' ' '` AC_MSG_RESULT($ESMTPLIBS) fi if test $SUPPORT_ESMTP = no; then SUPPORT_ESMTP=0 if test $missingisfatal = 0; then AC_MSG_WARN(Unable to support ESMTP) else AC_MSG_FAILURE(Unable to support ESMTP) fi else SUPPORT_ESMTP=1 PCMK_FEATURES="$PCMK_FEATURES libesmtp" fi fi AC_SUBST(ESMTPLIBS) AM_CONDITIONAL(ENABLE_ESMTP, test "$SUPPORT_ESMTP" = "1") AC_DEFINE_UNQUOTED(ENABLE_ESMTP, $SUPPORT_ESMTP, Build in support for sending mail notifications with ESMTP) dnl ======================================================================== dnl ACL dnl ======================================================================== case $SUPPORT_ACL in 1|yes|true) missingisfatal=1;; try) missingisfatal=0;; *) SUPPORT_ACL=no;; esac AC_MSG_CHECKING(for acl support) if test $SUPPORT_ACL = no; then AC_MSG_RESULT(no (disabled)) SUPPORT_ACL=0 else AC_MSG_RESULT($SUPPORT_ACL) AC_CHECK_MEMBERS([struct IPC_CHANNEL.farside_uid], [SUPPORT_ACL=1], [SUPPORT_ACL=0], [[#include ]]) if test $SUPPORT_ACL = 0; then if test $missingisfatal = 0; then AC_MSG_WARN(Unable to support ACL. You need to use cluster-glue >= 1.0.6) else AC_MSG_FAILURE(Unable to support ACL. You need to use cluster-glue >= 1.0.6) fi fi fi if test $SUPPORT_ACL = 1; then PCMK_FEATURES="$PCMK_FEATURES acls" fi AM_CONDITIONAL(ENABLE_ACL, test "$SUPPORT_ACL" = "1") AC_DEFINE_UNQUOTED(ENABLE_ACL, $SUPPORT_ACL, Build in support for CIB ACL) dnl ======================================================================== dnl GnuTLS dnl ======================================================================== AC_CHECK_HEADERS(gnutls/gnutls.h) AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h) dnl GNUTLS library: Attempt to determine by 'libgnutls-config' program. dnl If no 'libgnutls-config', try traditional autoconf means. AC_PATH_PROGS(LIBGNUTLS_CONFIG, libgnutls-config) if test -n "$LIBGNUTLS_CONFIG"; then AC_MSG_CHECKING(for gnutls header flags) GNUTLSHEAD="`$LIBGNUTLS_CONFIG --cflags`"; AC_MSG_RESULT($GNUTLSHEAD) AC_MSG_CHECKING(for gnutls library flags) GNUTLSLIBS="`$LIBGNUTLS_CONFIG --libs`"; AC_MSG_RESULT($GNUTLSLIBS) fi AC_CHECK_LIB(gnutls, gnutls_init) AC_CHECK_FUNCS(gnutls_priority_set_direct) AC_SUBST(GNUTLSHEAD) AC_SUBST(GNUTLSLIBS) dnl ======================================================================== dnl System Health dnl ======================================================================== dnl Check if servicelog development package is installed SERVICELOG=servicelog-1 SERVICELOG_EXISTS="no" AC_MSG_CHECKING(for $SERVICELOG packages) if $PKGCONFIG --exists $SERVICELOG then PKG_CHECK_MODULES([SERVICELOG], [servicelog-1]) SERVICELOG_EXISTS="yes" fi AC_MSG_RESULT($SERVICELOG_EXISTS) AM_CONDITIONAL(BUILD_SERVICELOG, test "$SERVICELOG_EXISTS" = "yes") dnl Check if OpenIMPI packages and servicelog are installed OPENIPMI="OpenIPMI OpenIPMIposix" OPENIPMI_SERVICELOG_EXISTS="no" AC_MSG_CHECKING(for $SERVICELOG $OPENIPMI packages) if $PKGCONFIG --exists $OPENIPMI $SERVICELOG then PKG_CHECK_MODULES([OPENIPMI_SERVICELOG],[OpenIPMI OpenIPMIposix]) OPENIPMI_SERVICELOG_EXISTS="yes" fi AC_MSG_RESULT($OPENIPMI_SERVICELOG_EXISTS) AM_CONDITIONAL(BUILD_OPENIPMI_SERVICELOG, test "$OPENIPMI_SERVICELOG_EXISTS" = "yes") 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. CC_ERRORS="" CC_EXTRAS="" if export | fgrep " CFLAGS=" > /dev/null; then SAVED_CFLAGS="$CFLAGS" unset CFLAGS CFLAGS="$SAVED_CFLAGS" unset SAVED_CFLAGS fi if test "$GCC" != yes; then CFLAGS="$CFLAGS -g" enable_fatal_warnings=no else CFLAGS="$CFLAGS -ggdb" # We had to eliminate -Wnested-externs because of libtool changes EXTRA_FLAGS="-fgnu89-inline -fstack-protector-all -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wdeclaration-after-statement -Wendif-labels -Wfloat-equal -Wformat=2 -Wformat-security -Wformat-nonliteral -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Wno-long-long -Wno-strict-aliasing -Wno-unused-but-set-variable -Wpointer-arith -Wstrict-prototypes -Wunsigned-char -Wwrite-strings" # Additional warnings it might be nice to enable one day # -Wshadow # -Wunreachable-code for j in $EXTRA_FLAGS do if cc_supports_flag $j then CC_EXTRAS="$CC_EXTRAS $j" fi done dnl In lib/ais/Makefile.am there's a gcc option available as of v4.x GCC_MAJOR=`gcc -v 2>&1 | awk 'END{print $3}' | sed 's/[.].*//'` AM_CONDITIONAL(GCC_4, test "${GCC_MAJOR}" = 4) dnl System specific options case "$host_os" in *linux*|*bsd*) if test "${enable_fatal_warnings}" = "unknown"; then enable_fatal_warnings=yes fi ;; esac if test "x${enable_fatal_warnings}" != xno && cc_supports_flag -Werror ; then enable_fatal_warnings=yes else enable_fatal_warnings=no fi if test "x${enable_ansi}" = xyes && cc_supports_flag -std=iso9899:199409 ; then AC_MSG_NOTICE(Enabling ANSI Compatibility) CC_EXTRAS="$CC_EXTRAS -ansi -D_GNU_SOURCE -DANSI_ONLY" fi AC_MSG_NOTICE(Activated additional gcc flags: ${CC_EXTRAS}) fi CFLAGS="$CFLAGS $CC_EXTRAS" 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 if test "x${enable_fatal_warnings}" = xyes ; then AC_MSG_NOTICE(Enabling Fatal Warnings) CFLAGS="$CFLAGS -Werror" fi 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(LIBADD_INTL) dnl extra flags for GNU gettext stuff... AC_SUBST(LOCALE) dnl Options for cleaning up the compiler output QUIET_LIBTOOL_OPTS="" QUIET_MAKE_OPTS="" if test "x${enable_quiet}" = "xyes"; then QUIET_LIBTOOL_OPTS="--quiet" QUIET_MAKE_OPTS="--quiet" fi AC_MSG_RESULT(Supress make details: ${enable_quiet}) dnl Put the above variables to use LIBTOOL="${LIBTOOL} --tag=CC \$(QUIET_LIBTOOL_OPTS)" MAKE="${MAKE} \$(QUIET_MAKE_OPTS)" AC_SUBST(CC) AC_SUBST(MAKE) AC_SUBST(LIBTOOL) AC_SUBST(QUIET_MAKE_OPTS) AC_SUBST(QUIET_LIBTOOL_OPTS) AC_DEFINE_UNQUOTED(CRM_FEATURES, "$PCMK_FEATURES", Set of enabled features) AC_SUBST(PCMK_FEATURES) dnl The Makefiles and shell scripts we output AC_CONFIG_FILES(Makefile \ cts/Makefile \ cts/CTSvars.py \ cts/LSBDummy \ cts/benchmark/Makefile \ cts/benchmark/clubench \ cib/Makefile \ crmd/Makefile \ pengine/Makefile \ pengine/regression.core.sh \ doc/Makefile \ doc/Pacemaker_Explained/publican.cfg \ doc/Clusters_from_Scratch/publican.cfg \ include/Makefile \ include/crm/Makefile \ include/crm/common/Makefile \ include/crm/pengine/Makefile \ replace/Makefile \ lib/Makefile \ lib/pcmk.pc \ lib/pcmk-pe.pc \ lib/pcmk-cib.pc \ lib/ais/Makefile \ lib/common/Makefile \ lib/cluster/Makefile \ lib/cib/Makefile \ lib/pengine/Makefile \ lib/transition/Makefile \ lib/fencing/Makefile \ lib/lrmd/Makefile \ lib/services/Makefile \ mcp/Makefile \ mcp/pacemaker \ mcp/pacemaker.service \ fencing/Makefile \ lrmd/Makefile \ extra/Makefile \ extra/resources/Makefile \ extra/rgmanager/Makefile \ tools/Makefile \ tools/crm_report \ tools/coverage.sh \ tools/hb2openais.sh \ tools/crm_primitive.py \ xml/Makefile \ lib/gnu/Makefile \ ) 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_RESULT([]) AC_MSG_RESULT([$PACKAGE configuration:]) AC_MSG_RESULT([ Version = ${VERSION} (Build: $BUILD_VERSION)]) AC_MSG_RESULT([ Features =${PCMK_FEATURES}]) AC_MSG_RESULT([]) AC_MSG_RESULT([ Prefix = ${prefix}]) AC_MSG_RESULT([ Executables = ${sbindir}]) AC_MSG_RESULT([ Man pages = ${mandir}]) AC_MSG_RESULT([ Libraries = ${libdir}]) AC_MSG_RESULT([ Header files = ${includedir}]) AC_MSG_RESULT([ Arch-independent files = ${datadir}]) AC_MSG_RESULT([ State information = ${localstatedir}]) AC_MSG_RESULT([ System configuration = ${sysconfdir}]) AC_MSG_RESULT([ Corosync Plugins = ${LCRSODIR}]) AC_MSG_RESULT([]) AC_MSG_RESULT([ Use system LTDL = ${ac_cv_lib_ltdl_lt_dlopen}]) AC_MSG_RESULT([]) AC_MSG_RESULT([ HA group name = ${CRM_DAEMON_GROUP}]) AC_MSG_RESULT([ HA user name = ${CRM_DAEMON_USER}]) AC_MSG_RESULT([]) AC_MSG_RESULT([ CFLAGS = ${CFLAGS}]) AC_MSG_RESULT([ Libraries = ${LIBS}]) AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}]) diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am index e44d94f78c..32df1332b9 100644 --- a/include/crm/common/Makefile.am +++ b/include/crm/common/Makefile.am @@ -1,23 +1,23 @@ # # Copyright (C) 2004 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in headerdir=$(pkgincludedir)/crm/common -header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h +header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h logging.h diff --git a/include/crm/common/logging.h b/include/crm/common/logging.h new file mode 100644 index 0000000000..64ad118f2c --- /dev/null +++ b/include/crm/common/logging.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2004 Andrew Beekhof + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef CRM_LOGGING__H +# define CRM_LOGGING__H +# include +# ifndef LOG_TRACE +# define LOG_TRACE LOG_DEBUG+1 +# endif +# define LOG_DEBUG_2 LOG_TRACE +# define LOG_DEBUG_3 LOG_TRACE +# define LOG_DEBUG_4 LOG_TRACE +# define LOG_DEBUG_5 LOG_TRACE +# define LOG_DEBUG_6 LOG_TRACE + +extern unsigned int crm_log_level; +extern gboolean crm_config_error; +extern gboolean crm_config_warning; + +void crm_enable_blackbox(int nsig); +void crm_enable_blackbox_tracing(int nsig); +void crm_write_blackbox(int nsig); + +void crm_update_callsites(void); + +void crm_log_deinit(void); + +gboolean crm_log_cli_init(const char *entity); + +gboolean crm_log_init(const char *entity, int level, gboolean daemon, + gboolean to_stderr, int argc, char **argv, gboolean quiet); + +void crm_log_args(int argc, char **argv); + +gboolean crm_add_logfile(const char *filename); + +void crm_bump_log_level(void); + +void crm_enable_stderr(int enable); + +/* returns the old value */ +unsigned int set_crm_log_level(unsigned int level); + +unsigned int get_crm_log_level(void); + +/* + * Throughout the macros below, note the leading, pre-comma, space in the + * various ' , ##args' occurences to aid portability across versions of 'gcc'. + * http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros + */ +# define CRM_TRACE_INIT_DATA(name) QB_LOG_INIT_DATA(name) + +# define do_crm_log(level, fmt, args...) do { \ + qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, 0, ##args); \ + if((level) < LOG_WARNING) { \ + crm_write_blackbox(0); \ + } \ + } while(0) + +/* level /MUST/ be a constant or compilation will fail */ +# define do_crm_log_unlikely(level, fmt, args...) do { \ + static struct qb_log_callsite *trace_cs = NULL; \ + if(trace_cs == NULL) { \ + trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, 0); \ + } \ + if (trace_cs && trace_cs->targets) { \ + qb_log_from_external_source( \ + __func__, __FILE__, fmt, level, __LINE__, 0, ##args); \ + } \ + } while(0) + +# define CRM_LOG_ASSERT(expr) do { \ + if(__unlikely((expr) == FALSE)) { \ + static struct qb_log_callsite *core_cs = NULL; \ + if(core_cs == NULL) { \ + core_cs = qb_log_callsite_get(__func__, __FILE__, "log-assert", LOG_TRACE, __LINE__, 0); \ + } \ + crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \ + core_cs?core_cs->targets:FALSE, TRUE); \ + } \ + } while(0) + +# define CRM_CHECK(expr, failure_action) do { \ + if(__unlikely((expr) == FALSE)) { \ + static struct qb_log_callsite *core_cs = NULL; \ + if(core_cs == NULL) { \ + core_cs = qb_log_callsite_get(__func__, __FILE__, "check-assert", LOG_TRACE, __LINE__, 0); \ + } \ + crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \ + core_cs?core_cs->targets:FALSE, TRUE); \ + failure_action; \ + } \ + } while(0) + +# define do_crm_log_xml(level, text, xml) do { \ + static struct qb_log_callsite *xml_cs = NULL; \ + if(xml_cs == NULL) { \ + xml_cs = qb_log_callsite_get(__func__, __FILE__, "xml-blog", level, __LINE__, 0); \ + } \ + if (xml_cs && xml_cs->targets) { \ + log_data_element(level, __FILE__, __PRETTY_FUNCTION__, __LINE__, text, xml, 0, TRUE); \ + } \ + if((level) < LOG_WARNING) { \ + crm_write_blackbox(0); \ + } \ + } while(0) + +# define do_crm_log_alias(level, file, function, line, fmt, args...) do { \ + qb_log_from_external_source(function, file, fmt, level, line, 0, ##args); \ + } while(0) + +# define do_crm_log_always(level, fmt, args...) qb_log(level, "%s: " fmt, __PRETTY_FUNCTION__ , ##args) + +# define crm_perror(level, fmt, args...) do { \ + const char *err = strerror(errno); \ + fprintf(stderr, fmt ": %s (%d)\n", ##args, err, errno); \ + do_crm_log(level, fmt ": %s (%d)", ##args, err, errno); \ + if((level) < LOG_WARNING) { \ + crm_write_blackbox(0); \ + } \ + } while(0) + +# define crm_log_tag(level, tag, fmt, args...) do { \ + qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, g_quark_try_string(tag), ##args); \ + } while(0) + + +# define crm_crit(fmt, args...) do { \ + qb_logt(LOG_CRIT, 0, fmt , ##args); \ + crm_write_blackbox(0); \ + } while(0) + +# define crm_err(fmt, args...) do { \ + qb_logt(LOG_ERR, 0, fmt , ##args); \ + crm_write_blackbox(0); \ + } while(0) + +# define crm_warn(fmt, args...) qb_logt(LOG_WARNING, 0, fmt , ##args) +# define crm_notice(fmt, args...) qb_logt(LOG_NOTICE, 0, fmt , ##args) +# define crm_info(fmt, args...) qb_logt(LOG_INFO, 0, fmt , ##args) + +# define crm_debug(fmt, args...) do_crm_log_unlikely(LOG_DEBUG, fmt , ##args) +# define crm_trace(fmt, args...) do_crm_log_unlikely(LOG_TRACE, fmt , ##args) + +# define crm_log_xml_crit(xml, text) do_crm_log_xml(LOG_CRIT, text, xml) +# define crm_log_xml_err(xml, text) do_crm_log_xml(LOG_ERR, text, xml) +# define crm_log_xml_warn(xml, text) do_crm_log_xml(LOG_WARNING, text, xml) +# define crm_log_xml_notice(xml, text) do_crm_log_xml(LOG_NOTICE, text, xml) +# define crm_log_xml_info(xml, text) do_crm_log_xml(LOG_INFO, text, xml) +# define crm_log_xml_debug(xml, text) do_crm_log_xml(LOG_DEBUG, text, xml) +# define crm_log_xml_trace(xml, text) do_crm_log_xml(LOG_TRACE, text, xml) + +# define crm_str(x) (const char*)(x?x:"") + +#endif diff --git a/include/crm/common/util.h b/include/crm/common/util.h index f54bfff911..59feab9791 100644 --- a/include/crm/common/util.h +++ b/include/crm/common/util.h @@ -1,403 +1,374 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CRM_COMMON_UTIL__H # define CRM_COMMON_UTIL__H # include # include # include # include # include # include # if SUPPORT_HEARTBEAT # include # else # define NORMALNODE "normal" # define ACTIVESTATUS "active"/* fully functional, and all links are up */ # define DEADSTATUS "dead" /* Status of non-working link or machine */ # define PINGSTATUS "ping" /* Status of a working ping node */ # define JOINSTATUS "join" /* Status when an api client joins */ # define LEAVESTATUS "leave" /* Status when an api client leaves */ # define ONLINESTATUS "online"/* Status of an online client */ # define OFFLINESTATUS "offline" /* Status of an offline client */ # endif -extern unsigned int crm_log_level; -extern gboolean crm_config_error; -extern gboolean crm_config_warning; - # ifdef HAVE_GETOPT_H # include # else # define no_argument 0 # define required_argument 1 # endif # define pcmk_option_default 0x00000 # define pcmk_option_hidden 0x00001 # define pcmk_option_paragraph 0x00002 # define pcmk_option_example 0x00004 struct crm_option { /* Fields from 'struct option' in getopt.h */ /* name of long option */ const char *name; /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; /* if not NULL, set *flag to val when option found */ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; /* Custom fields */ const char *desc; long flags; }; # define crm_config_err(fmt...) { crm_config_error = TRUE; crm_err(fmt); } # define crm_config_warn(fmt...) { crm_config_warning = TRUE; crm_warn(fmt); } -void crm_log_deinit(void); - -gboolean crm_log_cli_init(const char *entity); - -gboolean crm_log_init(const char *entity, int level, gboolean daemon, - gboolean to_stderr, int argc, char **argv, gboolean quiet); - -void crm_log_args(int argc, char **argv); - -gboolean crm_add_logfile(const char *filename); - -void crm_bump_log_level(void); - -void crm_enable_stderr(int enable); - -/* returns the old value */ -unsigned int set_crm_log_level(unsigned int level); - -unsigned int get_crm_log_level(void); - char *crm_itoa(int an_int); char *crm_strdup_fn(const char *a, const char *file, const char *fn, int line); char *generate_hash_key(const char *crm_msg_reference, const char *sys); char *generate_hash_value(const char *src_node, const char *src_subsys); gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value); int compare_version(const char *version1, const char *version2); char *generateReference(const char *custom1, const char *custom2); void g_hash_destroy_str(gpointer data); gboolean crm_is_true(const char *s); int crm_str_to_boolean(const char *s, int *ret); long long crm_get_msec(const char *input); unsigned long long crm_get_interval(const char *input); char *generate_op_key(const char *rsc_id, const char *op_type, int interval); gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval); char *generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type); char *generate_transition_magic_v202(const char *transition_key, int op_status); char *generate_transition_magic(const char *transition_key, int op_status, int op_rc); gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc); char *generate_transition_key(int action, int transition_id, int target_rc, const char *node); gboolean decode_transition_key(const char *key, char **uuid, int *action, int *transition_id, int *target_rc); char *crm_concat(const char *prefix, const char *suffix, char join); gboolean decode_op_key(const char *key, char **rsc_id, char **op_type, int *interval); void filter_action_parameters(xmlNode * param_set, const char *version); void filter_reload_parameters(xmlNode * param_set, const char *restart_string); static inline int crm_strlen_zero(const char *s) { return !s || *s == '\0'; } # define safe_str_eq(a, b) crm_str_eq(a, b, FALSE) gboolean crm_str_eq(const char *a, const char *b, gboolean use_case); gboolean safe_str_neq(const char *a, const char *b); int crm_parse_int(const char *text, const char *default_text); long long crm_int_helper(const char *text, char **end_text); # define crm_atoi(text, default_text) crm_parse_int(text, default_text) void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork); char *generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip); int get_last_sequence(const char *directory, const char *series); void write_last_sequence(const char *directory, const char *series, int sequence, int max); int crm_pid_active(long pid); int crm_read_pidfile(const char *filename); int crm_lock_pidfile(const char *filename); void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile); typedef struct pe_cluster_option_s { const char *name; const char *alt_name; const char *type; const char *values; const char *default_value; gboolean(*is_valid) (const char *); const char *description_short; const char *description_long; } pe_cluster_option; const char *cluster_option(GHashTable * options, gboolean(*validate) (const char *), const char *name, const char *old_name, const char *def_value); const char *get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name); void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option * option_list, int len); void verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len); gboolean check_time(const char *value); gboolean check_timer(const char *value); gboolean check_boolean(const char *value); gboolean check_number(const char *value); int char2score(const char *score); char *score2char(int score); gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both); # define set_bit(word, bit) word = crm_set_bit(__PRETTY_FUNCTION__, NULL, word, bit) # define clear_bit(word, bit) word = crm_clear_bit(__PRETTY_FUNCTION__, NULL, word, bit) # define set_bit_inplace set_bit # define clear_bit_inplace clear_bit static inline long long crm_clear_bit(const char *function, const char *target, long long word, long long bit) { long long rc = (word & ~bit); if(rc == word) { /* Unchanged */ } else if (target) { crm_trace("Bit 0x%.8llx for %s cleared by %s", bit, target, function); } else { crm_trace("Bit 0x%.8llx cleared by %s", bit, function); } return rc; } static inline long long crm_set_bit(const char *function, const char *target, long long word, long long bit) { long long rc = (word|bit); if(rc == word) { /* Unchanged */ } else if (target) { crm_trace("Bit 0x%.8llx for %s set by %s", bit, target, function); } else { crm_trace("Bit 0x%.8llx set by %s", bit, function); } return rc; } static inline gboolean is_not_set(long long word, long long bit) { return ((word & bit) == 0); } static inline gboolean is_set(long long word, long long bit) { return ((word & bit) == bit); } static inline gboolean is_set_any(long long word, long long bit) { return ((word & bit) != 0); } xmlNode *cib_recv_remote_msg(void *session, gboolean encrypted); void cib_send_remote_msg(void *session, xmlNode * msg, gboolean encrypted); char *crm_meta_name(const char *field); const char *crm_meta_value(GHashTable * hash, const char *field); void crm_set_options(const char *short_options, const char *usage, struct crm_option *long_options, const char *app_desc); int crm_get_option(int argc, char **argv, int *index); void crm_help(char cmd, int exit_code); int rsc_op_expected_rc(lrmd_event_data_t *event); gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc); extern int node_score_red; extern int node_score_green; extern int node_score_yellow; extern int node_score_infinity; xmlNode *create_operation_update(xmlNode * parent, lrmd_event_data_t *event, const char *caller_version, int target_rc, const char *origin, int level); # if USE_GHASH_COMPAT typedef struct fake_ghi { GHashTable *hash; int nth; /* current index over the iteration */ int lpc; /* internal loop counter inside g_hash_table_find */ gpointer key; gpointer value; } GHashTableIter; static inline void g_hash_prepend_value(gpointer key, gpointer value, gpointer user_data) { GList **values = (GList **) user_data; *values = g_list_prepend(*values, value); } static inline GList * g_hash_table_get_values(GHashTable * hash_table) { GList *values = NULL; g_hash_table_foreach(hash_table, g_hash_prepend_value, &values); return values; } static inline gboolean g_hash_table_nth_data(gpointer key, gpointer value, gpointer user_data) { GHashTableIter *iter = (GHashTableIter *) user_data; if (iter->lpc++ == iter->nth) { iter->key = key; iter->value = value; return TRUE; } return FALSE; } static inline void g_hash_table_iter_init(GHashTableIter * iter, GHashTable * hash_table) { iter->hash = hash_table; iter->nth = 0; iter->lpc = 0; iter->key = NULL; iter->value = NULL; } static inline gboolean g_hash_table_iter_next(GHashTableIter * iter, gpointer * key, gpointer * value) { gboolean found = FALSE; iter->lpc = 0; iter->key = NULL; iter->value = NULL; if (iter->nth < g_hash_table_size(iter->hash)) { found = ! !g_hash_table_find(iter->hash, g_hash_table_nth_data, iter); iter->nth++; } if (key) *key = iter->key; if (value) *value = iter->value; return found; } # endif /* USE_GHASH_COMPAT */ # if ENABLE_ACL static inline gboolean is_privileged(const char *user) { if (user == NULL) { return FALSE; } else if (strcmp(user, CRM_DAEMON_USER) == 0) { return TRUE; } else if (strcmp(user, "root") == 0) { return TRUE; } return FALSE; } void determine_request_user(char **user, IPC_Channel * channel, xmlNode * request, const char *field); # endif void *find_library_function(void **handle, const char *lib, const char *fn); void *convert_const_pointer(const void *ptr); char *crm_generate_uuid(void); char *crm_md5sum(const char *buffer); -void crm_enable_blackbox(int nsig); -void crm_enable_blackbox_tracing(int nsig); -void crm_write_blackbox(int nsig); - -void crm_update_callsites(void); int crm_user_lookup(const char *name, uid_t * uid, gid_t * gid); #endif diff --git a/include/crm/crm.h b/include/crm/crm.h index 8261113ea7..acf9d16d0a 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,387 +1,267 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CRM__H # define CRM__H # include # include # include # include # include # undef MIN # undef MAX # include -# include # include int log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode * data, int depth, gboolean formatted); # define CRM_FEATURE_SET "3.0.6" # define MINIMUM_SCHEMA_VERSION "pacemaker-1.0" # define LATEST_SCHEMA_VERSION "pacemaker-"CRM_DTD_VERSION # define EOS '\0' # define DIMOF(a) ((int) (sizeof(a)/sizeof(a[0])) ) # ifndef __GNUC__ # define __builtin_expect(expr, result) (expr) # endif /* Some handy macros used by the Linux kernel */ # define __likely(expr) __builtin_expect(expr, 1) # define __unlikely(expr) __builtin_expect(expr, 0) # define CRM_DEPRECATED_SINCE_2_0_1 0 # define CRM_DEPRECATED_SINCE_2_0_2 0 # define CRM_DEPRECATED_SINCE_2_0_3 0 # define CRM_DEPRECATED_SINCE_2_0_4 0 # define CRM_DEPRECATED_SINCE_2_0_5 0 # define CRM_DEPRECATED_SINCE_2_0_6 1 # define CRM_DEPRECATED_SINCE_2_0_7 1 # define CRM_DEPRECATED_SINCE_2_0_8 1 # define CRM_DEPRECATED_SINCE_2_1_0 1 # define CRM_META "CRM_meta" # define CRM_ASSERT(expr) do { \ if(__unlikely((expr) == FALSE)) { \ crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, TRUE, FALSE); \ } \ } while(0) extern const char *crm_system_name; /* *INDENT-OFF* */ /* Clean these up at some point, some probably should be runtime options */ # define SOCKET_LEN 1024 # define APPNAME_LEN 256 # define MAX_IPC_FAIL 5 # define MAX_IPC_DELAY 120 # define MSG_LOG 1 # define DOT_FSA_ACTIONS 1 # define DOT_ALL_FSA_INPUTS 1 /* #define FSA_TRACE 1 */ # define INFINITY_S "INFINITY" # define MINUS_INFINITY_S "-INFINITY" # define INFINITY 1000000 /* Sub-systems */ # define CRM_SYSTEM_DC "dc" # define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ # define CRM_SYSTEM_CIB "cib" # define CRM_SYSTEM_CRMD "crmd" # define CRM_SYSTEM_LRMD "lrmd" # define CRM_SYSTEM_PENGINE "pengine" # define CRM_SYSTEM_TENGINE "tengine" # define CRM_SYSTEM_STONITHD "stonithd" # define CRM_SYSTEM_MCP "pacemakerd" /* Valid operations */ # define CRM_OP_NOOP "noop" # define CRM_OP_JOIN_ANNOUNCE "join_announce" # define CRM_OP_JOIN_OFFER "join_offer" # define CRM_OP_JOIN_REQUEST "join_request" # define CRM_OP_JOIN_ACKNAK "join_ack_nack" # define CRM_OP_JOIN_CONFIRM "join_confirm" # define CRM_OP_DIE "die_no_respawn" # define CRM_OP_RETRIVE_CIB "retrieve_cib" # define CRM_OP_PING "ping" # define CRM_OP_VOTE "vote" # define CRM_OP_NOVOTE "no-vote" # define CRM_OP_HELLO "hello" # define CRM_OP_HBEAT "dc_beat" # define CRM_OP_PECALC "pe_calc" # define CRM_OP_ABORT "abort" # define CRM_OP_QUIT "quit" # define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" # define CRM_OP_SHUTDOWN_REQ "req_shutdown" # define CRM_OP_SHUTDOWN "do_shutdown" # define CRM_OP_FENCE "stonith" # define CRM_OP_EVENTCC "event_cc" # define CRM_OP_TEABORT "te_abort" # define CRM_OP_TEABORTED "te_abort_confirmed" /* we asked */ # define CRM_OP_TE_HALT "te_halt" # define CRM_OP_TECOMPLETE "te_complete" # define CRM_OP_TETIMEOUT "te_timeout" # define CRM_OP_TRANSITION "transition" # define CRM_OP_REGISTER "register" # define CRM_OP_DEBUG_UP "debug_inc" # define CRM_OP_DEBUG_DOWN "debug_dec" # define CRM_OP_INVOKE_LRM "lrm_invoke" # define CRM_OP_LRM_REFRESH "lrm_refresh" # define CRM_OP_LRM_QUERY "lrm_query" # define CRM_OP_LRM_DELETE "lrm_delete" # define CRM_OP_LRM_FAIL "lrm_fail" # define CRM_OP_PROBED "probe_complete" # define CRM_OP_REPROBE "probe_again" # define CRM_OP_CLEAR_FAILCOUNT "clear_failcount" # define CRM_OP_RELAXED_SET "one-or-more" # define CRMD_STATE_ACTIVE "member" # define CRMD_STATE_INACTIVE "down" # define CRMD_JOINSTATE_DOWN CRMD_STATE_INACTIVE # define CRMD_JOINSTATE_PENDING "pending" # define CRMD_JOINSTATE_MEMBER CRMD_STATE_ACTIVE # define CRMD_JOINSTATE_NACK "banned" # define CRMD_ACTION_DELETE "delete" # define CRMD_ACTION_CANCEL "cancel" # define CRMD_ACTION_MIGRATE "migrate_to" # define CRMD_ACTION_MIGRATED "migrate_from" # define CRMD_ACTION_START "start" # define CRMD_ACTION_STARTED "running" # define CRMD_ACTION_STOP "stop" # define CRMD_ACTION_STOPPED "stopped" # define CRMD_ACTION_PROMOTE "promote" # define CRMD_ACTION_PROMOTED "promoted" # define CRMD_ACTION_DEMOTE "demote" # define CRMD_ACTION_DEMOTED "demoted" # define CRMD_ACTION_NOTIFY "notify" # define CRMD_ACTION_NOTIFIED "notified" # define CRMD_ACTION_STATUS "monitor" /* short names */ # define RSC_DELETE CRMD_ACTION_DELETE # define RSC_CANCEL CRMD_ACTION_CANCEL # define RSC_MIGRATE CRMD_ACTION_MIGRATE # define RSC_MIGRATED CRMD_ACTION_MIGRATED # define RSC_START CRMD_ACTION_START # define RSC_STARTED CRMD_ACTION_STARTED # define RSC_STOP CRMD_ACTION_STOP # define RSC_STOPPED CRMD_ACTION_STOPPED # define RSC_PROMOTE CRMD_ACTION_PROMOTE # define RSC_PROMOTED CRMD_ACTION_PROMOTED # define RSC_DEMOTE CRMD_ACTION_DEMOTE # define RSC_DEMOTED CRMD_ACTION_DEMOTED # define RSC_NOTIFY CRMD_ACTION_NOTIFY # define RSC_NOTIFIED CRMD_ACTION_NOTIFIED # define RSC_STATUS CRMD_ACTION_STATUS /* *INDENT-ON* */ typedef GList *GListPtr; -# ifndef LOG_TRACE -# define LOG_TRACE LOG_DEBUG+1 -# endif -# define LOG_DEBUG_2 LOG_TRACE -# define LOG_DEBUG_3 LOG_TRACE -# define LOG_DEBUG_4 LOG_TRACE -# define LOG_DEBUG_5 LOG_TRACE -# define LOG_DEBUG_6 LOG_TRACE - -# define LOG_MSG LOG_TRACE - -/* - * Throughout the macros below, note the leading, pre-comma, space in the - * various ' , ##args' occurences to aid portability across versions of 'gcc'. - * http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros - */ -# define CRM_TRACE_INIT_DATA(name) QB_LOG_INIT_DATA(name) - -# define do_crm_log(level, fmt, args...) do { \ - qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, 0, ##args); \ - if((level) < LOG_WARNING) { \ - crm_write_blackbox(0); \ - } \ - } while(0) - -/* level /MUST/ be a constant or compilation will fail */ -# define do_crm_log_unlikely(level, fmt, args...) do { \ - static struct qb_log_callsite *trace_cs = NULL; \ - if(trace_cs == NULL) { \ - trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, 0); \ - } \ - if (trace_cs && trace_cs->targets) { \ - qb_log_from_external_source( \ - __func__, __FILE__, fmt, level, __LINE__, 0, ##args); \ - } \ - } while(0) - -# define CRM_LOG_ASSERT(expr) do { \ - if(__unlikely((expr) == FALSE)) { \ - static struct qb_log_callsite *core_cs = NULL; \ - if(core_cs == NULL) { \ - core_cs = qb_log_callsite_get(__func__, __FILE__, "log-assert", LOG_TRACE, __LINE__, 0); \ - } \ - crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \ - core_cs?core_cs->targets:FALSE, TRUE); \ - } \ - } while(0) - -# define CRM_CHECK(expr, failure_action) do { \ - if(__unlikely((expr) == FALSE)) { \ - static struct qb_log_callsite *core_cs = NULL; \ - if(core_cs == NULL) { \ - core_cs = qb_log_callsite_get(__func__, __FILE__, "check-assert", LOG_TRACE, __LINE__, 0); \ - } \ - crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \ - core_cs?core_cs->targets:FALSE, TRUE); \ - failure_action; \ - } \ - } while(0) - -# define do_crm_log_xml(level, text, xml) do { \ - static struct qb_log_callsite *xml_cs = NULL; \ - if(xml_cs == NULL) { \ - xml_cs = qb_log_callsite_get(__func__, __FILE__, "xml-blog", level, __LINE__, 0); \ - } \ - if (xml_cs && xml_cs->targets) { \ - log_data_element(level, __FILE__, __PRETTY_FUNCTION__, __LINE__, text, xml, 0, TRUE); \ - } \ - if((level) < LOG_WARNING) { \ - crm_write_blackbox(0); \ - } \ - } while(0) - -# define do_crm_log_alias(level, file, function, line, fmt, args...) do { \ - qb_log_from_external_source(function, file, fmt, level, line, 0, ##args); \ - } while(0) - -# define do_crm_log_always(level, fmt, args...) qb_log(level, "%s: " fmt, __PRETTY_FUNCTION__ , ##args) - -# define crm_perror(level, fmt, args...) do { \ - const char *err = strerror(errno); \ - fprintf(stderr, fmt ": %s (%d)\n", ##args, err, errno); \ - do_crm_log(level, fmt ": %s (%d)", ##args, err, errno); \ - if((level) < LOG_WARNING) { \ - crm_write_blackbox(0); \ - } \ - } while(0) - -# define crm_log_tag(level, tag, fmt, args...) do { \ - qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, g_quark_try_string(tag), ##args); \ - } while(0) - - -# define crm_crit(fmt, args...) do { \ - qb_logt(LOG_CRIT, 0, fmt , ##args); \ - crm_write_blackbox(0); \ - } while(0) - -# define crm_err(fmt, args...) do { \ - qb_logt(LOG_ERR, 0, fmt , ##args); \ - crm_write_blackbox(0); \ - } while(0) - -# define crm_warn(fmt, args...) qb_logt(LOG_WARNING, 0, fmt , ##args) -# define crm_notice(fmt, args...) qb_logt(LOG_NOTICE, 0, fmt , ##args) -# define crm_info(fmt, args...) qb_logt(LOG_INFO, 0, fmt , ##args) - -# define crm_debug(fmt, args...) do_crm_log_unlikely(LOG_DEBUG, fmt , ##args) -# define crm_trace(fmt, args...) do_crm_log_unlikely(LOG_TRACE, fmt , ##args) - +# include # include -# define crm_log_xml_crit(xml, text) do_crm_log_xml(LOG_CRIT, text, xml) -# define crm_log_xml_err(xml, text) do_crm_log_xml(LOG_ERR, text, xml) -# define crm_log_xml_warn(xml, text) do_crm_log_xml(LOG_WARNING, text, xml) -# define crm_log_xml_notice(xml, text) do_crm_log_xml(LOG_NOTICE, text, xml) -# define crm_log_xml_info(xml, text) do_crm_log_xml(LOG_INFO, text, xml) -# define crm_log_xml_debug(xml, text) do_crm_log_xml(LOG_DEBUG, text, xml) -# define crm_log_xml_trace(xml, text) do_crm_log_xml(LOG_TRACE, text, xml) - -# define crm_str(x) (const char*)(x?x:"") - # define crm_malloc0(malloc_obj, length) do { \ malloc_obj = malloc(length); \ if(malloc_obj == NULL) { \ crm_err("Failed allocation of %lu bytes", (unsigned long)length); \ CRM_ASSERT(malloc_obj != NULL); \ } \ memset(malloc_obj, 0, length); \ } while(0) # define crm_malloc(malloc_obj, length) do { \ malloc_obj = malloc(length); \ if(malloc_obj == NULL) { \ crm_err("Failed allocation of %lu bytes", (unsigned long)length); \ CRM_ASSERT(malloc_obj != NULL); \ } \ } while(0) # define crm_realloc(realloc_obj, length) do { \ realloc_obj = realloc(realloc_obj, length); \ CRM_ASSERT(realloc_obj != NULL); \ } while(0) # define crm_free(free_obj) do { free(free_obj); free_obj=NULL; } while(0) # define crm_strdup(str) crm_strdup_fn(str, __FILE__, __PRETTY_FUNCTION__, __LINE__) # define crm_str_hash g_str_hash_traditional guint g_str_hash_traditional(gconstpointer v); void update_all_trace_data(void); static inline void slist_basic_destroy(GListPtr list) { GListPtr gIter = NULL; for (gIter = list; gIter != NULL; gIter = gIter->next) { free(gIter->data); } g_list_free(list); } /* These two macros are no longer to be used * They exist for compatability reasons and will be removed in a * future release * Use something like this instead: GListPtr gIter = rsc->children; for(; gIter != NULL; gIter = gIter->next) { resource_t *child_rsc = (resource_t*)gIter->data; ... } * */ # define slist_destroy(child_type, child, parent, a) do { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ while(__crm_iter_head != NULL) { \ child = (child_type *) __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ g_list_free(parent); \ } while(0) #endif diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am index 19827253b5..599e08db20 100644 --- a/lib/common/Makefile.am +++ b/lib/common/Makefile.am @@ -1,50 +1,50 @@ # # Copyright (C) 2004 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \ -I$(top_builddir)/lib/gnu -I$(top_srcdir)/lib/gnu ## libraries lib_LTLIBRARIES = libcrmcommon.la # Can't use -Wcast-qual here because glib insists on pretending things are const # when they're not and thus we need the crm_element_value_const() hack # s390 needs -fPIC # s390-suse-linux/bin/ld: .libs/ipc.o: relocation R_390_PC32DBL against `__stack_chk_fail@@GLIBC_2.4' can not be used when making a shared object; recompile with -fPIC CFLAGS = $(CFLAGS_COPY:-Wcast-qual=) -fPIC -libcrmcommon_la_SOURCES = ipc.c utils.c xml.c iso8601.c iso8601_fields.c remote.c mainloop.c +libcrmcommon_la_SOURCES = ipc.c utils.c xml.c iso8601.c iso8601_fields.c remote.c mainloop.c logging.c libcrmcommon_la_LDFLAGS = -version-info 3:0:0 libcrmcommon_la_LIBADD = -ldl $(GNUTLSLIBS) libcrmcommon_la_SOURCES += $(top_builddir)/lib/gnu/md5.c if BUILD_HEARTBEAT_SUPPORT libcrmcommon_la_SOURCES += heartbeat.c endif clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: diff --git a/lib/common/logging.c b/lib/common/logging.c new file mode 100644 index 0000000000..c31182475d --- /dev/null +++ b/lib/common/logging.c @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2004 Andrew Beekhof + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +unsigned int crm_log_level = LOG_INFO; +static gboolean crm_tracing_enabled(void); + +#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER +GLogFunc glib_log_default; + +static void +crm_glib_handler(const gchar * log_domain, GLogLevelFlags flags, const gchar * message, + gpointer user_data) +{ + int log_level = LOG_WARNING; + GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK); + + switch (msg_level) { + case G_LOG_LEVEL_CRITICAL: + /* log and record how we got here */ + crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, message, TRUE, TRUE); + return; + + case G_LOG_LEVEL_ERROR: + log_level = LOG_ERR; + break; + case G_LOG_LEVEL_MESSAGE: + log_level = LOG_NOTICE; + break; + case G_LOG_LEVEL_INFO: + log_level = LOG_INFO; + break; + case G_LOG_LEVEL_DEBUG: + log_level = LOG_DEBUG; + break; + + case G_LOG_LEVEL_WARNING: + case G_LOG_FLAG_RECURSION: + case G_LOG_FLAG_FATAL: + case G_LOG_LEVEL_MASK: + log_level = LOG_WARNING; + break; + } + + do_crm_log(log_level, "%s: %s", log_domain, message); +} +#endif + +#ifndef NAME_MAX +# define NAME_MAX 256 +#endif +static const char * +daemon_option(const char *option) +{ + char env_name[NAME_MAX]; + const char *value = NULL; + + snprintf(env_name, NAME_MAX, "PCMK_%s", option); + value = getenv(env_name); + if (value != NULL) { + return value; + } + + snprintf(env_name, NAME_MAX, "HA_%s", option); + value = getenv(env_name); + if (value != NULL) { + return value; + } + + return NULL; +} + +static gboolean +daemon_option_enabled(const char *daemon, const char *option) +{ + const char *value = daemon_option(option); + if (value != NULL && crm_is_true(value)) { + return TRUE; + + } else if (value != NULL && strstr(value, daemon)) { + return TRUE; + } + + return FALSE; +} + +void +crm_log_deinit(void) +{ +#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER + g_log_set_default_handler(glib_log_default, NULL); +#endif +} + +#define FMT_MAX 256 +static void +set_format_string(int method, const char *daemon) +{ + int offset = 0; + char fmt[FMT_MAX]; + + if (method > QB_LOG_STDERR) { + /* When logging to a file */ + struct utsname res; + + if (uname(&res) == 0) { + offset += + snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %s %10s: ", getpid(), + res.nodename, daemon); + } else { + offset += snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %10s: ", getpid(), daemon); + } + } + + if (crm_tracing_enabled() && method >= QB_LOG_STDERR) { + offset += snprintf(fmt + offset, FMT_MAX - offset, "(%%-12f:%%5l %%g) %%-7p: %%n: "); + } else { + offset += snprintf(fmt + offset, FMT_MAX - offset, "%%g %%-7p: %%n: "); + } + + if (method == QB_LOG_SYSLOG) { + offset += snprintf(fmt + offset, FMT_MAX - offset, "%%b"); + } else { + offset += snprintf(fmt + offset, FMT_MAX - offset, "\t%%b"); + } + qb_log_format_set(method, fmt); +} + +gboolean +crm_add_logfile(const char *filename) +{ + struct stat parent; + int fd = 0, rc = 0; + FILE *logfile = NULL; + char *parent_dir = NULL; + + static gboolean have_logfile = FALSE; + + if(filename == NULL && have_logfile == FALSE) { + filename = "/var/log/pacemaker.log"; + } + + if (filename == NULL) { + return FALSE; /* Nothing to do */ + } + + /* Check the parent directory and attempt to open */ + parent_dir = dirname(strdup(filename)); + rc = stat(parent_dir, &parent); + + if (rc != 0) { + crm_err("Directory '%s' does not exist: logging to '%s' is disabled", parent_dir, filename); + return FALSE; + + } else if (parent.st_uid == geteuid() && (parent.st_mode & (S_IRUSR | S_IWUSR))) { + /* all good - user */ + logfile = fopen(filename, "a"); + + } else if (parent.st_gid == getegid() && (parent.st_mode & S_IXGRP)) { + /* all good - group */ + logfile = fopen(filename, "a"); + + } else { + crm_err("We (uid=%u, gid=%u) do not have permission to access '%s': logging to '%s' is disabled", + geteuid(), getegid(), parent_dir, filename); + return FALSE; + } + + /* Check/Set permissions if we're root */ + if(logfile && geteuid() == 0) { + struct stat st; + uid_t pcmk_uid = 0; + gid_t pcmk_gid = 0; + gboolean fix = FALSE; + int logfd = fileno(logfile); + + rc = fstat(logfd, &st); + if(rc < 0) { + crm_perror(LOG_WARNING, "Cannot stat %s", filename); + return FALSE; + } + + crm_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid); + if(st.st_gid != pcmk_gid) { + /* Wrong group */ + fix = TRUE; + } else if((st.st_mode & S_IRWXG) != (S_IRGRP|S_IWGRP)) { + /* Not read/writable by the correct group */ + fix = TRUE; + } + + if(fix) { + rc = fchown(logfd, pcmk_uid, pcmk_gid); + if(rc < 0) { + crm_warn("Cannot change the ownership of %s to user %s and gid %d", + filename, CRM_DAEMON_USER, pcmk_gid); + } + + rc = fchmod(logfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if(rc < 0) { + crm_warn("Cannot change the mode of %s to rw-rw----", filename); + } + + fprintf(logfile, "Set r/w permissions for uid=%d, gid=%d on %s\n", + pcmk_uid, pcmk_gid, filename); + if(fflush(logfile) < 0 || fsync(logfd) < 0) { + crm_err("Couldn't write out logfile: %s", filename); + } + } + fclose(logfile); + } + + /* Now open with libqb */ + fd = qb_log_file_open(filename); + + if(fd < 0) { + crm_perror(LOG_WARNING, "Couldn't send additional logging to %s", filename); + return FALSE; + } + + crm_notice("Additional logging available in %s", filename); + qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_TRUE); + + /* Enable callsites */ + crm_update_callsites(); + have_logfile = TRUE; + return TRUE; +} + + +static char *blackbox_file_prefix = NULL; +static gboolean blackbox_tracing_enabled = FALSE; + +void +crm_enable_blackbox_tracing(int nsig) +{ + + if(blackbox_tracing_enabled) { + blackbox_tracing_enabled = FALSE; + } else { + blackbox_tracing_enabled = TRUE; + } + crm_update_callsites(); + crm_debug("Blackbox tracing is %s", blackbox_tracing_enabled?"on":"off"); +} + +void +crm_enable_blackbox(int nsig) +{ + if(blackbox_file_prefix == NULL) { + pid_t pid = getpid(); + + blackbox_file_prefix = malloc(NAME_MAX); + snprintf(blackbox_file_prefix, NAME_MAX, "%s/blackbox-%s-%d", CRM_BLACKBOX_DIR, crm_system_name, pid); + } + + if (qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { + qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*1024); /* Any size change drops existing entries */ + qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); /* Setting the size seems to disable it */ + + crm_notice("Initiated blackbox recorder: %s", blackbox_file_prefix); + crm_signal(SIGSEGV, crm_write_blackbox); + crm_update_callsites(); + + /* Original meanings from signal(7) + * + * Signal Value Action Comment + * SIGPROF 27,27,29 Term Profiling timer expired + * SIGTRAP 5 Core Trace/breakpoint trap + * + * Our usage is as similar as possible + */ + mainloop_add_signal(SIGPROF, crm_enable_blackbox_tracing); + mainloop_add_signal(SIGTRAP, crm_write_blackbox); + } +} + +void +crm_write_blackbox(int nsig) +{ + static int counter = 1; + static time_t last = 0; + + char buffer[NAME_MAX]; + time_t now = time(NULL); + + if(blackbox_file_prefix == NULL) { + return; + } + + switch(nsig) { + case 0: + case SIGTRAP: + /* The graceful case - such as assertion failure or user request */ + snprintf(buffer, NAME_MAX, "%s.%d", blackbox_file_prefix, counter++); + + if(nsig == 0 && (now - last) < 2) { + /* Prevent over-dumping */ + return; + + } else if(nsig == SIGTRAP) { + crm_notice("Blackbox dump requested, please see %s for contents", buffer); + + } else { + crm_notice("Problem detected, please see %s for additional details", buffer); + } + last = now; + qb_log_blackbox_write_to_file(buffer); + + /* Flush the existing contents + * A size change would also work + */ + qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE); + qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); + break; + + default: + /* Do as little as possible, just try to get what we have out + * We logged the filename when the blackbox was enabled + */ + crm_signal(nsig, SIG_DFL); + qb_log_blackbox_write_to_file(blackbox_file_prefix); + qb_log_fini(); + raise(nsig); + break; + } +} + +gboolean +crm_log_cli_init(const char *entity) +{ + return crm_log_init(entity, LOG_ERR, FALSE, FALSE, 0, NULL, TRUE); +} + +static const char *crm_quark_to_string(uint32_t tag) +{ + const char *text = g_quark_to_string(tag); + if(text) { + return text; + } + return ""; +} + +static void +crm_log_filter_source(int source, const char *trace_files, const char *trace_fns, const char *trace_fmts, const char *trace_tags, struct qb_log_callsite *cs) +{ + if (qb_log_ctl(source, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { + return; + } else if (source == QB_LOG_SYSLOG) { /* No tracing to syslog */ + if(cs->priority <= LOG_NOTICE && cs->priority <= crm_log_level) { + qb_bit_set(cs->targets, source); + } + /* Tracing options... */ + } else if(source == QB_LOG_BLACKBOX && blackbox_tracing_enabled) { + qb_bit_set(cs->targets, source); + } else if (cs->priority <= crm_log_level) { + qb_bit_set(cs->targets, source); + } else if(trace_files && strstr(trace_files, cs->filename) != NULL) { + qb_bit_set(cs->targets, source); + } else if(trace_fns && strstr(trace_fns, cs->function) != NULL) { + qb_bit_set(cs->targets, source); + } else if(trace_fmts && strstr(trace_fmts, cs->format) != NULL) { + qb_bit_set(cs->targets, source); + } else if(trace_tags && cs->tags != 0 && g_quark_to_string(cs->tags) != NULL) { + qb_bit_set(cs->targets, source); + } +} + +static void +crm_log_filter(struct qb_log_callsite *cs) +{ + int lpc = 0; + static int need_init = 1; + static const char *trace_fns = NULL; + static const char *trace_tags = NULL; + static const char *trace_fmts = NULL; + static const char *trace_files = NULL; + + if(need_init) { + need_init = 0; + trace_fns = getenv("PCMK_trace_functions"); + trace_fmts = getenv("PCMK_trace_formats"); + trace_tags = getenv("PCMK_trace_tags"); + trace_files = getenv("PCMK_trace_files"); + + if (trace_tags != NULL) { + uint32_t tag; + char token[500]; + const char *offset = NULL; + const char *next = trace_tags; + + do { + offset = next; + next = strchrnul(offset, ','); + snprintf(token, 499, "%.*s", (int)(next - offset), offset); + + tag = g_quark_from_string(token); + crm_info("Created GQuark %u from token '%s' in '%s'", tag, token, trace_tags); + + if (next[0] != 0) { + next++; + } + + } while (next != NULL && next[0] != 0); + } + } + + cs->targets = 0; /* Reset then find targets to enable */ + for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) { + crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, cs); + } +} + +void +crm_update_callsites(void) +{ + crm_info("Enabling callsites based on priority=%d, files=%s, functions=%s, formats=%s, tags=%s", + crm_log_level, + getenv("PCMK_trace_files"), + getenv("PCMK_trace_functions"), + getenv("PCMK_trace_formats"), + getenv("PCMK_trace_tags")); + qb_log_filter_fn_set(crm_log_filter); +} + +static gboolean +crm_tracing_enabled(void) +{ + if(crm_log_level >= LOG_TRACE) { + return TRUE; + } else if(getenv("PCMK_trace_files") || getenv("PCMK_trace_functions") || getenv("PCMK_trace_formats") || getenv("PCMK_trace_tags")) { + return TRUE; + } + return FALSE; +} + +gboolean +crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, + int argc, char **argv, gboolean quiet) +{ + int lpc = 0; + const char *logfile = daemon_option("debugfile"); + const char *facility = daemon_option("logfacility"); + + /* Redirect messages from glib functions to our handler */ +#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER + glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL); +#endif + + /* and for good measure... - this enum is a bit field (!) */ + g_log_set_always_fatal((GLogLevelFlags) 0); /*value out of range */ + + if (facility == NULL) { + /* Set a default */ + facility = "daemon"; + } + + if (entity) { + crm_system_name = entity; + + } else if (argc > 0 && argv != NULL) { + char *mutable = crm_strdup(argv[0]); + + crm_system_name = basename(mutable); + if (strstr(crm_system_name, "lt-") == crm_system_name) { + crm_system_name += 3; + } + + } else if (crm_system_name == NULL) { + crm_system_name = "Unknown"; + } + + setenv("PCMK_service", crm_system_name, 1); + + if (daemon_option_enabled(crm_system_name, "debug")) { + /* Override the default setting */ + level = LOG_DEBUG; + } + + if (daemon_option_enabled(crm_system_name, "stderr")) { + /* Override the default setting */ + to_stderr = TRUE; + } + + crm_log_level = level; + qb_log_init(crm_system_name, qb_log_facility2int(facility), level); + qb_log_tags_stringify_fn_set(crm_quark_to_string); + + /* Set default format strings */ + for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) { + set_format_string(lpc, crm_system_name); + } + + if (quiet) { + /* Nuke any syslog activity */ + unsetenv("HA_logfacility"); + unsetenv("PCMK_logfacility"); + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); + + } else { + crm_log_args(argc, argv); + if(daemon) { + setenv("HA_logfacility", facility, TRUE); + setenv("PCMK_logfacility", facility, TRUE); + } + } + + if (daemon_option_enabled(crm_system_name, "blackbox")) { + crm_enable_blackbox(0); + } + + crm_enable_stderr(to_stderr); + + if(logfile) { + crm_add_logfile(logfile); + } + + if(daemon + && crm_tracing_enabled() + && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED + && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { + /* Make sure tracing goes somewhere */ + crm_add_logfile(NULL); + } + + crm_update_callsites(); + + /* Ok, now we can start logging... */ + + if (daemon) { + const char *user = getenv("USER"); + + if (user != NULL && safe_str_neq(user, "root") && safe_str_neq(user, CRM_DAEMON_USER)) { + crm_trace("Not switching to corefile directory for %s", user); + daemon = FALSE; + } + } + + if (daemon) { + int user = getuid(); + const char *base = CRM_CORE_DIR; + struct passwd *pwent = getpwuid(user); + + if (pwent == NULL) { + crm_perror(LOG_ERR, "Cannot get name for uid: %d", user); + + } else if (safe_str_neq(pwent->pw_name, "root") + && safe_str_neq(pwent->pw_name, "nobody") + && safe_str_neq(pwent->pw_name, CRM_DAEMON_USER)) { + crm_debug("Don't change active directory for regular user: %s", pwent->pw_name); + + } else if (chdir(base) < 0) { + crm_perror(LOG_ERR, "Cannot change active directory to %s", base); + + } else if (chdir(pwent->pw_name) < 0) { + crm_perror(LOG_ERR, "Cannot change active directory to %s/%s", base, pwent->pw_name); + } else { + crm_info("Changed active directory to %s/%s", base, pwent->pw_name); +#if 0 + { + char path[512]; + + snprintf(path, 512, "%s-%d", crm_system_name, getpid()); + mkdir(path, 0750); + chdir(path); + crm_info("Changed active directory to %s/%s/%s", base, pwent->pw_name, path); + } +#endif + } + mainloop_add_signal(SIGUSR1, crm_enable_blackbox); + } + + return TRUE; +} + +/* returns the old value */ +unsigned int +set_crm_log_level(unsigned int level) +{ + unsigned int old = crm_log_level; + crm_log_level = level; + crm_update_callsites(); + crm_info("New log level: %d", level); + return old; +} + +void +crm_enable_stderr(int enable) +{ + if (enable && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { + qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); + crm_update_callsites(); + + } else if (enable == FALSE) { + qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE); + } +} + +void +crm_bump_log_level(void) +{ + if (qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) { + set_crm_log_level(crm_log_level + 1); + } + crm_enable_stderr(TRUE); +} + +unsigned int +get_crm_log_level(void) +{ + return crm_log_level; +} + +void +crm_log_args(int argc, char **argv) +{ + int lpc = 0; + int len = 0; + int existing_len = 0; + char *arg_string = NULL; + + if (argc == 0 || argv == NULL) { + return; + } + + for (; lpc < argc; lpc++) { + if (argv[lpc] == NULL) { + break; + } + + len = 2 + strlen(argv[lpc]); /* +1 space, +1 EOS */ + arg_string = realloc(arg_string, len + existing_len); + existing_len += sprintf(arg_string + existing_len, "%s ", argv[lpc]); + } + do_crm_log_always(LOG_NOTICE, "Invoked: %s", arg_string); + free(arg_string); +} diff --git a/lib/common/utils.c b/lib/common/utils.c index 89e4a28b78..f00657f00b 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -1,2941 +1,2302 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#if HAVE_HB_CONFIG_H -# include /* for HA_COREDIR */ -#endif - -#if HAVE_GLUE_CONFIG_H -# include /* for HA_COREDIR */ -#endif - #ifndef MAXLINE # define MAXLINE 512 #endif #ifdef HAVE_GETOPT_H # include #endif #ifndef PW_BUFFER_LEN # define PW_BUFFER_LEN 500 #endif CRM_TRACE_INIT_DATA(common); static uint ref_counter = 0; gboolean crm_config_error = FALSE; gboolean crm_config_warning = FALSE; const char *crm_system_name = "unknown"; int node_score_red = 0; int node_score_green = 0; int node_score_yellow = 0; int node_score_infinity = INFINITY; -unsigned int crm_log_level = LOG_INFO; - -static gboolean crm_tracing_enabled(void); gboolean check_time(const char *value) { if (crm_get_msec(value) < 5000) { return FALSE; } return TRUE; } gboolean check_timer(const char *value) { if (crm_get_msec(value) < 0) { return FALSE; } return TRUE; } gboolean check_boolean(const char *value) { int tmp = FALSE; if (crm_str_to_boolean(value, &tmp) != 1) { return FALSE; } return TRUE; } gboolean check_number(const char *value) { errno = 0; if (value == NULL) { return FALSE; } else if (safe_str_eq(value, MINUS_INFINITY_S)) { } else if (safe_str_eq(value, INFINITY_S)) { } else { crm_int_helper(value, NULL); } if (errno != 0) { return FALSE; } return TRUE; } int char2score(const char *score) { int score_f = 0; if (score == NULL) { } else if (safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -node_score_infinity; } else if (safe_str_eq(score, INFINITY_S)) { score_f = node_score_infinity; } else if (safe_str_eq(score, "+" INFINITY_S)) { score_f = node_score_infinity; } else if (safe_str_eq(score, "red")) { score_f = node_score_red; } else if (safe_str_eq(score, "yellow")) { score_f = node_score_yellow; } else if (safe_str_eq(score, "green")) { score_f = node_score_green; } else { score_f = crm_parse_int(score, NULL); if (score_f > 0 && score_f > node_score_infinity) { score_f = node_score_infinity; } else if (score_f < 0 && score_f < -node_score_infinity) { score_f = -node_score_infinity; } } return score_f; } char * score2char(int score) { if (score >= node_score_infinity) { return crm_strdup(INFINITY_S); } else if (score <= -node_score_infinity) { return crm_strdup("-" INFINITY_S); } return crm_itoa(score); } const char * cluster_option(GHashTable * options, gboolean(*validate) (const char *), const char *name, const char *old_name, const char *def_value) { const char *value = NULL; CRM_ASSERT(name != NULL); if (options != NULL) { value = g_hash_table_lookup(options, name); } if (value == NULL && old_name && options != NULL) { value = g_hash_table_lookup(options, old_name); if (value != NULL) { crm_config_warn("Using deprecated name '%s' for" " cluster option '%s'", old_name, name); g_hash_table_insert(options, crm_strdup(name), crm_strdup(value)); value = g_hash_table_lookup(options, old_name); } } if (value == NULL) { crm_trace("Using default value '%s' for cluster option '%s'", def_value, name); if (options == NULL) { return def_value; } g_hash_table_insert(options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } if (validate && validate(value) == FALSE) { crm_config_err("Value '%s' for cluster option '%s' is invalid." " Defaulting to %s", value, name, def_value); g_hash_table_replace(options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } return value; } const char * get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name) { int lpc = 0; const char *value = NULL; gboolean found = FALSE; for (lpc = 0; lpc < len; lpc++) { if (safe_str_eq(name, option_list[lpc].name)) { found = TRUE; value = cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } CRM_CHECK(found, crm_err("No option named: %s", name)); CRM_ASSERT(value != NULL); return value; } void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option * option_list, int len) { int lpc = 0; fprintf(stdout, "" "\n" "\n" " %s\n" " %s\n" " %s\n" " \n", name, version, desc_long, desc_short); for (lpc = 0; lpc < len; lpc++) { if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) { continue; } fprintf(stdout, " \n" " %s\n" " \n" " %s%s%s\n" " \n", option_list[lpc].name, option_list[lpc].description_short, option_list[lpc].type, option_list[lpc].default_value, option_list[lpc]. description_long ? option_list[lpc].description_long : option_list[lpc]. description_short, option_list[lpc].values ? " Allowed values: " : "", option_list[lpc].values ? option_list[lpc].values : ""); } fprintf(stdout, " \n\n"); } void verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len) { int lpc = 0; for (lpc = 0; lpc < len; lpc++) { cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } char * generateReference(const char *custom1, const char *custom2) { const char *local_cust1 = custom1; const char *local_cust2 = custom2; int reference_len = 4; char *since_epoch = NULL; reference_len += 20; /* too big */ reference_len += 40; /* too big */ if (local_cust1 == NULL) { local_cust1 = "_empty_"; } reference_len += strlen(local_cust1); if (local_cust2 == NULL) { local_cust2 = "_empty_"; } reference_len += strlen(local_cust2); since_epoch = calloc(1, reference_len); if (since_epoch != NULL) { sprintf(since_epoch, "%s-%s-%ld-%u", local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++); } return since_epoch; } gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value) { int lpc = 0; int len = 0; const char *temp = NULL; CRM_ASSERT(name != NULL && value != NULL); *name = NULL; *value = NULL; crm_trace("Attempting to decode: [%s]", srcstring); if (srcstring != NULL) { len = strlen(srcstring); while (lpc <= len) { if (srcstring[lpc] == separator) { *name = calloc(1, lpc + 1); if (*name == NULL) { break; /* and return FALSE */ } memcpy(*name, srcstring, lpc); (*name)[lpc] = '\0'; /* this sucks but as the strtok manpage says.. * it *is* a bug */ len = len - lpc; len--; if (len <= 0) { *value = NULL; } else { *value = calloc(1, len + 1); if (*value == NULL) { free(*name); break; /* and return FALSE */ } temp = srcstring + lpc + 1; memcpy(*value, temp, len); (*value)[len] = '\0'; } return TRUE; } lpc++; } } if (*name != NULL) { free(*name); } *name = NULL; *value = NULL; return FALSE; } char * crm_concat(const char *prefix, const char *suffix, char join) { int len = 0; char *new_str = NULL; CRM_ASSERT(prefix != NULL); CRM_ASSERT(suffix != NULL); len = strlen(prefix) + strlen(suffix) + 2; new_str = calloc(1, (len)); sprintf(new_str, "%s%c%s", prefix, join, suffix); new_str[len - 1] = 0; return new_str; } char * generate_hash_key(const char *crm_msg_reference, const char *sys) { char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_'); crm_trace("created hash key: (%s)", hash_key); return hash_key; } char * generate_hash_value(const char *src_node, const char *src_subsys) { char *hash_value = NULL; if (src_node == NULL || src_subsys == NULL) { return NULL; } if (strcasecmp(CRM_SYSTEM_DC, src_subsys) == 0) { hash_value = crm_strdup(src_subsys); CRM_ASSERT(hash_value); return hash_value; } hash_value = crm_concat(src_node, src_subsys, '_'); crm_info("created hash value: (%s)", hash_value); return hash_value; } char * crm_itoa(int an_int) { int len = 32; char *buffer = NULL; buffer = calloc(1, (len + 1)); if (buffer != NULL) { snprintf(buffer, len, "%d", an_int); } return buffer; } -#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER -GLogFunc glib_log_default; - -static void -crm_glib_handler(const gchar * log_domain, GLogLevelFlags flags, const gchar * message, - gpointer user_data) -{ - int log_level = LOG_WARNING; - GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK); - - switch (msg_level) { - case G_LOG_LEVEL_CRITICAL: - /* log and record how we got here */ - crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, message, TRUE, TRUE); - return; - - case G_LOG_LEVEL_ERROR: - log_level = LOG_ERR; - break; - case G_LOG_LEVEL_MESSAGE: - log_level = LOG_NOTICE; - break; - case G_LOG_LEVEL_INFO: - log_level = LOG_INFO; - break; - case G_LOG_LEVEL_DEBUG: - log_level = LOG_DEBUG; - break; - - case G_LOG_LEVEL_WARNING: - case G_LOG_FLAG_RECURSION: - case G_LOG_FLAG_FATAL: - case G_LOG_LEVEL_MASK: - log_level = LOG_WARNING; - break; - } - - do_crm_log(log_level, "%s: %s", log_domain, message); -} -#endif int crm_user_lookup(const char *name, uid_t * uid, gid_t * gid) { int rc = -1; char *buffer = NULL; struct passwd pwd; struct passwd *pwentry = NULL; buffer = calloc(1, PW_BUFFER_LEN); getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry); if (pwentry) { rc = 0; if (uid) { *uid = pwentry->pw_uid; } if (gid) { *gid = pwentry->pw_gid; } crm_trace("Cluster user %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid); } else { crm_err("Cluster user %s does not exist", name); } free(buffer); return rc; } -void -crm_log_deinit(void) -{ -#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER - g_log_set_default_handler(glib_log_default, NULL); -#endif -} - -#define FMT_MAX 256 -static void -set_format_string(int method, const char *daemon) -{ - int offset = 0; - char fmt[FMT_MAX]; - - if (method > QB_LOG_STDERR) { - /* When logging to a file */ - struct utsname res; - - if (uname(&res) == 0) { - offset += - snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %s %10s: ", getpid(), - res.nodename, daemon); - } else { - offset += snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %10s: ", getpid(), daemon); - } - } - - if (crm_tracing_enabled() && method >= QB_LOG_STDERR) { - offset += snprintf(fmt + offset, FMT_MAX - offset, "(%%-12f:%%5l %%g) %%-7p: %%n: "); - } else { - offset += snprintf(fmt + offset, FMT_MAX - offset, "%%g %%-7p: %%n: "); - } - - if (method == QB_LOG_SYSLOG) { - offset += snprintf(fmt + offset, FMT_MAX - offset, "%%b"); - } else { - offset += snprintf(fmt + offset, FMT_MAX - offset, "\t%%b"); - } - qb_log_format_set(method, fmt); -} - -gboolean -crm_add_logfile(const char *filename) -{ - struct stat parent; - int fd = 0, rc = 0; - FILE *logfile = NULL; - char *parent_dir = NULL; - - static gboolean have_logfile = FALSE; - - if(filename == NULL && have_logfile == FALSE) { - filename = "/var/log/pacemaker.log"; - } - - if (filename == NULL) { - return FALSE; /* Nothing to do */ - } - - /* Check the parent directory and attempt to open */ - parent_dir = dirname(strdup(filename)); - rc = stat(parent_dir, &parent); - - if (rc != 0) { - crm_err("Directory '%s' does not exist: logging to '%s' is disabled", parent_dir, filename); - return FALSE; - - } else if (parent.st_uid == geteuid() && (parent.st_mode & (S_IRUSR | S_IWUSR))) { - /* all good - user */ - logfile = fopen(filename, "a"); - - } else if (parent.st_gid == getegid() && (parent.st_mode & S_IXGRP)) { - /* all good - group */ - logfile = fopen(filename, "a"); - - } else { - crm_err("We (uid=%u, gid=%u) do not have permission to access '%s': logging to '%s' is disabled", - geteuid(), getegid(), parent_dir, filename); - return FALSE; - } - - /* Check/Set permissions if we're root */ - if(logfile && geteuid() == 0) { - struct stat st; - uid_t pcmk_uid = 0; - gid_t pcmk_gid = 0; - gboolean fix = FALSE; - int logfd = fileno(logfile); - - rc = fstat(logfd, &st); - if(rc < 0) { - crm_perror(LOG_WARNING, "Cannot stat %s", filename); - return FALSE; - } - - crm_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid); - if(st.st_gid != pcmk_gid) { - /* Wrong group */ - fix = TRUE; - } else if((st.st_mode & S_IRWXG) != (S_IRGRP|S_IWGRP)) { - /* Not read/writable by the correct group */ - fix = TRUE; - } - - if(fix) { - rc = fchown(logfd, pcmk_uid, pcmk_gid); - if(rc < 0) { - crm_warn("Cannot change the ownership of %s to user %s and gid %d", - filename, CRM_DAEMON_USER, pcmk_gid); - } - - rc = fchmod(logfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if(rc < 0) { - crm_warn("Cannot change the mode of %s to rw-rw----", filename); - } - - fprintf(logfile, "Set r/w permissions for uid=%d, gid=%d on %s\n", - pcmk_uid, pcmk_gid, filename); - if(fflush(logfile) < 0 || fsync(logfd) < 0) { - crm_err("Couldn't write out logfile: %s", filename); - } - } - fclose(logfile); - } - - /* Now open with libqb */ - fd = qb_log_file_open(filename); - - if(fd < 0) { - crm_perror(LOG_WARNING, "Couldn't send additional logging to %s", filename); - return FALSE; - } - - crm_notice("Additional logging available in %s", filename); - qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_TRUE); - - /* Enable callsites */ - crm_update_callsites(); - have_logfile = TRUE; - return TRUE; -} - -#ifndef NAME_MAX -# define NAME_MAX 256 -#endif -static const char * -daemon_option(const char *option) -{ - char env_name[NAME_MAX]; - const char *value = NULL; - - snprintf(env_name, NAME_MAX, "PCMK_%s", option); - value = getenv(env_name); - if (value != NULL) { - return value; - } - - snprintf(env_name, NAME_MAX, "HA_%s", option); - value = getenv(env_name); - if (value != NULL) { - return value; - } - - return NULL; -} - -static gboolean -daemon_option_enabled(const char *daemon, const char *option) -{ - const char *value = daemon_option(option); - if (value != NULL && crm_is_true(value)) { - return TRUE; - - } else if (value != NULL && strstr(value, daemon)) { - return TRUE; - } - - return FALSE; -} - -static char *blackbox_file_prefix = NULL; -static gboolean blackbox_tracing_enabled = FALSE; - -void -crm_enable_blackbox_tracing(int nsig) -{ - - if(blackbox_tracing_enabled) { - blackbox_tracing_enabled = FALSE; - } else { - blackbox_tracing_enabled = TRUE; - } - crm_update_callsites(); - crm_debug("Blackbox tracing is %s", blackbox_tracing_enabled?"on":"off"); -} - -void -crm_enable_blackbox(int nsig) -{ - if(blackbox_file_prefix == NULL) { - pid_t pid = getpid(); - - blackbox_file_prefix = malloc(NAME_MAX); - snprintf(blackbox_file_prefix, NAME_MAX, "%s/blackbox-%s-%d", CRM_BLACKBOX_DIR, crm_system_name, pid); - } - - if (qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { - qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*1024); /* Any size change drops existing entries */ - qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); /* Setting the size seems to disable it */ - - crm_notice("Initiated blackbox recorder: %s", blackbox_file_prefix); - crm_signal(SIGSEGV, crm_write_blackbox); - crm_update_callsites(); - - /* Original meanings from signal(7) - * - * Signal Value Action Comment - * SIGPROF 27,27,29 Term Profiling timer expired - * SIGTRAP 5 Core Trace/breakpoint trap - * - * Our usage is as similar as possible - */ - mainloop_add_signal(SIGPROF, crm_enable_blackbox_tracing); - mainloop_add_signal(SIGTRAP, crm_write_blackbox); - } -} - -void -crm_write_blackbox(int nsig) -{ - static int counter = 1; - static time_t last = 0; - - char buffer[NAME_MAX]; - time_t now = time(NULL); - - if(blackbox_file_prefix == NULL) { - return; - } - - switch(nsig) { - case 0: - case SIGTRAP: - /* The graceful case - such as assertion failure or user request */ - snprintf(buffer, NAME_MAX, "%s.%d", blackbox_file_prefix, counter++); - - if(nsig == 0 && (now - last) < 2) { - /* Prevent over-dumping */ - return; - - } else if(nsig == SIGTRAP) { - crm_notice("Blackbox dump requested, please see %s for contents", buffer); - - } else { - crm_notice("Problem detected, please see %s for additional details", buffer); - } - last = now; - qb_log_blackbox_write_to_file(buffer); - - /* Flush the existing contents - * A size change would also work - */ - qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE); - qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); - break; - - default: - /* Do as little as possible, just try to get what we have out - * We logged the filename when the blackbox was enabled - */ - crm_signal(nsig, SIG_DFL); - qb_log_blackbox_write_to_file(blackbox_file_prefix); - qb_log_fini(); - raise(nsig); - break; - } -} - -gboolean -crm_log_cli_init(const char *entity) -{ - return crm_log_init(entity, LOG_ERR, FALSE, FALSE, 0, NULL, TRUE); -} - -static const char *crm_quark_to_string(uint32_t tag) -{ - const char *text = g_quark_to_string(tag); - if(text) { - return text; - } - return ""; -} - -static void -crm_log_filter_source(int source, const char *trace_files, const char *trace_fns, const char *trace_fmts, const char *trace_tags, struct qb_log_callsite *cs) -{ - if (qb_log_ctl(source, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { - return; - } else if (source == QB_LOG_SYSLOG) { /* No tracing to syslog */ - if(cs->priority <= LOG_NOTICE && cs->priority <= crm_log_level) { - qb_bit_set(cs->targets, source); - } - /* Tracing options... */ - } else if(source == QB_LOG_BLACKBOX && blackbox_tracing_enabled) { - qb_bit_set(cs->targets, source); - } else if (cs->priority <= crm_log_level) { - qb_bit_set(cs->targets, source); - } else if(trace_files && strstr(trace_files, cs->filename) != NULL) { - qb_bit_set(cs->targets, source); - } else if(trace_fns && strstr(trace_fns, cs->function) != NULL) { - qb_bit_set(cs->targets, source); - } else if(trace_fmts && strstr(trace_fmts, cs->format) != NULL) { - qb_bit_set(cs->targets, source); - } else if(trace_tags && cs->tags != 0 && g_quark_to_string(cs->tags) != NULL) { - qb_bit_set(cs->targets, source); - } -} - -static void -crm_log_filter(struct qb_log_callsite *cs) -{ - int lpc = 0; - static int need_init = 1; - static const char *trace_fns = NULL; - static const char *trace_tags = NULL; - static const char *trace_fmts = NULL; - static const char *trace_files = NULL; - - if(need_init) { - need_init = 0; - trace_fns = getenv("PCMK_trace_functions"); - trace_fmts = getenv("PCMK_trace_formats"); - trace_tags = getenv("PCMK_trace_tags"); - trace_files = getenv("PCMK_trace_files"); - - if (trace_tags != NULL) { - uint32_t tag; - char token[500]; - const char *offset = NULL; - const char *next = trace_tags; - - do { - offset = next; - next = strchrnul(offset, ','); - snprintf(token, 499, "%.*s", (int)(next - offset), offset); - - tag = g_quark_from_string(token); - crm_info("Created GQuark %u from token '%s' in '%s'", tag, token, trace_tags); - - if (next[0] != 0) { - next++; - } - - } while (next != NULL && next[0] != 0); - } - } - - cs->targets = 0; /* Reset then find targets to enable */ - for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) { - crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, cs); - } -} - -void -crm_update_callsites(void) -{ - crm_notice("Enabling callsites based on priority=%d, files=%s, functions=%s, formats=%s, tags=%s", - crm_log_level, - getenv("PCMK_trace_files"), - getenv("PCMK_trace_functions"), - getenv("PCMK_trace_formats"), - getenv("PCMK_trace_tags")); - qb_log_filter_fn_set(crm_log_filter); -} - -static gboolean -crm_tracing_enabled(void) -{ - if(crm_log_level >= LOG_TRACE) { - return TRUE; - } else if(getenv("PCMK_trace_files") || getenv("PCMK_trace_functions") || getenv("PCMK_trace_formats") || getenv("PCMK_trace_tags")) { - return TRUE; - } - return FALSE; -} - -gboolean -crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr, - int argc, char **argv, gboolean quiet) -{ - int lpc = 0; - const char *logfile = daemon_option("debugfile"); - const char *facility = daemon_option("logfacility"); - - /* Redirect messages from glib functions to our handler */ -#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER - glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL); -#endif - - /* and for good measure... - this enum is a bit field (!) */ - g_log_set_always_fatal((GLogLevelFlags) 0); /*value out of range */ - - if (facility == NULL) { - /* Set a default */ - facility = "daemon"; - } - - if (entity) { - crm_system_name = entity; - - } else if (argc > 0 && argv != NULL) { - char *mutable = crm_strdup(argv[0]); - - crm_system_name = basename(mutable); - if (strstr(crm_system_name, "lt-") == crm_system_name) { - crm_system_name += 3; - } - - } else if (crm_system_name == NULL) { - crm_system_name = "Unknown"; - } - - setenv("PCMK_service", crm_system_name, 1); - - if (daemon_option_enabled(crm_system_name, "debug")) { - /* Override the default setting */ - level = LOG_DEBUG; - } - - if (daemon_option_enabled(crm_system_name, "stderr")) { - /* Override the default setting */ - to_stderr = TRUE; - } - - crm_log_level = level; - qb_log_init(crm_system_name, qb_log_facility2int(facility), level); - qb_log_tags_stringify_fn_set(crm_quark_to_string); - - /* Set default format strings */ - for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) { - set_format_string(lpc, crm_system_name); - } - - if (quiet) { - /* Nuke any syslog activity */ - unsetenv("HA_logfacility"); - unsetenv("PCMK_logfacility"); - qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); - - } else { - crm_log_args(argc, argv); - if(daemon) { - setenv("HA_logfacility", facility, TRUE); - setenv("PCMK_logfacility", facility, TRUE); - } - } - - if (daemon_option_enabled(crm_system_name, "blackbox")) { - crm_enable_blackbox(0); - } - - crm_enable_stderr(to_stderr); - - if(logfile) { - crm_add_logfile(logfile); - } - - if(daemon - && crm_tracing_enabled() - && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED - && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { - /* Make sure tracing goes somewhere */ - crm_add_logfile(NULL); - } - - crm_update_callsites(); - - /* Ok, now we can start logging... */ - - if (daemon) { - const char *user = getenv("USER"); - - if (user != NULL && safe_str_neq(user, "root") && safe_str_neq(user, CRM_DAEMON_USER)) { - crm_trace("Not switching to corefile directory for %s", user); - daemon = FALSE; - } - } - - if (daemon) { - int user = getuid(); - const char *base = HA_COREDIR; - struct passwd *pwent = getpwuid(user); - - if (pwent == NULL) { - crm_perror(LOG_ERR, "Cannot get name for uid: %d", user); - - } else if (safe_str_neq(pwent->pw_name, "root") - && safe_str_neq(pwent->pw_name, "nobody") - && safe_str_neq(pwent->pw_name, CRM_DAEMON_USER)) { - crm_debug("Don't change active directory for regular user: %s", pwent->pw_name); - - } else if (chdir(base) < 0) { - crm_perror(LOG_ERR, "Cannot change active directory to %s", base); - - } else if (chdir(pwent->pw_name) < 0) { - crm_perror(LOG_ERR, "Cannot change active directory to %s/%s", base, pwent->pw_name); - } else { - crm_info("Changed active directory to %s/%s", base, pwent->pw_name); -#if 0 - { - char path[512]; - - snprintf(path, 512, "%s-%d", crm_system_name, getpid()); - mkdir(path, 0750); - chdir(path); - crm_info("Changed active directory to %s/%s/%s", base, pwent->pw_name, path); - } -#endif - } - mainloop_add_signal(SIGUSR1, crm_enable_blackbox); - } - - return TRUE; -} - -/* returns the old value */ -unsigned int -set_crm_log_level(unsigned int level) -{ - unsigned int old = crm_log_level; - crm_log_level = level; - crm_update_callsites(); - crm_info("New log level: %d", level); - return old; -} - -void -crm_enable_stderr(int enable) -{ - if (enable && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) { - qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); - crm_update_callsites(); - - } else if (enable == FALSE) { - qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE); - } -} - -void -crm_bump_log_level(void) -{ - if (qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) { - set_crm_log_level(crm_log_level + 1); - } - crm_enable_stderr(TRUE); -} - -unsigned int -get_crm_log_level(void) -{ - return crm_log_level; -} static int crm_version_helper(const char *text, char **end_text) { int atoi_result = -1; CRM_ASSERT(end_text != NULL); errno = 0; if (text != NULL && text[0] != 0) { atoi_result = (int)strtol(text, end_text, 10); if (errno == EINVAL) { crm_err("Conversion of '%s' %c failed", text, text[0]); atoi_result = -1; } } return atoi_result; } -void -crm_log_args(int argc, char **argv) -{ - int lpc = 0; - int len = 0; - int existing_len = 0; - char *arg_string = NULL; - - if (argc == 0 || argv == NULL) { - return; - } - - for (; lpc < argc; lpc++) { - if (argv[lpc] == NULL) { - break; - } - - len = 2 + strlen(argv[lpc]); /* +1 space, +1 EOS */ - arg_string = realloc(arg_string, len + existing_len); - existing_len += sprintf(arg_string + existing_len, "%s ", argv[lpc]); - } - do_crm_log_always(LOG_INFO, "Invoked: %s", arg_string); - free(arg_string); -} - /* * version1 < version2 : -1 * version1 = version2 : 0 * version1 > version2 : 1 */ int compare_version(const char *version1, const char *version2) { int rc = 0; int lpc = 0; char *ver1_copy = NULL, *ver2_copy = NULL; char *rest1 = NULL, *rest2 = NULL; if (version1 == NULL && version2 == NULL) { return 0; } else if (version1 == NULL) { return -1; } else if (version2 == NULL) { return 1; } ver1_copy = crm_strdup(version1); ver2_copy = crm_strdup(version2); rest1 = ver1_copy; rest2 = ver2_copy; while (1) { int digit1 = 0; int digit2 = 0; lpc++; if (rest1 == rest2) { break; } if (rest1 != NULL) { digit1 = crm_version_helper(rest1, &rest1); } if (rest2 != NULL) { digit2 = crm_version_helper(rest2, &rest2); } if (digit1 < digit2) { rc = -1; crm_trace("%d < %d", digit1, digit2); break; } else if (digit1 > digit2) { rc = 1; crm_trace("%d > %d", digit1, digit2); break; } if (rest1 != NULL && rest1[0] == '.') { rest1++; } if (rest1 != NULL && rest1[0] == 0) { rest1 = NULL; } if (rest2 != NULL && rest2[0] == '.') { rest2++; } if (rest2 != NULL && rest2[0] == 0) { rest2 = NULL; } } free(ver1_copy); free(ver2_copy); if (rc == 0) { crm_trace("%s == %s (%d)", version1, version2, lpc); } else if (rc < 0) { crm_trace("%s < %s (%d)", version1, version2, lpc); } else if (rc > 0) { crm_trace("%s > %s (%d)", version1, version2, lpc); } return rc; } gboolean do_stderr = FALSE; void g_hash_destroy_str(gpointer data) { free(data); } #include /* #include */ /* #include */ long long crm_int_helper(const char *text, char **end_text) { long long result = -1; char *local_end_text = NULL; int saved_errno = 0; errno = 0; if (text != NULL) { #ifdef ANSI_ONLY if (end_text != NULL) { result = strtol(text, end_text, 10); } else { result = strtol(text, &local_end_text, 10); } #else if (end_text != NULL) { result = strtoll(text, end_text, 10); } else { result = strtoll(text, &local_end_text, 10); } #endif saved_errno = errno; /* CRM_CHECK(errno != EINVAL); */ if (errno == EINVAL) { crm_err("Conversion of %s failed", text); result = -1; } else if (errno == ERANGE) { crm_err("Conversion of %s was clipped: %lld", text, result); } else if (errno != 0) { crm_perror(LOG_ERR, "Conversion of %s failed:", text); } if (local_end_text != NULL && local_end_text[0] != '\0') { crm_err("Characters left over after parsing '%s': '%s'", text, local_end_text); } errno = saved_errno; } return result; } int crm_parse_int(const char *text, const char *default_text) { int atoi_result = -1; if (text != NULL) { atoi_result = crm_int_helper(text, NULL); if (errno == 0) { return atoi_result; } } if (default_text != NULL) { atoi_result = crm_int_helper(default_text, NULL); if (errno == 0) { return atoi_result; } } else { crm_err("No default conversion value supplied"); } return -1; } gboolean safe_str_neq(const char *a, const char *b) { if (a == b) { return FALSE; } else if (a == NULL || b == NULL) { return TRUE; } else if (strcasecmp(a, b) == 0) { return FALSE; } return TRUE; } char * crm_strdup_fn(const char *src, const char *file, const char *fn, int line) { char *dup = NULL; CRM_CHECK(src != NULL, crm_err("Could not perform copy at %s:%d (%s)", file, line, fn); return NULL); dup = calloc(1, strlen(src) + 1); return strcpy(dup, src); } gboolean crm_is_true(const char *s) { gboolean ret = FALSE; if (s != NULL) { crm_str_to_boolean(s, &ret); } return ret; } int crm_str_to_boolean(const char *s, int *ret) { if (s == NULL) { return -1; } else if (strcasecmp(s, "true") == 0 || strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) { *ret = TRUE; return 1; } else if (strcasecmp(s, "false") == 0 || strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) { *ret = FALSE; return 1; } return -1; } #ifndef NUMCHARS # define NUMCHARS "0123456789." #endif #ifndef WHITESPACE # define WHITESPACE " \t\n\r\f" #endif unsigned long long crm_get_interval(const char *input) { ha_time_t *interval = NULL; char *input_copy = crm_strdup(input); char *input_copy_mutable = input_copy; unsigned long long msec = 0; if (input == NULL) { return 0; } else if (input[0] != 'P') { free(input_copy); return crm_get_msec(input); } interval = parse_time_duration(&input_copy_mutable); msec = date_in_seconds(interval); free_ha_date(interval); free(input_copy); return msec * 1000; } long long crm_get_msec(const char *input) { const char *cp = input; const char *units; long long multiplier = 1000; long long divisor = 1; long long msec = -1; char *end_text = NULL; /* double dret; */ if (input == NULL) { return msec; } cp += strspn(cp, WHITESPACE); units = cp + strspn(cp, NUMCHARS); units += strspn(units, WHITESPACE); if (strchr(NUMCHARS, *cp) == NULL) { return msec; } if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) { multiplier = 1; divisor = 1; } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) { multiplier = 1; divisor = 1000; } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) { multiplier = 1000; divisor = 1; } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) { multiplier = 60 * 1000; divisor = 1; } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) { multiplier = 60 * 60 * 1000; divisor = 1; } else if (*units != EOS && *units != '\n' && *units != '\r') { return msec; } msec = crm_int_helper(cp, &end_text); msec *= multiplier; msec /= divisor; /* dret += 0.5; */ /* msec = (long long)dret; */ return msec; } char * generate_op_key(const char *rsc_id, const char *op_type, int interval) { int len = 35; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); op_id = calloc(1, len); CRM_CHECK(op_id != NULL, return NULL); sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval); return op_id; } gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval) { char *notify = NULL; char *mutable_key = NULL; char *mutable_key_ptr = NULL; int len = 0, offset = 0, ch = 0; CRM_CHECK(key != NULL, return FALSE); *interval = 0; len = strlen(key); offset = len - 1; crm_trace("Source: %s", key); while (offset > 0 && isdigit(key[offset])) { int digits = len - offset; ch = key[offset] - '0'; CRM_CHECK(ch < 10, return FALSE); CRM_CHECK(ch >= 0, return FALSE); while (digits > 1) { digits--; ch = ch * 10; } *interval += ch; offset--; } crm_trace(" Interval: %d", *interval); CRM_CHECK(key[offset] == '_', return FALSE); mutable_key = crm_strdup(key); mutable_key_ptr = mutable_key_ptr; mutable_key[offset] = 0; offset--; while (offset > 0 && key[offset] != '_') { offset--; } CRM_CHECK(key[offset] == '_', free(mutable_key); return FALSE); mutable_key_ptr = mutable_key + offset + 1; crm_trace(" Action: %s", mutable_key_ptr); *op_type = crm_strdup(mutable_key_ptr); mutable_key[offset] = 0; offset--; CRM_CHECK(mutable_key != mutable_key_ptr, free(mutable_key); return FALSE); notify = strstr(mutable_key, "_post_notify"); if (safe_str_eq(notify, "_post_notify")) { notify[0] = 0; } notify = strstr(mutable_key, "_pre_notify"); if (safe_str_eq(notify, "_pre_notify")) { notify[0] = 0; } crm_trace(" Resource: %s", mutable_key); *rsc_id = mutable_key; return TRUE; } char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type) { int len = 12; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); CRM_CHECK(notify_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); len += strlen(notify_type); op_id = calloc(1, len); if (op_id != NULL) { sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type); } return op_id; } char * generate_transition_magic_v202(const char *transition_key, int op_status) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); fail_state = calloc(1, len); if (fail_state != NULL) { snprintf(fail_state, len, "%d:%s", op_status, transition_key); } return fail_state; } char * generate_transition_magic(const char *transition_key, int op_status, int op_rc) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); fail_state = calloc(1, len); if (fail_state != NULL) { snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key); } return fail_state; } gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc) { int res = 0; char *key = NULL; gboolean result = TRUE; CRM_CHECK(magic != NULL, return FALSE); CRM_CHECK(op_rc != NULL, return FALSE); CRM_CHECK(op_status != NULL, return FALSE); key = calloc(1, strlen(magic) + 1); res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key); if (res != 3) { crm_crit("Only found %d items in: %s", res, magic); result = FALSE; goto bail; } CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE; goto bail; ); bail: free(key); return result; } char * generate_transition_key(int transition_id, int action_id, int target_rc, const char *node) { int len = 40; char *fail_state = NULL; CRM_CHECK(node != NULL, return NULL); len += strlen(node); fail_state = calloc(1, len); if (fail_state != NULL) { snprintf(fail_state, len, "%d:%d:%d:%s", action_id, transition_id, target_rc, node); } return fail_state; } gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc) { int res = 0; gboolean done = FALSE; CRM_CHECK(uuid != NULL, return FALSE); CRM_CHECK(target_rc != NULL, return FALSE); CRM_CHECK(action_id != NULL, return FALSE); CRM_CHECK(transition_id != NULL, return FALSE); *uuid = calloc(1, strlen(key) + 1); res = sscanf(key, "%d:%d:%d:%s", action_id, transition_id, target_rc, *uuid); switch (res) { case 4: /* Post Pacemaker 0.6 */ done = TRUE; break; case 3: case 2: /* this can be tricky - the UUID might start with an integer */ /* Until Pacemaker 0.6 */ done = TRUE; *target_rc = -1; res = sscanf(key, "%d:%d:%s", action_id, transition_id, *uuid); if (res == 2) { *action_id = -1; res = sscanf(key, "%d:%s", transition_id, *uuid); CRM_CHECK(res == 2, done = FALSE); } else if (res != 3) { CRM_CHECK(res == 3, done = FALSE); } break; case 1: /* Prior to Heartbeat 2.0.8 */ done = TRUE; *action_id = -1; *target_rc = -1; res = sscanf(key, "%d:%s", transition_id, *uuid); CRM_CHECK(res == 2, done = FALSE); break; default: crm_crit("Unhandled sscanf result (%d) for %s", res, key); } if (strlen(*uuid) != 36) { crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key); } if (done == FALSE) { crm_err("Cannot decode '%s' rc=%d", key, res); free(*uuid); *uuid = NULL; *target_rc = -1; *action_id = -1; *transition_id = -1; } return done; } void filter_action_parameters(xmlNode * param_set, const char *version) { char *key = NULL; char *timeout = NULL; char *interval = NULL; const char *attr_filter[] = { XML_ATTR_ID, XML_ATTR_CRM_VERSION, XML_LRM_ATTR_OP_DIGEST, }; gboolean do_delete = FALSE; int lpc = 0; static int meta_len = 0; if (meta_len == 0) { meta_len = strlen(CRM_META); } if (param_set == NULL) { return; } for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) { xml_remove_prop(param_set, attr_filter[lpc]); } key = crm_meta_name(XML_LRM_ATTR_INTERVAL); interval = crm_element_value_copy(param_set, key); free(key); key = crm_meta_name(XML_ATTR_TIMEOUT); timeout = crm_element_value_copy(param_set, key); if (param_set) { xmlAttrPtr xIter = param_set->properties; while (xIter) { const char *prop_name = (const char *)xIter->name; xIter = xIter->next; do_delete = FALSE; if (strncasecmp(prop_name, CRM_META, meta_len) == 0) { do_delete = TRUE; } if (do_delete) { xml_remove_prop(param_set, prop_name); } } } if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) { /* Re-instate the operation's timeout value */ if (timeout != NULL) { crm_xml_add(param_set, key, timeout); } } free(interval); free(timeout); free(key); } void filter_reload_parameters(xmlNode * param_set, const char *restart_string) { int len = 0; char *name = NULL; char *match = NULL; if (param_set == NULL) { return; } if (param_set) { xmlAttrPtr xIter = param_set->properties; while (xIter) { const char *prop_name = (const char *)xIter->name; xIter = xIter->next; name = NULL; len = strlen(prop_name) + 3; name = calloc(1, len); sprintf(name, " %s ", prop_name); name[len - 1] = 0; match = strstr(restart_string, name); if (match == NULL) { crm_trace("%s not found in %s", prop_name, restart_string); xml_remove_prop(param_set, prop_name); } free(name); } } } void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_core, gboolean do_fork) { int rc = 0; int pid = 0; int status = 0; /* Implied by the parent's error logging below */ /* crm_write_blackbox(0); */ if (do_core == FALSE) { crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition); return; } else if (do_fork) { pid = fork(); } else { crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition); } switch (pid) { case -1: crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s", function, file, line, assert_condition); return; case 0: /* Child */ abort(); break; default: /* Parent */ crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s", function, pid, file, line, assert_condition); do { rc = waitpid(pid, &status, 0); if (rc < 0 && errno != EINTR) { crm_perror(LOG_ERR, "%s: Cannot wait on forked child %d", function, pid); } } while (rc < 0 && errno == EINTR); return; } } char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip) { int len = 40; char *filename = NULL; const char *ext = "raw"; CRM_CHECK(directory != NULL, return NULL); CRM_CHECK(series != NULL, return NULL); len += strlen(directory); len += strlen(series); filename = calloc(1, len); CRM_CHECK(filename != NULL, return NULL); if (bzip) { ext = "bz2"; } sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext); return filename; } int get_last_sequence(const char *directory, const char *series) { FILE *file_strm = NULL; int start = 0, length = 0, read_len = 0; char *series_file = NULL; char *buffer = NULL; int seq = 0; int len = 36; CRM_CHECK(directory != NULL, return 0); CRM_CHECK(series != NULL, return 0); len += strlen(directory); len += strlen(series); series_file = calloc(1, len); CRM_CHECK(series_file != NULL, return 0); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "r"); if (file_strm == NULL) { crm_debug("Series file %s does not exist", series_file); free(series_file); return 0; } /* see how big the file is */ start = ftell(file_strm); fseek(file_strm, 0L, SEEK_END); length = ftell(file_strm); fseek(file_strm, 0L, start); CRM_ASSERT(length >= 0); CRM_ASSERT(start == ftell(file_strm)); if (length <= 0) { crm_info("%s was not valid", series_file); free(buffer); buffer = NULL; } else { crm_trace("Reading %d bytes from file", length); buffer = calloc(1, (length + 1)); read_len = fread(buffer, 1, length, file_strm); if (read_len != length) { crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len); free(buffer); buffer = NULL; } } free(series_file); seq = crm_parse_int(buffer, "0"); free(buffer); fclose(file_strm); return seq; } void write_last_sequence(const char *directory, const char *series, int sequence, int max) { int rc = 0; int len = 36; FILE *file_strm = NULL; char *series_file = NULL; CRM_CHECK(directory != NULL, return); CRM_CHECK(series != NULL, return); if (max == 0) { return; } if (sequence >= max) { sequence = 0; } len += strlen(directory); len += strlen(series); series_file = calloc(1, len); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "w"); if (file_strm == NULL) { crm_err("Cannout open series file %s for writing", series_file); goto bail; } rc = fprintf(file_strm, "%d", sequence); if (rc < 0) { crm_perror(LOG_ERR, "Cannot write to series file %s", series_file); } bail: if (file_strm != NULL) { fflush(file_strm); fclose(file_strm); } free(series_file); } #define LOCKSTRLEN 11 int crm_pid_active(long pid) { if (pid <= 0) { return -1; } else if (kill(pid, 0) < 0 && errno == ESRCH) { return 0; } #ifndef HAVE_PROC_PID return 1; #else { int rc = 0; int running = 0; char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX]; /* check to make sure pid hasn't been reused by another process */ snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", pid); rc = readlink(proc_path, exe_path, PATH_MAX - 1); if (rc < 0) { crm_perror(LOG_ERR, "Could not read from %s", proc_path); goto bail; } exe_path[rc] = 0; snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", (long unsigned int)getpid()); rc = readlink(proc_path, myexe_path, PATH_MAX - 1); if (rc < 0) { crm_perror(LOG_ERR, "Could not read from %s", proc_path); goto bail; } myexe_path[rc] = 0; if (strcmp(exe_path, myexe_path) == 0) { running = 1; } } bail: return running; #endif } int crm_read_pidfile(const char *filename) { int fd; long pid = -1; char buf[LOCKSTRLEN + 1]; if ((fd = open(filename, O_RDONLY)) < 0) { goto bail; } if (read(fd, buf, sizeof(buf)) < 1) { goto bail; } if (sscanf(buf, "%lu", &pid) > 0) { if (pid <= 0) { pid = -LSB_STATUS_STOPPED; } } bail: if (fd >= 0) { close(fd); } return pid; } int crm_lock_pidfile(const char *filename) { struct stat sbuf; int fd = 0, rc = 0; long pid = 0, mypid = 0; char lf_name[256], tf_name[256], buf[LOCKSTRLEN + 1]; mypid = (unsigned long)getpid(); snprintf(lf_name, sizeof(lf_name), "%s", filename); snprintf(tf_name, sizeof(tf_name), "%s.%lu", filename, mypid); if ((fd = open(lf_name, O_RDONLY)) >= 0) { if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) { sleep(1); /* if someone was about to create one, * give'm a sec to do so * Though if they follow our protocol, * this won't happen. They should really * put the pid in, then link, not the * other way around. */ } if (read(fd, buf, sizeof(buf)) > 0) { if (sscanf(buf, "%lu", &pid) > 0) { if (pid > 1 && pid != getpid() && crm_pid_active(pid)) { /* locked by existing process - give up */ close(fd); return -1; } } } unlink(lf_name); close(fd); } if ((fd = open(tf_name, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) { /* Hmmh, why did we fail? Anyway, nothing we can do about it */ return -3; } /* Slight overkill with the %*d format ;-) */ snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid); if (write(fd, buf, LOCKSTRLEN) != LOCKSTRLEN) { /* Again, nothing we can do about this */ rc = -3; close(fd); goto out; } close(fd); switch (link(tf_name, lf_name)) { case 0: if (stat(tf_name, &sbuf) < 0) { /* something weird happened */ rc = -3; } else if (sbuf.st_nlink < 2) { /* somehow, it didn't get through - NFS trouble? */ rc = -2; } else { rc = 0; } break; case EEXIST: rc = -1; break; default: rc = -3; } out: unlink(tf_name); return rc; } void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile) { long pid; const char *devnull = "/dev/null"; if (daemonize == FALSE) { return; } pid = fork(); if (pid < 0) { fprintf(stderr, "%s: could not start daemon\n", name); crm_perror(LOG_ERR, "fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (crm_lock_pidfile(pidfile) < 0) { pid = crm_read_pidfile(pidfile); if (crm_pid_active(pid) > 0) { crm_warn("%s: already running [pid %ld] (%s).\n", name, pid, pidfile); exit(LSB_EXIT_OK); } } umask(022); close(STDIN_FILENO); (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ close(STDOUT_FILENO); (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ close(STDERR_FILENO); (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ } gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both) { int s_res = -1; struct stat buf; char *full_file = NULL; const char *target = NULL; gboolean pass = TRUE; gboolean readwritable = FALSE; CRM_ASSERT(dir != NULL); if (file != NULL) { full_file = crm_concat(dir, file, '/'); target = full_file; s_res = stat(full_file, &buf); if (s_res == 0 && S_ISREG(buf.st_mode) == FALSE) { crm_err("%s must be a regular file", target); pass = FALSE; goto out; } } if (s_res != 0) { target = dir; s_res = stat(dir, &buf); if (s_res != 0) { crm_err("%s must exist and be a directory", dir); pass = FALSE; goto out; } else if (S_ISDIR(buf.st_mode) == FALSE) { crm_err("%s must be a directory", dir); pass = FALSE; } } if (user) { struct passwd *sys_user = NULL; sys_user = getpwnam(user); readwritable = (sys_user != NULL && buf.st_uid == sys_user->pw_uid && (buf.st_mode & (S_IRUSR | S_IWUSR))); if (readwritable == FALSE) { crm_err("%s must be owned and r/w by user %s", target, user); if (need_both) { pass = FALSE; } } } if (group) { struct group *sys_grp = getgrnam(group); readwritable = (sys_grp != NULL && buf.st_gid == sys_grp->gr_gid && (buf.st_mode & (S_IRGRP | S_IWGRP))); if (readwritable == FALSE) { if (need_both || user == NULL) { pass = FALSE; crm_err("%s must be owned and r/w by group %s", target, group); } else { crm_warn("%s should be owned and r/w by group %s", target, group); } } } out: free(full_file); return pass; } gboolean crm_str_eq(const char *a, const char *b, gboolean use_case) { if (a == b) { return TRUE; } else if (a == NULL || b == NULL) { /* shouldn't be comparing NULLs */ return FALSE; } else if (use_case && a[0] != b[0]) { return FALSE; } else if (strcasecmp(a, b) == 0) { return TRUE; } return FALSE; } char * crm_meta_name(const char *field) { int lpc = 0; int max = 0; char *crm_name = NULL; CRM_CHECK(field != NULL, return NULL); crm_name = crm_concat(CRM_META, field, '_'); /* Massage the names so they can be used as shell variables */ max = strlen(crm_name); for (; lpc < max; lpc++) { switch (crm_name[lpc]) { case '-': crm_name[lpc] = '_'; break; } } return crm_name; } const char * crm_meta_value(GHashTable * hash, const char *field) { char *key = NULL; const char *value = NULL; key = crm_meta_name(field); if (key) { value = g_hash_table_lookup(hash, key); free(key); } return value; } static struct crm_option *crm_long_options = NULL; static const char *crm_app_description = NULL; static const char *crm_short_options = NULL; static const char *crm_app_usage = NULL; static struct option * crm_create_long_opts(struct crm_option *long_options) { struct option *long_opts = NULL; #ifdef HAVE_GETOPT_H int index = 0, lpc = 0; /* * A previous, possibly poor, choice of '?' as the short form of --help * means that getopt_long() returns '?' for both --help and for "unknown option" * * This dummy entry allows us to differentiate between the two in crm_get_option() * and exit with the correct error code */ crm_realloc(long_opts, (index + 1) * sizeof(struct option)); long_opts[index].name = "__dummmy__"; long_opts[index].has_arg = 0; long_opts[index].flag = 0; long_opts[index].val = '_'; index++; for (lpc = 0; long_options[lpc].name != NULL; lpc++) { if (long_options[lpc].name[0] == '-') { continue; } crm_realloc(long_opts, (index + 1) * sizeof(struct option)); /*fprintf(stderr, "Creating %d %s = %c\n", index, * long_options[lpc].name, long_options[lpc].val); */ long_opts[index].name = long_options[lpc].name; long_opts[index].has_arg = long_options[lpc].has_arg; long_opts[index].flag = long_options[lpc].flag; long_opts[index].val = long_options[lpc].val; index++; } /* Now create the list terminator */ crm_realloc(long_opts, (index + 1) * sizeof(struct option)); long_opts[index].name = NULL; long_opts[index].has_arg = 0; long_opts[index].flag = 0; long_opts[index].val = 0; #endif return long_opts; } void crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options, const char *app_desc) { if (short_options) { crm_short_options = short_options; } else if (long_options) { int lpc = 0; int opt_string_len = 0; char *local_short_options = NULL; for (lpc = 0; long_options[lpc].name != NULL; lpc++) { if (long_options[lpc].val) { crm_realloc(local_short_options, opt_string_len + 3); local_short_options[opt_string_len++] = long_options[lpc].val; if (long_options[lpc].has_arg == required_argument) { local_short_options[opt_string_len++] = ':'; } local_short_options[opt_string_len] = 0; } } crm_short_options = local_short_options; crm_trace("Generated short option string: '%s'", local_short_options); } if (long_options) { crm_long_options = long_options; } if (app_desc) { crm_app_description = app_desc; } if (app_usage) { crm_app_usage = app_usage; } } int crm_get_option(int argc, char **argv, int *index) { #ifdef HAVE_GETOPT_H static struct option *long_opts = NULL; if (long_opts == NULL && crm_long_options) { long_opts = crm_create_long_opts(crm_long_options); } if (long_opts) { int flag = getopt_long(argc, argv, crm_short_options, long_opts, index); switch (flag) { case 0: return long_opts[*index].val; case -1: /* End of option processing */ break; case ':': crm_trace("Missing argument"); crm_help('?', 1); break; case '?': crm_help('?', *index ? 0 : 1); break; } return flag; } #endif if (crm_short_options) { return getopt(argc, argv, crm_short_options); } return -1; } void crm_help(char cmd, int exit_code) { int i = 0; FILE *stream = (exit_code ? stderr : stdout); if (cmd == 'v' || cmd == '$') { fprintf(stream, "Pacemaker %s\n", VERSION); fprintf(stream, "Written by Andrew Beekhof\n"); goto out; } if (cmd == '!') { fprintf(stream, "Pacemaker %s (Build: %s): %s\n", VERSION, BUILD_VERSION, CRM_FEATURES); goto out; } fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description); if (crm_app_usage) { fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage); } if (crm_long_options) { fprintf(stream, "Options:\n"); for (i = 0; crm_long_options[i].name != NULL; i++) { if (crm_long_options[i].flags & pcmk_option_hidden) { } else if (crm_long_options[i].flags & pcmk_option_paragraph) { fprintf(stream, "%s\n\n", crm_long_options[i].desc); } else if (crm_long_options[i].flags & pcmk_option_example) { fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc); } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) { fprintf(stream, "%s\n", crm_long_options[i].desc); } else { /* is val printable as char ? */ if (crm_long_options[i].val <= UCHAR_MAX) { fprintf(stream, " -%c,", crm_long_options[i].val); } else { fputs(" ", stream); } fprintf(stream, " --%s%c%s\t%s\n", crm_long_options[i].name, crm_long_options[i].has_arg ? '=' : ' ', crm_long_options[i].has_arg ? "value" : "", crm_long_options[i].desc ? crm_long_options[i].desc : ""); } } } else if (crm_short_options) { fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description); for (i = 0; crm_short_options[i] != 0; i++) { int has_arg = FALSE; if (crm_short_options[i + 1] == ':') { has_arg = TRUE; } fprintf(stream, " -%c %s\n", crm_short_options[i], has_arg ? "{value}" : ""); if (has_arg) { i++; } } } fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT); out: if (exit_code >= 0) { exit(exit_code); } } gboolean attrd_update(crm_ipc_t *cluster, char command, const char *host, const char *name, const char *value, const char *section, const char *set, const char *dampen) { return attrd_update_delegate(cluster, command, host, name, value, section, set, dampen, NULL); } gboolean attrd_lazy_update(char command, const char *host, const char *name, const char *value, const char *section, const char *set, const char *dampen) { return attrd_update_delegate(NULL, command, host, name, value, section, set, dampen, NULL); } gboolean attrd_update_no_mainloop(int *connection, char command, const char *host, const char *name, const char *value, const char *section, const char *set, const char *dampen) { return attrd_update_delegate(NULL, command, host, name, value, section, set, dampen, NULL); } gboolean attrd_update_delegate(crm_ipc_t *ipc, char command, const char *host, const char *name, const char *value, const char *section, const char *set, const char *dampen, const char *user_name) { int rc = 0; int max = 5; xmlNode *update = create_xml_node(NULL, __FUNCTION__); static gboolean connected = TRUE; static crm_ipc_t *local_ipc = NULL; if(ipc == NULL && local_ipc == NULL) { local_ipc = crm_ipc_new(T_ATTRD, 0); connected = FALSE; } if(ipc == NULL) { ipc = local_ipc; } /* remap common aliases */ if (safe_str_eq(section, "reboot")) { section = XML_CIB_TAG_STATUS; } else if (safe_str_eq(section, "forever")) { section = XML_CIB_TAG_NODES; } crm_xml_add(update, F_TYPE, T_ATTRD); crm_xml_add(update, F_ORIG, crm_system_name); if (name == NULL && command == 'U') { command = 'R'; } switch (command) { case 'D': case 'U': case 'v': crm_xml_add(update, F_ATTRD_TASK, "update"); crm_xml_add(update, F_ATTRD_ATTRIBUTE, name); break; case 'R': crm_xml_add(update, F_ATTRD_TASK, "refresh"); break; case 'q': crm_xml_add(update, F_ATTRD_TASK, "query"); break; } crm_xml_add(update, F_ATTRD_VALUE, value); crm_xml_add(update, F_ATTRD_DAMPEN, dampen); crm_xml_add(update, F_ATTRD_SECTION, section); crm_xml_add(update, F_ATTRD_HOST, host); crm_xml_add(update, F_ATTRD_SET, set); #if ENABLE_ACL if (user_name) { crm_xml_add(update, F_ATTRD_USER, user_name); } #endif while (max > 0) { if (connected == FALSE) { crm_info("Connecting to cluster... %d retries remaining", max); connected = crm_ipc_connect(ipc); } if(connected) { rc = crm_ipc_send(ipc, update, NULL, 0); } if(ipc != local_ipc) { break; } else if (rc > 0) { break; } else { crm_ipc_close(ipc); connected = FALSE; sleep(5-max); max--; } } free_xml(update); if (rc > 0) { crm_debug("Sent update: %s=%s for %s", name, value, host ? host : "localhost"); return TRUE; } crm_info("Could not send update: %s=%s for %s", name, value, host ? host : "localhost"); return FALSE; } #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" static void append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic, int level) { /* this will enable us to later determine that the * resource's parameters have changed and we should force * a restart */ char *digest = NULL; xmlNode *args_xml = NULL; if (op->params == NULL) { return; } args_xml = create_xml_node(NULL, XML_TAG_PARAMS); g_hash_table_foreach(op->params, hash2field, args_xml); filter_action_parameters(args_xml, version); digest = calculate_operation_digest(args_xml, version); #if 0 if (level < get_crm_log_level() && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) { char *digest_source = dump_xml_unformatted(args_xml); do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n", digest, ID(update), magic, digest_source); free(digest_source); } #endif crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest); free_xml(args_xml); free(digest); } int rsc_op_expected_rc(lrmd_event_data_t * op) { int rc = 0; if (op && op->user_data) { int dummy = 0; char *uuid = NULL; decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc); free(uuid); } return rc; } gboolean did_rsc_op_fail(lrmd_event_data_t * op, int target_rc) { switch (op->op_status) { case PCMK_LRM_OP_CANCELLED: case PCMK_LRM_OP_PENDING: return FALSE; break; case PCMK_LRM_OP_NOTSUPPORTED: case PCMK_LRM_OP_TIMEOUT: case PCMK_LRM_OP_ERROR: return TRUE; break; default: if (target_rc != op->rc) { return TRUE; } } return FALSE; } xmlNode * create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char *caller_version, int target_rc, const char *origin, int level) { char *key = NULL; char *magic = NULL; char *op_id = NULL; char *local_user_data = NULL; xmlNode *xml_op = NULL; const char *task = NULL; gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0); gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0); CRM_CHECK(op != NULL, return NULL); do_crm_log(level, "%s: Updating resouce %s after %s %s op (interval=%d)", origin, op->rsc_id, services_lrm_status_str(op->op_status), op->op_type, op->interval); if (op->op_status == PCMK_LRM_OP_CANCELLED) { crm_trace("Ignoring cancelled op"); return NULL; } crm_trace("DC version: %s", caller_version); task = op->op_type; /* remap the task name under various scenarios * this makes life easier for the PE when its trying determin the current state */ if (crm_str_eq(task, "reload", TRUE)) { if (op->op_status == PCMK_LRM_OP_DONE) { task = CRMD_ACTION_START; } else { task = CRMD_ACTION_STATUS; } } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) { /* if the migrate_from fails it will have enough info to do the right thing */ if (op->op_status == PCMK_LRM_OP_DONE) { task = CRMD_ACTION_STOP; } else { task = CRMD_ACTION_STATUS; } } else if (dc_munges_migrate_ops && op->op_status == PCMK_LRM_OP_DONE && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) { task = CRMD_ACTION_START; } key = generate_op_key(op->rsc_id, task, op->interval); if (dc_needs_unique_ops && op->interval > 0) { op_id = crm_strdup(key); } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) { const char *n_type = crm_meta_value(op->params, "notify_type"); const char *n_task = crm_meta_value(op->params, "notify_operation"); CRM_LOG_ASSERT(n_type != NULL); CRM_LOG_ASSERT(n_task != NULL); op_id = generate_notify_key(op->rsc_id, n_type, n_task); /* these are not yet allowed to fail */ op->op_status = PCMK_LRM_OP_DONE; op->rc = 0; } else if (did_rsc_op_fail(op, target_rc)) { op_id = generate_op_key(op->rsc_id, "last_failure", 0); } else if (op->interval > 0) { op_id = crm_strdup(key); } else { op_id = generate_op_key(op->rsc_id, "last", 0); } xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id); if (xml_op == NULL) { xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP); } if (op->user_data == NULL) { crm_debug("Generating fake transition key for:" " %s_%s_%d %d from %s", op->rsc_id, op->op_type, op->interval, op->call_id); local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID); op->user_data = local_user_data; } magic = generate_transition_magic(op->user_data, op->op_status, op->rc); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin); crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic); crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id); crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc); crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status); crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, op->interval); if (compare_version("2.1", caller_version) <= 0) { if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) { crm_trace("Timing data (%s_%s_%d): last=%lu change=%lu exec=%lu queue=%lu", op->rsc_id, op->op_type, op->interval, op->t_run, op->t_rcchange, op->exec_time, op->queue_time); if (op->interval == 0) { crm_xml_add_int(xml_op, "last-run", op->t_run); } crm_xml_add_int(xml_op, "last-rc-change", op->t_rcchange); crm_xml_add_int(xml_op, "exec-time", op->exec_time); crm_xml_add_int(xml_op, "queue-time", op->queue_time); } } if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE) || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) { /* * Record migrate_source and migrate_target always for migrate ops. */ const char *name = XML_LRM_ATTR_MIGRATE_SOURCE; crm_xml_add(xml_op, name, crm_meta_value(op->params, name)); name = XML_LRM_ATTR_MIGRATE_TARGET; crm_xml_add(xml_op, name, crm_meta_value(op->params, name)); } append_digest(op, xml_op, caller_version, magic, LOG_DEBUG); if (local_user_data) { free(local_user_data); op->user_data = NULL; } free(magic); free(op_id); free(key); return xml_op; } #if ENABLE_ACL void determine_request_user(char **user, IPC_Channel * channel, xmlNode * request, const char *field) { /* Get our internal validation out of the way first */ CRM_CHECK(user != NULL && channel != NULL && field != NULL, return); if (*user == NULL) { /* Figure out who our peer is and cache it... */ struct passwd *pwent = getpwuid(channel->farside_uid); if (pwent == NULL) { crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", channel->farside_uid); } else { *user = crm_strdup(pwent->pw_name); } } /* If our peer is a privileged user, we might be doing something on behalf of someone else */ if (is_privileged(*user) == FALSE) { /* We're not a privileged user, set or overwrite any existing value for $field */ crm_xml_replace(request, field, *user); } else if (crm_element_value(request, field) == NULL) { /* Even if we're privileged, make sure there is always a value set */ crm_xml_replace(request, field, *user); /* } else { Legal delegation */ } crm_trace("Processing msg for user '%s'", crm_element_value(request, field)); } #endif /* * This re-implements g_str_hash as it was prior to glib2-2.28: * * http://git.gnome.org/browse/glib/commit/?id=354d655ba8a54b754cb5a3efb42767327775696c * * Note that the new g_str_hash is presumably a *better* hash (it's actually * a correct implementation of DJB's hash), but we need to preserve existing * behaviour, because the hash key ultimately determines the "sort" order * when iterating through GHashTables, which affects allocation of scores to * clone instances when iterating through rsc->allowed_nodes. It (somehow) * also appears to have some minor impact on the ordering of a few * pseudo_event IDs in the transition graph. */ guint g_str_hash_traditional(gconstpointer v) { const signed char *p; guint32 h = 0; for (p = v; *p != '\0'; p++) h = (h << 5) - h + *p; return h; } void * find_library_function(void **handle, const char *lib, const char *fn) { char *error; void *a_function; if (*handle == NULL) { *handle = dlopen(lib, RTLD_LAZY); } if (!(*handle)) { crm_err("Could not open %s: %s", lib, dlerror()); exit(100); } a_function = dlsym(*handle, fn); if ((error = dlerror()) != NULL) { crm_err("Could not find %s in %s: %s", fn, lib, error); exit(100); } return a_function; } void * convert_const_pointer(const void *ptr) { /* Worst function ever */ return (void *)ptr; } #include char *crm_generate_uuid(void) { unsigned char uuid[16]; char *buffer = malloc(37); /* Including NUL byte */ uuid_generate(uuid); uuid_unparse(uuid, buffer); return buffer; } #include char * crm_md5sum(const char *buffer) { int lpc = 0; char *digest = NULL; unsigned char raw_digest[MD5_DIGEST_SIZE]; digest = malloc(2*MD5_DIGEST_SIZE + 1); md5_buffer(buffer, strlen(buffer), raw_digest); for(lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) { sprintf(digest+(2*lpc), "%02x", raw_digest[lpc]); } digest[(2*MD5_DIGEST_SIZE)] = 0; crm_trace("Digest %s\n", digest); return digest; }