diff --git a/attrd/Makefile.am b/attrd/Makefile.am index 9c95949b85..bf34d7dbb0 100644 --- a/attrd/Makefile.am +++ b/attrd/Makefile.am @@ -1,44 +1,39 @@ # # Copyright (C) 2004-2009 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. # include $(top_srcdir)/Makefile.common halibdir = $(CRM_DAEMON_DIR) halib_PROGRAMS = attrd ## SOURCES noinst_HEADERS = internal.h attrd_common.h attrd_CFLAGS = $(CFLAGS_HARDENED_EXE) attrd_LDFLAGS = $(LDFLAGS_HARDENED_EXE) attrd_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/common/libcrmcommon.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(CLUSTERLIBS) -attrd_SOURCES = -if BUILD_ATOMIC_ATTRD -attrd_SOURCES += main.c commands.c attrd_common.c attrd_common_alerts.c -else -attrd_SOURCES += legacy.c attrd_common.c attrd_common_alerts.c -endif +attrd_SOURCES = main.c commands.c attrd_common.c attrd_common_alerts.c clean-generic: rm -f *.log *.debug *.xml *~ diff --git a/attrd/legacy.c b/attrd/legacy.c deleted file mode 100644 index 638f7024fd..0000000000 --- a/attrd/legacy.c +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * 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 - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define OPTARGS "hV" - -char *attrd_uname = NULL; -char *attrd_uuid = NULL; -uint32_t attrd_nodeid = 0; - -GHashTable *attr_hash = NULL; -lrmd_t *the_lrmd = NULL; -crm_trigger_t *attrd_config_read = NULL; - -/* Convenience macro for registering a CIB callback. - * Check the_cib != NULL before using. - */ -#define register_cib_callback(call_id, data, fn, free_fn) \ - the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, \ - data, #fn, fn, free_fn) - -typedef struct attr_hash_entry_s { - char *uuid; - char *id; - char *set; - char *section; - - char *value; - char *stored_value; - - int timeout; - char *dampen; - guint timer_id; - - char *user; - -} attr_hash_entry_t; - -void attrd_local_callback(xmlNode * msg); -gboolean attrd_timer_callback(void *user_data); -gboolean attrd_trigger_update(attr_hash_entry_t * hash_entry); -void attrd_perform_update(attr_hash_entry_t * hash_entry); -static void update_local_attr(xmlNode *msg, attr_hash_entry_t *hash_entry); - -static void -free_hash_entry(gpointer data) -{ - attr_hash_entry_t *entry = data; - - if (entry == NULL) { - return; - } - free(entry->id); - free(entry->set); - free(entry->dampen); - free(entry->section); - free(entry->uuid); - free(entry->value); - free(entry->stored_value); - free(entry->user); - free(entry); -} - -/* Exit code means? */ -static int32_t -attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size) -{ - uint32_t id = 0; - uint32_t flags = 0; - crm_client_t *client = crm_client_get(c); - xmlNode *msg = crm_ipcs_recv(client, data, size, &id, &flags); - - crm_ipcs_send_ack(client, id, flags, "ack", __FUNCTION__, __LINE__); - if (msg == NULL) { - crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c); - return 0; - } -#if ENABLE_ACL - CRM_ASSERT(client->user != NULL); - crm_acl_get_set_user(msg, F_ATTRD_USER, client->user); -#endif - - crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c); - crm_log_xml_trace(msg, __FUNCTION__); - - attrd_local_callback(msg); - - free_xml(msg); - return 0; -} - -static void -usage(const char *cmd, int exit_status) -{ - FILE *stream; - - stream = exit_status ? stderr : stdout; - - fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd); -/* fprintf(stream, "\t-d\tsets debug level\n"); */ -/* fprintf(stream, "\t-s\tgets daemon status\n"); */ -/* fprintf(stream, "\t-r\trestarts daemon\n"); */ -/* fprintf(stream, "\t-k\tstops daemon\n"); */ -/* fprintf(stream, "\t-h\thelp message\n"); */ - fflush(stream); - - crm_exit(exit_status); -} - -static void -stop_attrd_timer(attr_hash_entry_t * hash_entry) -{ - if (hash_entry != NULL && hash_entry->timer_id != 0) { - crm_trace("Stopping %s timer", hash_entry->id); - g_source_remove(hash_entry->timer_id); - hash_entry->timer_id = 0; - } -} - -static void -log_hash_entry(int level, attr_hash_entry_t * entry, const char *text) -{ - do_crm_log(level, "%s: Set: %s, Name: %s, Value: %s, Timeout: %s", - text, entry->section, entry->id, entry->value, entry->dampen); -} - -static attr_hash_entry_t * -find_hash_entry(xmlNode * msg) -{ - const char *value = NULL; - const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE); - attr_hash_entry_t *hash_entry = NULL; - - if (attr == NULL) { - crm_info("Ignoring message with no attribute name"); - return NULL; - } - - hash_entry = g_hash_table_lookup(attr_hash, attr); - - if (hash_entry == NULL) { - /* create one and add it */ - crm_info("Creating hash entry for %s", attr); - hash_entry = calloc(1, sizeof(attr_hash_entry_t)); - hash_entry->id = strdup(attr); - - g_hash_table_insert(attr_hash, hash_entry->id, hash_entry); - hash_entry = g_hash_table_lookup(attr_hash, attr); - CRM_CHECK(hash_entry != NULL, return NULL); - } - - value = crm_element_value(msg, F_ATTRD_SET); - if (value != NULL) { - free(hash_entry->set); - hash_entry->set = strdup(value); - crm_debug("\t%s->set: %s", attr, value); - } - - value = crm_element_value(msg, F_ATTRD_SECTION); - if (value == NULL) { - value = XML_CIB_TAG_STATUS; - } - free(hash_entry->section); - hash_entry->section = strdup(value); - crm_trace("\t%s->section: %s", attr, value); - - value = crm_element_value(msg, F_ATTRD_DAMPEN); - if (value != NULL) { - free(hash_entry->dampen); - hash_entry->dampen = strdup(value); - - hash_entry->timeout = crm_get_msec(value); - crm_trace("\t%s->timeout: %s", attr, value); - } -#if ENABLE_ACL - free(hash_entry->user); - hash_entry->user = NULL; - - value = crm_element_value(msg, F_ATTRD_USER); - if (value != NULL) { - hash_entry->user = strdup(value); - crm_trace("\t%s->user: %s", attr, value); - } -#endif - - log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:"); - return hash_entry; -} - -/*! - * \internal - * \brief Clear failure-related attributes for local node - * - * \param[in] xml XML of ATTRD_OP_CLEAR_FAILURE request - */ -static void -local_clear_failure(xmlNode *xml) -{ - const char *rsc = crm_element_value(xml, F_ATTRD_RESOURCE); - const char *what = rsc? rsc : "all resources"; - const char *op = crm_element_value(xml, F_ATTRD_OPERATION); - const char *interval_s = crm_element_value(xml, F_ATTRD_INTERVAL); - int interval = crm_get_interval(interval_s); - regex_t regex; - GHashTableIter iter; - attr_hash_entry_t *hash_entry = NULL; - - if (attrd_failure_regex(®ex, rsc, op, interval) != pcmk_ok) { - crm_info("Ignoring invalid request to clear %s", - (rsc? rsc : "all resources")); - return; - } - crm_debug("Clearing %s locally", what); - - /* Make sure value is not set, so we delete */ - if (crm_element_value(xml, F_ATTRD_VALUE)) { - crm_xml_replace(xml, F_ATTRD_VALUE, NULL); - } - - g_hash_table_iter_init(&iter, attr_hash); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &hash_entry)) { - if (regexec(®ex, hash_entry->id, 0, NULL, 0) == 0) { - crm_trace("Matched %s when clearing %s", hash_entry->id, what); - update_local_attr(xml, hash_entry); - } - } - regfree(®ex); -} - -static void -remote_clear_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, - void *user_data) -{ - if (rc == 0) { - crm_debug("Successfully cleared failures using %s", (char *) user_data); - } else { - crm_notice("Failed to clear failures: %s " CRM_XS " call=%d xpath=%s rc=%d", - pcmk_strerror(rc), call_id, (char *) user_data, rc); - } -} - -/* xpath component to match an id attribute (format takes remote node name) */ -#define XPATH_ID "[@" XML_ATTR_UUID "='%s']" - -/* Define the start of an xpath to match a remote node transient attribute - * (argument must be either an empty string to match for all remote nodes, - * or XPATH_ID to match for a single remote node) - */ -#define XPATH_REMOTE_ATTR(x) "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS \ - "/" XML_CIB_TAG_STATE "[@" XML_NODE_IS_REMOTE "='true']" x \ - "/" XML_TAG_TRANSIENT_NODEATTRS "/" XML_TAG_ATTR_SETS "/" XML_CIB_TAG_NVPAIR - -/* xpath component to match an attribute name exactly */ -#define XPATH_NAME_IS(x) "@" XML_NVPAIR_ATTR_NAME "='" x "'" - -/* xpath component to match an attribute name by prefix */ -#define XPATH_NAME_START(x) "starts-with(@" XML_NVPAIR_ATTR_NAME ", '" x "')" - -/* xpath ending to clear all resources */ -#define XPATH_CLEAR_ALL \ - "[" XPATH_NAME_START(CRM_FAIL_COUNT_PREFIX "-") \ - " or " XPATH_NAME_START(CRM_LAST_FAILURE_PREFIX "-") "]" - -/* xpath ending to clear all operations for one resource - * (format takes resource name x 4) - * - * @COMPAT attributes set < 1.1.17: - * also match older attributes that do not have the operation part - */ -#define XPATH_CLEAR_ONE \ - "[" XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s") \ - " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s") \ - " or " XPATH_NAME_START(CRM_FAIL_COUNT_PREFIX "-%s#") \ - " or " XPATH_NAME_START(CRM_LAST_FAILURE_PREFIX "-%s#") "]" - -/* xpath ending to clear one operation for one resource - * (format takes resource name x 2, resource name + operation + interval x 2) - * - * @COMPAT attributes set < 1.1.17: - * also match older attributes that do not have the operation part - */ -#define XPATH_CLEAR_OP \ - "[" XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s") \ - " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s") \ - " or " XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s#%s_%d") \ - " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s#%s_%d") "]" - -/*! - * \internal - * \brief Clear failure-related attributes for Pacemaker Remote node(s) - * - * \param[in] xml XML of ATTRD_OP_CLEAR_FAILURE request - */ -static void -remote_clear_failure(xmlNode *xml) -{ - const char *rsc = crm_element_value(xml, F_ATTRD_RESOURCE); - const char *host = crm_element_value(xml, F_ATTRD_HOST); - const char *op = crm_element_value(xml, F_ATTRD_OPERATION); - int rc = pcmk_ok; - char *xpath; - - if (the_cib == NULL) { - crm_info("Ignoring request to clear %s on %s because not connected to CIB", - (rsc? rsc : "all resources"), - (host? host: "all remote nodes")); - return; - } - - /* Build an xpath to clear appropriate attributes */ - - if (rsc == NULL) { - /* No resource specified, clear all resources */ - - if (host == NULL) { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_ALL); - } else { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_ALL, - host); - } - - } else if (op == NULL) { - /* Resource but no operation specified, clear all operations */ - - if (host == NULL) { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_ONE, - rsc, rsc, rsc, rsc); - } else { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_ONE, - host, rsc, rsc, rsc, rsc); - } - - } else { - /* Resource and operation specified */ - - const char *interval_s = crm_element_value(xml, F_ATTRD_INTERVAL); - int interval = crm_get_interval(interval_s); - - if (host == NULL) { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_OP, - rsc, rsc, rsc, op, interval, - rsc, op, interval); - } else { - xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_OP, - host, rsc, rsc, rsc, op, interval, - rsc, op, interval); - } - } - - crm_trace("Clearing attributes matching %s", xpath); - rc = the_cib->cmds->delete(the_cib, xpath, NULL, cib_xpath|cib_multiple); - register_cib_callback(rc, xpath, remote_clear_callback, free); -} - -static void -process_xml_request(xmlNode *xml) -{ - attr_hash_entry_t *hash_entry = NULL; - const char *from = crm_element_value(xml, F_ORIG); - const char *op = crm_element_value(xml, F_ATTRD_TASK); - const char *host = crm_element_value(xml, F_ATTRD_HOST); - const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY); - - if (host && safe_str_eq(host, attrd_uname)) { - crm_info("%s relayed from %s", (op? op : "Request"), from); - attrd_local_callback(xml); - - } else if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) { - CRM_CHECK(host != NULL, return); - crm_debug("Removing %s from peer caches for %s", host, from); - crm_remote_peer_cache_remove(host); - reap_crm_member(0, host); - - } else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) { - local_clear_failure(xml); - - } else if ((ignore == NULL) || safe_str_neq(from, attrd_uname)) { - crm_trace("%s message from %s", op, from); - hash_entry = find_hash_entry(xml); - stop_attrd_timer(hash_entry); - attrd_perform_update(hash_entry); - } -} - -#if SUPPORT_COROSYNC -static void -attrd_cs_dispatch(cpg_handle_t handle, - const struct cpg_name *groupName, - uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) -{ - uint32_t kind = 0; - xmlNode *xml = NULL; - const char *from = NULL; - char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from); - - if(data == NULL) { - return; - } - if (kind == crm_class_cluster) { - xml = string2xml(data); - if (xml == NULL) { - crm_err("Bad message received: '%.120s'", data); - } - } - - if (xml != NULL) { - /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */ - crm_xml_add(xml, F_ORIG, from); - process_xml_request(xml); - free_xml(xml); - } - - free(data); -} - -static void -attrd_cs_destroy(gpointer unused) -{ - if (attrd_shutting_down()) { - /* we signed out, so this is expected */ - crm_info("Corosync disconnection complete"); - return; - } - - crm_crit("Lost connection to Corosync service!"); - if (attrd_mainloop_running()) { - attrd_quit_mainloop(); - return; - } - crm_exit(EINVAL); -} -#endif - -static void -attrd_cib_connection_destroy(gpointer user_data) -{ - cib_t *conn = user_data; - - conn->cmds->signoff(conn); /* Ensure IPC is cleaned up */ - - if (attrd_shutting_down()) { - crm_info("Connection to the CIB terminated..."); - - } else { - /* eventually this will trigger a reconnect, not a shutdown */ - crm_err("Connection to the CIB terminated..."); - crm_exit(ENOTCONN); - } - - return; -} - -static void -update_for_hash_entry(gpointer key, gpointer value, gpointer user_data) -{ - attr_hash_entry_t *entry = value; - - if (entry->value != NULL || entry->stored_value != NULL) { - attrd_timer_callback(value); - } -} - -static void -local_update_for_hash_entry(gpointer key, gpointer value, gpointer user_data) -{ - attr_hash_entry_t *entry = value; - - if (entry->timer_id == 0) { - crm_trace("Performing local-only update after replace for %s", entry->id); - attrd_perform_update(entry); - /* } else { - * just let the timer expire and attrd_timer_callback() will do the right thing - */ - } -} - -static void -do_cib_replaced(const char *event, xmlNode * msg) -{ - crm_info("Updating all attributes after %s event", event); - g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL); -} - -static gboolean -cib_connect(void *user_data) -{ - static int attempts = 1; - static int max_retry = 20; - gboolean was_err = FALSE; - static cib_t *local_conn = NULL; - - if (local_conn == NULL) { - local_conn = cib_new(); - } - - if (was_err == FALSE) { - int rc = -ENOTCONN; - - if (attempts < max_retry) { - crm_debug("CIB signon attempt %d", attempts); - rc = local_conn->cmds->signon(local_conn, T_ATTRD, cib_command); - } - - if (rc != pcmk_ok && attempts > max_retry) { - crm_err("Signon to CIB failed: %s", pcmk_strerror(rc)); - was_err = TRUE; - - } else if (rc != pcmk_ok) { - attempts++; - return TRUE; - } - } - - crm_info("Connected to the CIB after %d signon attempts", attempts); - - if (was_err == FALSE) { - int rc = local_conn->cmds->set_connection_dnotify(local_conn, attrd_cib_connection_destroy); - - if (rc != pcmk_ok) { - crm_err("Could not set dnotify callback"); - was_err = TRUE; - } - } - - if (was_err == FALSE) { - if (pcmk_ok != - local_conn->cmds->add_notify_callback(local_conn, T_CIB_REPLACE_NOTIFY, - do_cib_replaced)) { - crm_err("Could not set CIB notification callback"); - was_err = TRUE; - } - if (was_err == FALSE) { - if (pcmk_ok != local_conn->cmds->add_notify_callback(local_conn, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb)) { - crm_err("Could not set CIB notification callback (update)"); - was_err = TRUE; - } - - } - attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL); - - /* Reading of cib(Alert section) after the start */ - mainloop_set_trigger(attrd_config_read); - } - - if (was_err) { - crm_err("Aborting startup"); - crm_exit(DAEMON_RESPAWN_STOP); - } - - the_cib = local_conn; - - crm_info("Sending full refresh now that we're connected to the cib"); - g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL); - - return FALSE; -} - -int -main(int argc, char **argv) -{ - int flag = 0; - int argerr = 0; - crm_cluster_t cluster; - gboolean was_err = FALSE; - qb_ipcs_connection_t *c = NULL; - qb_ipcs_service_t *ipcs = NULL; - - crm_log_init(T_ATTRD, LOG_NOTICE, TRUE, FALSE, argc, argv, FALSE); - mainloop_add_signal(SIGTERM, attrd_shutdown); - - while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { - switch (flag) { - case 'V': - crm_bump_log_level(argc, argv); - break; - case 'h': /* Help message */ - usage(T_ATTRD, EX_OK); - break; - default: - ++argerr; - break; - } - } - - if (optind > argc) { - ++argerr; - } - - if (argerr) { - usage(T_ATTRD, EX_USAGE); - } - - attr_hash = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_hash_entry); - - crm_info("Starting up"); - - if (was_err == FALSE) { - -#if SUPPORT_COROSYNC - if (is_corosync_cluster()) { - cluster.destroy = attrd_cs_destroy; - cluster.cpg.cpg_deliver_fn = attrd_cs_dispatch; - cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership; - } -#endif - - if (FALSE == crm_cluster_connect(&cluster)) { - crm_err("HA Signon failed"); - was_err = TRUE; - } - - attrd_uname = cluster.uname; - attrd_uuid = cluster.uuid; - attrd_nodeid = cluster.nodeid; - } - - crm_info("Cluster connection active"); - - if (was_err == FALSE) { - attrd_init_ipc(&ipcs, attrd_ipc_dispatch); - } - - crm_info("Accepting attribute updates"); - - attrd_init_mainloop(); - - if (0 == g_timeout_add_full(G_PRIORITY_LOW + 1, 5000, cib_connect, NULL, NULL)) { - crm_info("Adding timer failed"); - was_err = TRUE; - } - - if (was_err) { - crm_err("Aborting startup"); - return 100; - } - - crm_notice("Starting mainloop..."); - attrd_run_mainloop(); - crm_notice("Exiting..."); - - c = qb_ipcs_connection_first_get(ipcs); - while (c != NULL) { - qb_ipcs_connection_t *last = c; - - c = qb_ipcs_connection_next_get(ipcs, last); - - /* There really shouldn't be anyone connected at this point */ - crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last)); - qb_ipcs_disconnect(last); - qb_ipcs_connection_unref(last); - } - - qb_ipcs_destroy(ipcs); - - attrd_lrmd_disconnect(); - attrd_cib_disconnect(); - - g_hash_table_destroy(attr_hash); - free(attrd_uuid); - - return crm_exit(pcmk_ok); -} - -struct attrd_callback_s { - char *attr; - char *value; -}; - -/*! - * \internal - * \brief Free an attrd callback structure - */ -static void -free_attrd_callback(void *user_data) -{ - struct attrd_callback_s *data = user_data; - - free(data->attr); - free(data->value); - free(data); -} - -static void -attrd_cib_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) -{ - attr_hash_entry_t *hash_entry = NULL; - struct attrd_callback_s *data = user_data; - - if (data->value == NULL && rc == -ENXIO) { - rc = pcmk_ok; - - } else if (call_id < 0) { - crm_warn("Update %s=%s failed: %s", data->attr, data->value, pcmk_strerror(call_id)); - return; - } - - switch (rc) { - case pcmk_ok: - crm_debug("Update %d for %s=%s passed", call_id, data->attr, data->value); - hash_entry = g_hash_table_lookup(attr_hash, data->attr); - - if (hash_entry) { - free(hash_entry->stored_value); - hash_entry->stored_value = NULL; - if (data->value != NULL) { - hash_entry->stored_value = strdup(data->value); - } - } - break; - case -pcmk_err_diff_failed: /* When an attr changes while the CIB is syncing */ - case -ETIME: /* When an attr changes while there is a DC election */ - case -ENXIO: /* When an attr changes while the CIB is syncing a - * newer config from a node that just came up - */ - crm_warn("Update %d for %s=%s failed: %s", - call_id, data->attr, data->value, pcmk_strerror(rc)); - break; - default: - crm_err("Update %d for %s=%s failed: %s", - call_id, data->attr, data->value, pcmk_strerror(rc)); - } -} - -void -attrd_perform_update(attr_hash_entry_t * hash_entry) -{ - int rc = pcmk_ok; - struct attrd_callback_s *data = NULL; - const char *user_name = NULL; - - if (hash_entry == NULL) { - return; - - } else if (the_cib == NULL) { - crm_info("Delaying operation %s=%s: cib not connected", hash_entry->id, - crm_str(hash_entry->value)); - return; - - } -#if ENABLE_ACL - if (hash_entry->user) { - user_name = hash_entry->user; - crm_trace("Performing request from user '%s'", hash_entry->user); - } -#endif - - if (hash_entry->value == NULL) { - /* delete the attr */ - rc = delete_attr_delegate(the_cib, cib_none, hash_entry->section, attrd_uuid, NULL, - hash_entry->set, hash_entry->uuid, hash_entry->id, NULL, FALSE, - user_name); - - if (rc >= 0 && hash_entry->stored_value) { - crm_notice("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s", - rc, attrd_uuid, hash_entry->id, - hash_entry->uuid ? hash_entry->uuid : "", hash_entry->set, - hash_entry->section); - - } else if (rc < 0 && rc != -ENXIO) { - crm_notice - ("Delete operation failed: node=%s, attr=%s, id=%s, set=%s, section=%s: %s (%d)", - attrd_uuid, hash_entry->id, hash_entry->uuid ? hash_entry->uuid : "", - hash_entry->set, hash_entry->section, pcmk_strerror(rc), rc); - - } else { - crm_trace("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s", - rc, attrd_uuid, hash_entry->id, - hash_entry->uuid ? hash_entry->uuid : "", hash_entry->set, - hash_entry->section); - } - } else { - /* send update */ - rc = update_attr_delegate(the_cib, cib_none, hash_entry->section, - attrd_uuid, NULL, hash_entry->set, hash_entry->uuid, - hash_entry->id, hash_entry->value, FALSE, user_name, NULL); - if (rc < 0) { - crm_notice("Could not update %s=%s: %s (%d)", hash_entry->id, - hash_entry->value, pcmk_strerror(rc), rc); - } else if (safe_str_neq(hash_entry->value, hash_entry->stored_value)) { - crm_notice("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value); - } else { - crm_trace("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value); - } - } - attrd_send_attribute_alert(attrd_uname, attrd_nodeid, - hash_entry->id, hash_entry->value); - - data = calloc(1, sizeof(struct attrd_callback_s)); - data->attr = strdup(hash_entry->id); - if (hash_entry->value != NULL) { - data->value = strdup(hash_entry->value); - } - register_cib_callback(rc, data, attrd_cib_callback, free_attrd_callback); - return; -} - -/*! - * \internal - * \brief Expand attribute values that use "++" or "+=" - * - * \param[in] value Attribute value to expand - * \param[in] old_value Previous value of attribute - * - * \return Newly allocated string with expanded value, or NULL if not expanded - */ -static char * -expand_attr_value(const char *value, const char *old_value) -{ - char *expanded = NULL; - - if (attrd_value_needs_expansion(value)) { - expanded = crm_itoa(attrd_expand_value(value, old_value)); - } - return expanded; -} - -/*! - * \internal - * \brief Update a single node attribute for this node - * - * \param[in] msg XML message with update - * \param[in,out] hash_entry Node attribute structure - */ -static void -update_local_attr(xmlNode *msg, attr_hash_entry_t *hash_entry) -{ - const char *value = crm_element_value(msg, F_ATTRD_VALUE); - char *expanded = NULL; - - if (hash_entry->uuid == NULL) { - const char *key = crm_element_value(msg, F_ATTRD_KEY); - - if (key) { - hash_entry->uuid = strdup(key); - } - } - - crm_debug("Request to update %s (%s) to %s from %s (stored: %s)", - hash_entry->id, (hash_entry->uuid? hash_entry->uuid : "no uuid"), - value, hash_entry->value, hash_entry->stored_value); - - if (safe_str_eq(value, hash_entry->value) - && safe_str_eq(value, hash_entry->stored_value)) { - crm_trace("Ignoring non-change"); - return; - - } else if (value) { - expanded = expand_attr_value(value, hash_entry->value); - if (expanded) { - crm_info("Expanded %s=%s to %s", hash_entry->id, value, expanded); - value = expanded; - } - } - - if (safe_str_eq(value, hash_entry->value) && hash_entry->timer_id) { - /* We're already waiting to set this value */ - free(expanded); - return; - } - - free(hash_entry->value); - hash_entry->value = NULL; - if (value != NULL) { - hash_entry->value = (expanded? expanded : strdup(value)); - crm_debug("New value of %s is %s", hash_entry->id, value); - } - - stop_attrd_timer(hash_entry); - - if (hash_entry->timeout > 0) { - hash_entry->timer_id = g_timeout_add(hash_entry->timeout, attrd_timer_callback, hash_entry); - } else { - attrd_trigger_update(hash_entry); - } -} - -/*! - * \internal - * \brief Log the result of a CIB operation for a remote attribute - * - * \param[in] msg ignored - * \param[in] id CIB operation ID - * \param[in] rc CIB operation result - * \param[in] output ignored - * \param[in] data User-friendly string describing operation - */ -static void -remote_attr_callback(xmlNode *msg, int id, int rc, xmlNode *output, void *data) -{ - if (rc == pcmk_ok) { - crm_debug("%s succeeded " CRM_XS " call=%d", (char *) data, id); - } else { - crm_notice("%s failed: %s " CRM_XS " call=%d rc=%d", - (char *) data, pcmk_strerror(rc), id, rc); - } -} - -/*! - * \internal - * \brief Update a Pacemaker Remote node attribute via CIB only - * - * \param[in] host Pacemaker Remote node name - * \param[in] name Attribute name - * \param[in] value New attribute value - * \param[in] section CIB section to update (defaults to status if NULL) - * \param[in] user_name User to perform operation as - * - * \note Legacy attrd does not track remote node attributes, so such requests - * are only sent to the CIB. This means that dampening is ignored, and - * updates for the same attribute submitted to different nodes cannot be - * reliably ordered. This is not ideal, but allows remote nodes to - * be supported, and should be acceptable in practice. - */ -static void -update_remote_attr(const char *host, const char *name, const char *value, - const char *section, const char *user_name) -{ - int rc = pcmk_ok; - char *desc; - - if (value == NULL) { - desc = crm_strdup_printf("Delete of %s in %s for %s", - name, section, host); - } else { - desc = crm_strdup_printf("Update of %s=%s in %s for %s", - name, value, section, host); - } - - if (name == NULL) { - rc = -EINVAL; - } else if (the_cib == NULL) { - rc = -ENOTCONN; - } - if (rc != pcmk_ok) { - remote_attr_callback(NULL, rc, rc, NULL, desc); - free(desc); - return; - } - - if (value == NULL) { - rc = delete_attr_delegate(the_cib, cib_none, section, - host, NULL, NULL, NULL, name, NULL, - FALSE, user_name); - } else { - rc = update_attr_delegate(the_cib, cib_none, section, - host, NULL, NULL, NULL, name, value, - FALSE, user_name, "remote"); - } - - attrd_send_attribute_alert(host, 0, name, (value? value : "")); - - crm_trace("%s submitted as CIB call %d", desc, rc); - register_cib_callback(rc, desc, remote_attr_callback, free); -} - -/*! - * \internal - * \brief Handle a client request to clear failures - * - * \param[in] msg XML of request - * - * \note Handling is according to the host specified in the request: - * NULL: Relay to all cluster nodes (which do local_clear_failure()) - * and also handle all remote nodes here, using remote_clear_failure(); - * Our uname: Handle here, using local_clear_failure(); - * Known peer: Relay to that peer, which (via process_xml_message() then - * attrd_local_callback()) comes back here as previous case; - * Unknown peer: Handle here as remote node, using remote_clear_failure() - */ -static void -attrd_client_clear_failure(xmlNode *msg) -{ - const char *host = crm_element_value(msg, F_ATTRD_HOST); - - if (host == NULL) { - /* Clear failure on all cluster nodes */ - crm_notice("Broadcasting request to clear failure on all hosts"); - send_cluster_message(NULL, crm_msg_attrd, msg, FALSE); - - /* Clear failure on all remote nodes */ - remote_clear_failure(msg); - - } else if (safe_str_eq(host, attrd_uname)) { - local_clear_failure(msg); - - } else { - int is_remote = FALSE; - crm_node_t *peer = crm_find_peer(0, host); - - crm_element_value_int(msg, F_ATTRD_IS_REMOTE, &is_remote); - - if (is_remote || (peer == NULL)) { - /* If request is not for a known cluster node, assume remote */ - remote_clear_failure(msg); - } else { - /* Relay request to proper node */ - crm_notice("Relaying request to clear failure to %s", host); - send_cluster_message(peer, crm_msg_attrd, msg, FALSE); - } - } -} - -void -attrd_local_callback(xmlNode * msg) -{ - attr_hash_entry_t *hash_entry = NULL; - const char *from = crm_element_value(msg, F_ORIG); - const char *op = crm_element_value(msg, F_ATTRD_TASK); - const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE); - const char *pattern = crm_element_value(msg, F_ATTRD_REGEX); - const char *value = crm_element_value(msg, F_ATTRD_VALUE); - const char *host = crm_element_value(msg, F_ATTRD_HOST); - int is_remote = FALSE; - - crm_element_value_int(msg, F_ATTRD_IS_REMOTE, &is_remote); - - if (safe_str_eq(op, ATTRD_OP_REFRESH)) { - crm_notice("Sending full refresh (origin=%s)", from); - g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL); - return; - - } else if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) { - if (host) { - crm_notice("Broadcasting removal of peer %s", host); - send_cluster_message(NULL, crm_msg_attrd, msg, FALSE); - } - return; - - } else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) { - attrd_client_clear_failure(msg); - return; - - } else if (op && safe_str_neq(op, ATTRD_OP_UPDATE)) { - crm_notice("Ignoring unsupported %s request from %s", op, from); - return; - } - - /* Handle requests for Pacemaker Remote nodes specially */ - if (host && is_remote) { - const char *section = crm_element_value(msg, F_ATTRD_SECTION); - const char *user_name = crm_element_value(msg, F_ATTRD_USER); - - if (section == NULL) { - section = XML_CIB_TAG_STATUS; - } - if ((attr == NULL) && (pattern != NULL)) { - /* Attribute(s) specified by regular expression */ - /* @TODO query, iterate and update_remote_attr() for matches? */ - crm_notice("Update of %s for %s failed: regular expressions " - "are not supported with Pacemaker Remote nodes", - pattern, host); - } else { - /* Single attribute specified by exact name */ - update_remote_attr(host, attr, value, section, user_name); - } - return; - } - - /* Redirect requests for another cluster node to that node */ - if (host != NULL && safe_str_neq(host, attrd_uname)) { - send_cluster_message(crm_get_peer(0, host), crm_msg_attrd, msg, FALSE); - return; - } - - if (attr != NULL) { - /* Single attribute specified by exact name */ - crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value)); - hash_entry = find_hash_entry(msg); - if (hash_entry != NULL) { - update_local_attr(msg, hash_entry); - } - - } else if (pattern != NULL) { - /* Attribute(s) specified by regular expression */ - regex_t regex; - GHashTableIter iter; - - if (regcomp(®ex, pattern, REG_EXTENDED|REG_NOSUB)) { - crm_err("Update from %s failed: invalid pattern %s", - from, pattern); - return; - } - - crm_debug("%s message from %s: %s=%s", - op, from, pattern, crm_str(value)); - g_hash_table_iter_init(&iter, attr_hash); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &hash_entry)) { - int rc = regexec(®ex, hash_entry->id, 0, NULL, 0); - - if (rc == 0) { - crm_trace("Attribute %s matches %s", hash_entry->id, pattern); - update_local_attr(msg, hash_entry); - } - } - regfree(®ex); - - } else { - crm_info("Ignoring message with no attribute name or expression"); - } -} - -gboolean -attrd_timer_callback(void *user_data) -{ - stop_attrd_timer(user_data); - attrd_trigger_update(user_data); - return TRUE; /* Always return true, removed cleanly by stop_attrd_timer() */ -} - -gboolean -attrd_trigger_update(attr_hash_entry_t * hash_entry) -{ - xmlNode *msg = NULL; - - /* send HA message to everyone */ - crm_notice("Sending flush op to all hosts for: %s (%s)", - hash_entry->id, crm_str(hash_entry->value)); - log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:"); - - msg = create_xml_node(NULL, __FUNCTION__); - crm_xml_add(msg, F_TYPE, T_ATTRD); - crm_xml_add(msg, F_ORIG, attrd_uname); - crm_xml_add(msg, F_ATTRD_TASK, "flush"); - crm_xml_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id); - crm_xml_add(msg, F_ATTRD_SET, hash_entry->set); - crm_xml_add(msg, F_ATTRD_SECTION, hash_entry->section); - crm_xml_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen); - crm_xml_add(msg, F_ATTRD_VALUE, hash_entry->value); -#if ENABLE_ACL - if (hash_entry->user) { - crm_xml_add(msg, F_ATTRD_USER, hash_entry->user); - } -#endif - - if (hash_entry->timeout <= 0) { - crm_xml_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value); - attrd_perform_update(hash_entry); - } - - send_cluster_message(NULL, crm_msg_attrd, msg, FALSE); - free_xml(msg); - - return TRUE; -} diff --git a/configure.ac b/configure.ac index afbfbd4df6..1d4a2b1407 100644 --- a/configure.ac +++ b/configure.ac @@ -1,1957 +1,1951 @@ 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 m4_include([version.m4]) AC_INIT([pacemaker], VERSION_NUMBER, [users@clusterlabs.org], [pacemaker], PCMK_URL) dnl Workaround autoconf < 2.64 if test x"${PACKAGE_URL}" = x""; then AC_SUBST([PACKAGE_URL], PCMK_URL) fi PCMK_FEATURES="" 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 crm_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" ]) dnl Older distros may need: AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION) AM_INIT_AUTOMAKE([foreign]) AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$PACKAGE_VERSION", Current pacemaker version) dnl Versioned attributes implementation is not yet production-ready AC_DEFINE_UNQUOTED(ENABLE_VERSIONED_ATTRS, 0, Enable versioned attributes) 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 -BUILD_ATOMIC_ATTRD=1 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 LT_INIT([dlopen]) LTDL_INIT([convenience]) 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="-Werror $@" AC_MSG_CHECKING(whether $CC supports "$@") AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])], [RC=0; AC_MSG_RESULT(yes)],[RC=1; AC_MSG_RESULT(no)]) return $RC } try_extract_header_define() { AC_MSG_CHECKING(if $2 in $1 exists) 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} 2>/dev/null value= if test -x ${Cfile}; then value=`${Cfile} 2>/dev/null` fi if test x"${value}" == x""; then value=$3 AC_MSG_RESULT(default: $value) else AC_MSG_RESULT($value) fi 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([no-stack], [ --enable-no-stack Only build the Policy Engine and pieces needed to support it [default=no]]) AC_ARG_ENABLE([upstart], [ --enable-upstart Enable support for managing resources via Upstart [default=try]], [], [enable_upstart=try], ) AC_ARG_ENABLE([systemd], [ --enable-systemd Enable support for managing resources via systemd [default=try]], [], [enable_systemd=try], ) AC_ARG_ENABLE(hardening, [ --with-hardening Harden the resulting executables/libraries (best effort by default)], [ HARDENING="${enableval}" ], [ HARDENING=try ], ) AC_ARG_WITH(corosync, [ --with-corosync Support the Corosync messaging and membership layer ], [ SUPPORT_CS=$withval ], [ SUPPORT_CS=try ], ) AC_ARG_WITH(nagios, [ --with-nagios Support nagios remote monitoring ], [ SUPPORT_NAGIOS=$withval ], [ SUPPORT_NAGIOS=try ], ) AC_ARG_WITH(nagios-plugin-dir, [ --with-nagios-plugin-dir=DIR Directory for nagios plugins [${NAGIOS_PLUGIN_DIR}]], [ NAGIOS_PLUGIN_DIR="$withval" ] ) AC_ARG_WITH(nagios-metadata-dir, [ --with-nagios-metadata-dir=DIR Directory for nagios plugins metadata [${NAGIOS_METADATA_DIR}]], [ NAGIOS_METADATA_DIR="$withval" ] ) 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=yes ], ) AC_ARG_WITH(cibsecrets, [ --with-cibsecrets Support CIB secrets ], [ SUPPORT_CIBSECRETS=$withval ], [ SUPPORT_CIBSECRETS=no ], ) 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 Disable optimizations for effective profiling ], [ SUPPORT_PROFILING=$withval ]) AC_ARG_WITH(coverage, [ --with-coverage Disable optimizations for effective profiling ], [ SUPPORT_COVERAGE=$withval ]) PUBLICAN_BRAND="common" AC_ARG_WITH(brand, [ --with-brand=brand Brand to use for generated documentation (set empty for no docs) [$PUBLICAN_BRAND]], [ test x"$withval" = x"no" || PUBLICAN_BRAND="$withval" ]) AC_SUBST(PUBLICAN_BRAND) ASCIIDOC_CLI_TYPE="pcs" AC_ARG_WITH(doc-cli, [ --with-doc-cli=cli_type CLI type to use for generated documentation. [$ASCIIDOC_CLI_TYPE]], [ ASCIIDOC_CLI_TYPE="$withval" ]) AC_SUBST(ASCIIDOC_CLI_TYPE) CONFIGDIR="" AC_ARG_WITH(configdir, [ --with-configdir=DIR Directory for Pacemaker configuration file [${CONFIGDIR}]], [ CONFIGDIR="$withval" ] ) dnl =============================================== dnl General Processing dnl =============================================== 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 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 don't 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) if test x"${CONFIGDIR}" = x""; then CONFIGDIR="${sysconfdir}/sysconfig" fi AC_SUBST(CONFIGDIR) for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \ sharedstatedir localstatedir libdir includedir oldincludedir infodir \ mandir INITDIR docdir CONFIGDIR 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*) AC_DEFINE_UNQUOTED(ON_BSD, 1, Compiling for BSD platform) LIBS="-L/usr/local/lib" CPPFLAGS="$CPPFLAGS -I/usr/local/include" INIT_EXT=".sh" ;; *solaris*) AC_DEFINE_UNQUOTED(ON_SOLARIS, 1, Compiling for Solaris platform) ;; *linux*) AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform) ;; darwin*) AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform) LIBS="$LIBS -L${prefix}/lib" CFLAGS="$CFLAGS -I${prefix}/include" ;; esac 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(XMLCATALOG, xmlcatalog) 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) PKG_PROG_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) # first try to figure out correct template using xmlcatalog query, # resort to extensive (semi-deterministic) file search if that fails DOCBOOK_XSL_URI='http://docbook.sourceforge.net/release/xsl/current' DOCBOOK_XSL_PATH='manpages/docbook.xsl' MANPAGE_XSLT=$(${XMLCATALOG} "" ${DOCBOOK_XSL_URI}/${DOCBOOK_XSL_PATH} \ | sed -n 's|^file://||p;q') if test x"${MANPAGE_XSLT}" = x""; then DIRS=$(find "${datadir}" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \ -type d | LC_ALL=C sort) XSLT=$(basename ${DOCBOOK_XSL_PATH}) for d in ${DIRS}; do if test -f "${d}/${XSLT}"; then MANPAGE_XSLT="${d}/${XSLT}" break fi done fi 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) publican_intree_brand=no if test x"${PUBLICAN_BRAND}" != x"" \ && test x"${PUBLICAN}" != x"" \ && test x"${INKSCAPE}" != x""; then dnl special handling for clusterlabs brand (possibly in-tree version used) test "${PUBLICAN_BRAND}" != "clusterlabs" \ || test -d /usr/share/publican/Common_Content/clusterlabs if test $? -ne 0; then dnl Unknown option: brand_dir vs. Option brand_dir requires an argument if ${PUBLICAN} build --brand_dir 2>&1 | grep -Eq 'brand_dir$'; then AC_MSG_WARN([Cannot use in-tree clusterlabs brand, resorting to common]) PUBLICAN_BRAND=common else publican_intree_brand=yes fi fi AC_MSG_NOTICE([Enabling Publican-generated documentation using ${PUBLICAN_BRAND} brand]) PCMK_FEATURES="$PCMK_FEATURES publican-docs" fi AM_CONDITIONAL([BUILD_DOCBOOK], [test x"${PUBLICAN_BRAND}" != x"" \ && test x"${PUBLICAN}" != x"" \ && test x"${INKSCAPE}" != x""]) AM_CONDITIONAL([PUBLICAN_INTREE_BRAND], [test x"${publican_intree_brand}" = x"yes"]) 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 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. AC_REPLACE_FUNCS(alphasort NoSuchFunctionName scandir setenv strerror strchrnul unsetenv strnlen strndup) 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_FUNCS([sched_setscheduler]) AC_CHECK_LIB(uuid, uuid_parse) dnl load the library if necessary AC_CHECK_FUNCS(uuid_unparse) dnl OSX ships uuid_* as standard functions AC_CHECK_HEADERS(uuid/uuid.h) if test "x$ac_cv_func_uuid_unparse" != xyes; then AC_MSG_ERROR(You do not have the libuuid development package installed) fi if test x"${PKG_CONFIG}" = x""; then AC_MSG_ERROR(You need pkgconfig installed in order to build ${PACKAGE}) fi if $PKG_CONFIG --exists glib-2.0 then GLIBCONFIG="$PKG_CONFIG glib-2.0" else set -x echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH $PKG_CONFIG --exists glib-2.0; echo $? $PKG_CONFIG --cflags glib-2.0; echo $? $PKG_CONFIG glib-2.0; echo $? set +x AC_MSG_ERROR(You need glib2-devel installed in order to build ${PACKAGE}) fi AC_MSG_RESULT(using $GLIBCONFIG) # # 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 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 FreeBSD needs -lcompat for ftime() used by lrmd.c AC_CHECK_LIB([compat], [ftime], [COMPAT_LIBS='-lcompat']) AC_SUBST(COMPAT_LIBS) 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(linux/swab.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/reboot.h) AC_CHECK_HEADERS(sys/resource.h) AC_CHECK_HEADERS(sys/select.h) AC_CHECK_HEADERS(sys/socket.h) AC_CHECK_HEADERS(sys/signalfd.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 AC_CACHE_CHECK(whether __progname and __progname_full are available, pf_cv_var_progname, AC_TRY_LINK([extern char *__progname, *__progname_full;], [__progname = "foo"; __progname_full = "foo bar";], pf_cv_var_progname="yes", pf_cv_var_progname="no")) if test "$pf_cv_var_progname" = "yes"; then AC_DEFINE(HAVE___PROGNAME,1,[ ]) fi dnl ======================================================================== dnl Structures dnl ======================================================================== AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[[#include ]]) AC_CHECK_MEMBERS([lrm_op_t.rsc_deleted],,,[[#include ]]) AC_CHECK_MEMBER([struct dirent.d_type], AC_DEFINE(HAVE_STRUCT_DIRENT_D_TYPE,1,[Define this if struct dirent has d_type]),, [#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 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 sighandler_t is missing from Illumos, Solaris11 systems dnl ======================================================================== AC_MSG_CHECKING([for sighandler_t]) AC_TRY_COMPILE([#include ],[sighandler_t *f;], has_sighandler_t=yes,has_sighandler_t=no) AC_MSG_RESULT($has_sighandler_t) if test "$has_sighandler_t" = "yes" ; then AC_DEFINE( HAVE_SIGHANDLER_T, 1, [Define if sighandler_t available] ) 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, [AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses' fi if test "$ac_cv_header_ncurses_ncurses_h" = "yes"; then AC_CHECK_LIB(ncurses, printw, [AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses' 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_save_LIBS=$LIBS LIBS="$CURSESLIBS" ac_save_CFLAGS=$CFLAGS CFLAGS="-Wcast-qual -Werror" # avoid broken test because of hardened build environment in Fedora 23+ # - https://fedoraproject.org/wiki/Changes/Harden_All_Packages # - https://bugzilla.redhat.com/1297985 if cc_supports_flag -fPIC; then CFLAGS="$CFLAGS -fPIC" fi AC_MSG_CHECKING(whether printw() requires argument of "const char *") AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #if defined(HAVE_NCURSES_H) # include #elif defined(HAVE_NCURSES_NCURSES_H) # include #elif defined(HAVE_CURSES_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 ======================================================================== AC_MSG_NOTICE(Old CFLAGS: $CFLAGS) case $SUPPORT_COVERAGE in 1|yes|true) SUPPORT_PROFILING=1 PCMK_FEATURES="$PCMK_FEATURES coverage" CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage" dnl During linking, make sure to specify -lgcov or -coverage dnl Enable gprof #LIBS="$LIBS -pg" #CFLAGS="$CFLAGS -pg" ;; esac case $SUPPORT_PROFILING in 1|yes|true) SUPPORT_PROFILING=1 dnl Disable various compiler optimizations CFLAGS="$CFLAGS -fno-omit-frame-pointer -fno-inline -fno-builtin " dnl CFLAGS="$CFLAGS -fno-inline-functions -fno-default-inline -fno-inline-functions-called-once -fno-optimize-sibling-calls" dnl Turn off optimization so tools can get accurate line numbers CFLAGS=`echo $CFLAGS | sed -e 's/-O.\ //g' -e 's/-Wp,-D_FORTIFY_SOURCE=.\ //g' -e 's/-D_FORTIFY_SOURCE=.\ //g'` CFLAGS="$CFLAGS -O0 -g3 -gdwarf-2" dnl Update features PCMK_FEATURES="$PCMK_FEATURES profile" ;; *) SUPPORT_PROFILING=0;; esac AC_MSG_NOTICE(New CFLAGS: $CFLAGS) AC_DEFINE_UNQUOTED(SUPPORT_PROFILING, $SUPPORT_PROFILING, Support for profiling) dnl ======================================================================== dnl Cluster infrastructure - LibQB dnl ======================================================================== if test x${enable_no_stack} = xyes; then SUPPORT_CS=no fi PKG_CHECK_MODULES(libqb, libqb >= 0.13) CPPFLAGS="$libqb_CFLAGS $CPPFLAGS" LIBS="$libqb_LIBS $LIBS" AC_CHECK_HEADERS(qb/qbipc_common.h) AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set) PCMK_FEATURES="$PCMK_FEATURES libqb-logging libqb-ipc" AC_CHECK_FUNCS(qb_ipcs_connection_get_buffer_size, AC_DEFINE(HAVE_IPCS_GET_BUFFER_SIZE, 1, [Have qb_ipcc_get_buffer_size function])) dnl Support Linux-HA fence agents if available if test "$cross_compiling" != "yes"; then CPPFLAGS="$CPPFLAGS -I${prefix}/include/heartbeat" fi AC_CHECK_HEADERS(stonith/stonith.h) if test "$ac_cv_header_stonith_stonith_h" = "yes"; then dnl On Debian, AC_CHECK_LIBS fail if a library has any unresolved symbols dnl So check for all the dependencies (so they're added to LIBS) before checking for -lplumb AC_CHECK_LIB(pils, PILLoadPlugin) AC_CHECK_LIB(plumb, G_main_add_IPC_Channel) PCMK_FEATURES="$PCMK_FEATURES lha-fencing" 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) CRM_CORE_DIR="${localstatedir}/lib/pacemaker/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="hacluster" AC_DEFINE_UNQUOTED(CRM_DAEMON_USER,"$CRM_DAEMON_USER", User to run Pacemaker daemons as) AC_SUBST(CRM_DAEMON_USER) CRM_DAEMON_GROUP="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_LOG_DIR="${localstatedir}/log/pacemaker" AC_DEFINE_UNQUOTED(CRM_LOG_DIR,"$CRM_LOG_DIR", Where Pacemaker can store log files) AC_SUBST(CRM_LOG_DIR) CRM_PACEMAKER_DIR=${localstatedir}/lib/pacemaker AC_DEFINE_UNQUOTED(CRM_PACEMAKER_DIR,"$CRM_PACEMAKER_DIR", Location to store directory produced by Pacemaker daemons) AC_SUBST(CRM_PACEMAKER_DIR) CRM_BLACKBOX_DIR=${localstatedir}/lib/pacemaker/blackbox AC_DEFINE_UNQUOTED(CRM_BLACKBOX_DIR,"$CRM_BLACKBOX_DIR", Where to keep blackbox dumps) AC_SUBST(CRM_BLACKBOX_DIR) PE_STATE_DIR="${localstatedir}/lib/pacemaker/pengine" AC_DEFINE_UNQUOTED(PE_STATE_DIR,"$PE_STATE_DIR", Where to keep PEngine outputs) AC_SUBST(PE_STATE_DIR) CRM_CONFIG_DIR="${localstatedir}/lib/pacemaker/cib" AC_DEFINE_UNQUOTED(CRM_CONFIG_DIR,"$CRM_CONFIG_DIR", Where to keep configuration files) AC_SUBST(CRM_CONFIG_DIR) CRM_CONFIG_CTS="${localstatedir}/lib/pacemaker/cts" AC_DEFINE_UNQUOTED(CRM_CONFIG_CTS,"$CRM_CONFIG_CTS", Where to keep cts stateful data) AC_SUBST(CRM_CONFIG_CTS) CRM_DAEMON_DIR="${libexecdir}/pacemaker" AC_DEFINE_UNQUOTED(CRM_DAEMON_DIR,"$CRM_DAEMON_DIR", Location for Pacemaker daemons) AC_SUBST(CRM_DAEMON_DIR) HA_STATE_DIR="${localstatedir}/run" AC_DEFINE_UNQUOTED(HA_STATE_DIR,"$HA_STATE_DIR", Where sbd keeps its PID file) AC_SUBST(HA_STATE_DIR) CRM_RSCTMP_DIR=`try_extract_header_define agent_config.h HA_RSCTMPDIR $HA_STATE_DIR/resource-agents` 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) 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="$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) AC_DEFINE_UNQUOTED(SBIN_DIR,"$sbindir", Location for system binaries) 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) HAVE_dbus=1 HAVE_upstart=0 HAVE_systemd=0 PKG_CHECK_MODULES(DBUS, dbus-1, ,HAVE_dbus=0) AC_DEFINE_UNQUOTED(SUPPORT_DBUS, $HAVE_dbus, Support dbus) AM_CONDITIONAL(BUILD_DBUS, test $HAVE_dbus = 1) if test $HAVE_dbus = 1; then CFLAGS="$CFLAGS `$PKG_CONFIG --cflags dbus-1`" fi DBUS_LIBS="$CFLAGS `$PKG_CONFIG --libs dbus-1`" AC_SUBST(DBUS_LIBS) AC_CHECK_TYPES([DBusBasicValue],,,[[#include ]]) if test "x${enable_systemd}" != xno; then if test $HAVE_dbus = 0; then if test "x${enable_systemd}" = xyes; then AC_MSG_FAILURE([cannot enable systemd without DBus]) else enable_systemd=no fi fi if test "x${enable_systemd}" = xtry; then AC_MSG_CHECKING([for systemd version query result via dbus-send]) ret=$({ dbus-send --system --print-reply \ --dest=org.freedesktop.systemd1 \ /org/freedesktop/systemd1 \ org.freedesktop.DBus.Properties.Get \ string:org.freedesktop.systemd1.Manager \ string:Version 2>/dev/null \ || echo "this borked"; } | tail -n1) # sanitize output a bit (interested just in value, not type), # ret is intentionally unenquoted so as to normalize whitespace ret=$(echo ${ret} | cut -d' ' -f2-) AC_MSG_RESULT([${ret}]) if test "x${ret}" != xborked \ || systemctl --version 2>/dev/null | grep -q systemd; then enable_systemd=yes else enable_systemd=no fi fi fi AC_MSG_CHECKING([whether to enable support for managing resources via systemd]) AC_MSG_RESULT([${enable_systemd}]) if test "x${enable_systemd}" = xyes; then HAVE_systemd=1 PCMK_FEATURES="$PCMK_FEATURES systemd" AC_MSG_CHECKING([for systemd path for system unit files]) systemdunitdir="${systemdunitdir-}" PKG_CHECK_VAR([systemdunitdir], [systemd], [systemdsystemunitdir], [],[ systemdunitdir=no ]) AC_MSG_RESULT([${systemdunitdir}]) if test "x${systemdunitdir}" = xno; then AC_MSG_FAILURE([cannot enable systemd when systemdunitdir unresolved]) fi fi AC_DEFINE_UNQUOTED(SUPPORT_SYSTEMD, $HAVE_systemd, Support systemd based system services) AM_CONDITIONAL(BUILD_SYSTEMD, test $HAVE_systemd = 1) AC_SUBST(SUPPORT_SYSTEMD) if test "x${enable_upstart}" != xno; then if test $HAVE_dbus = 0; then if test "x${enable_upstart}" = xyes; then AC_MSG_FAILURE([cannot enable Upstart without DBus]) else enable_upstart=no fi fi if test "x${enable_upstart}" = xtry; then AC_MSG_CHECKING([for Upstart version query result via dbus-send]) ret=$({ dbus-send --system --print-reply --dest=com.ubuntu.Upstart \ /com/ubuntu/Upstart org.freedesktop.DBus.Properties.Get \ string:com.ubuntu.Upstart0_6 string:version 2>/dev/null \ || echo "this borked"; } | tail -n1) # sanitize output a bit (interested just in value, not type), # ret is intentionally unenquoted so as to normalize whitespace ret=$(echo ${ret} | cut -d' ' -f2-) AC_MSG_RESULT([${ret}]) if test "x${ret}" != xborked \ || initctl --version 2>/dev/null | grep -q upstart; then enable_upstart=yes else enable_upstart=no fi fi fi AC_MSG_CHECKING([whether to enable support for managing resources via Upstart]) AC_MSG_RESULT([${enable_upstart}]) if test "x${enable_upstart}" = xyes; then HAVE_upstart=1 PCMK_FEATURES="$PCMK_FEATURES upstart" fi AC_DEFINE_UNQUOTED(SUPPORT_UPSTART, $HAVE_upstart, Support upstart based system services) AM_CONDITIONAL(BUILD_UPSTART, test $HAVE_upstart = 1) AC_SUBST(SUPPORT_UPSTART) case $SUPPORT_NAGIOS in 1|yes|true|try) SUPPORT_NAGIOS=1;; *) SUPPORT_NAGIOS=0;; esac if test $SUPPORT_NAGIOS = 1; then PCMK_FEATURES="$PCMK_FEATURES nagios" fi AC_DEFINE_UNQUOTED(SUPPORT_NAGIOS, $SUPPORT_NAGIOS, Support nagios plugins) AM_CONDITIONAL(BUILD_NAGIOS, test $SUPPORT_NAGIOS = 1) if test x"$NAGIOS_PLUGIN_DIR" = x""; then NAGIOS_PLUGIN_DIR="${libexecdir}/nagios/plugins" fi AC_DEFINE_UNQUOTED(NAGIOS_PLUGIN_DIR, "$NAGIOS_PLUGIN_DIR", Directory for nagios plugins) AC_SUBST(NAGIOS_PLUGIN_DIR) if test x"$NAGIOS_METADATA_DIR" = x""; then NAGIOS_METADATA_DIR="${datadir}/nagios/plugins-metadata" fi AC_DEFINE_UNQUOTED(NAGIOS_METADATA_DIR, "$NAGIOS_METADATA_DIR", Directory for nagios plugins metadata) AC_SUBST(NAGIOS_METADATA_DIR) STACKS="" CLUSTERLIBS="" 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="" if test $SUPPORT_CS = no; then AC_MSG_RESULT(no (disabled)) SUPPORT_CS=0 else AC_MSG_RESULT($SUPPORT_CS) SUPPORT_CS=1 PKG_CHECK_MODULES(cpg, libcpg) dnl Fatal PKG_CHECK_MODULES(cfg, libcfg) dnl Fatal PKG_CHECK_MODULES(cmap, libcmap) dnl Fatal PKG_CHECK_MODULES(quorum, libquorum) dnl Fatal CFLAGS="$CFLAGS $libqb_FLAGS $cpg_FLAGS $cfg_FLAGS $cmap_CFLAGS $quorum_CFLAGS" COROSYNC_LIBS="$COROSYNC_LIBS $libqb_LIBS $cpg_LIBS $cfg_LIBS $cmap_LIBS $quorum_LIBS" CLUSTERLIBS="$CLUSTERLIBS $COROSYNC_LIBS" AC_CHECK_LIB(corosync_common, cs_strerror) STACKS="$STACKS corosync-native" fi AC_DEFINE_UNQUOTED(SUPPORT_COROSYNC, $SUPPORT_CS, Support the Corosync messaging and membership layer) AM_CONDITIONAL(BUILD_CS_SUPPORT, test $SUPPORT_CS = 1) AC_SUBST(SUPPORT_COROSYNC) -AM_CONDITIONAL(BUILD_ATOMIC_ATTRD, test $BUILD_ATOMIC_ATTRD = 1) -AC_DEFINE_UNQUOTED(HAVE_ATOMIC_ATTRD, $BUILD_ATOMIC_ATTRD, Support the new atomic attrd) - 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) fi AC_MSG_RESULT($STACKS) PCMK_FEATURES="$PCMK_FEATURES $STACKS" fi -if test ${BUILD_ATOMIC_ATTRD} = 1; then - PCMK_FEATURES="$PCMK_FEATURES atomic-attrd" -fi +PCMK_FEATURES="$PCMK_FEATURES atomic-attrd" AC_SUBST(CLUSTERLIBS) 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) SUPPORT_ACL=1 AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set) if test $ac_cv_lib_qb_qb_ipcs_connection_auth_set != yes; then SUPPORT_ACL=0 fi if test $SUPPORT_ACL = 0; then if test $missingisfatal = 0; then AC_MSG_WARN(Unable to support ACL. You need to use libqb > 0.13.0) else AC_MSG_FAILURE(Unable to support ACL. You need to use libqb > 0.13.0) 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 CIB secrets dnl ======================================================================== case $SUPPORT_CIBSECRETS in 1|yes|true|try) SUPPORT_CIBSECRETS=1;; *) SUPPORT_CIBSECRETS=0;; esac AC_DEFINE_UNQUOTED(SUPPORT_CIBSECRETS, $SUPPORT_CIBSECRETS, Support CIB secrets) AM_CONDITIONAL(BUILD_CIBSECRETS, test $SUPPORT_CIBSECRETS = 1) if test $SUPPORT_CIBSECRETS = 1; then PCMK_FEATURES="$PCMK_FEATURES cibsecrets" LRM_CIBSECRETS_DIR="${localstatedir}/lib/pacemaker/lrm/secrets" AC_DEFINE_UNQUOTED(LRM_CIBSECRETS_DIR,"$LRM_CIBSECRETS_DIR", Location for CIB secrets) AC_SUBST(LRM_CIBSECRETS_DIR) fi 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 $PKG_CONFIG --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 $PKG_CONFIG --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. if export | fgrep " CFLAGS=" > /dev/null; then SAVED_CFLAGS="$CFLAGS" unset CFLAGS CFLAGS="$SAVED_CFLAGS" unset SAVED_CFLAGS fi AC_ARG_VAR([CFLAGS_HARDENED_LIB], [extra C compiler flags for hardened libraries]) AC_ARG_VAR([LDFLAGS_HARDENED_LIB], [extra linker flags for hardened libraries]) AC_ARG_VAR([CFLAGS_HARDENED_EXE], [extra C compiler flags for hardened executables]) AC_ARG_VAR([LDFLAGS_HARDENED_EXE], [extra linker flags for hardened executables]) CC_EXTRAS="" if test "$GCC" != yes; then CFLAGS="$CFLAGS -g" enable_fatal_warnings=no else CFLAGS="$CFLAGS -ggdb" dnl When we don't have diagnostic push / pull, we can't explicitly disable dnl checking for nonliteral formats in the places where they occur on purpose dnl thus we disable nonliteral format checking globally as we are aborting dnl on warnings. dnl what makes the things really ugly is that nonliteral format checking is dnl obviously available as an extra switch in very modern gcc but for older dnl gcc this is part of -Wformat=2 dnl so if we have push/pull we can enable -Wformat=2 -Wformat-nonliteral dnl if we don't have push/pull but -Wformat-nonliteral we can enable -Wformat=2 dnl otherwise none of both gcc_diagnostic_push_pull=no SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" AC_MSG_CHECKING([for gcc diagnostic push / pull]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #pragma GCC diagnostic push #pragma GCC diagnostic pop ]])], [ AC_MSG_RESULT([yes]) gcc_diagnostic_push_pull=yes ], AC_MSG_RESULT([no])) CFLAGS="$SAVED_CFLAGS" if cc_supports_flag "-Wformat-nonliteral"; then gcc_format_nonliteral=yes else gcc_format_nonliteral=no fi # We had to eliminate -Wnested-externs because of libtool changes # Make sure to order options so that the former stand for prerequisites # of the latter (e.g., -Wformat-nonliteral requires -Wformat). EXTRA_FLAGS="-fgnu89-inline -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wdeclaration-after-statement -Wendif-labels -Wfloat-equal -Wformat-security -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Wno-long-long -Wno-strict-aliasing -Wpointer-arith -Wstrict-prototypes -Wwrite-strings -Wunused-but-set-variable -Wunsigned-char" if test "x$gcc_diagnostic_push_pull" = "xyes"; then AC_DEFINE([GCC_FORMAT_NONLITERAL_CHECKING_ENABLED], [], [gcc can complain about nonliterals in format]) EXTRA_FLAGS="$EXTRA_FLAGS -Wformat=2 -Wformat-nonliteral" else if test "x$gcc_format_nonliteral" = "xyes"; then EXTRA_FLAGS="$EXTRA_FLAGS -Wformat=2" fi fi # Additional warnings it might be nice to enable one day # -Wshadow # -Wunreachable-code for j in $EXTRA_FLAGS do if cc_supports_flag $CC_EXTRAS $j then CC_EXTRAS="$CC_EXTRAS $j" fi done 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 dnl dnl Hardening flags dnl dnl The prime control of whether to apply (targeted) hardening build flags and dnl which ones is --{enable,disable}-hardening option passed to ./configure: dnl dnl --enable-hardening=try (default): dnl depending on whether any of CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE, dnl CFLAGS_HARDENED_LIB or LDFLAGS_HARDENED_LIB environment variables dnl (see below) is set and non-null, all these custom flags (even if not dnl set) are used as are, otherwise the best effort is made to offer dnl reasonably strong hardening in several categories (RELRO, PIE, dnl "bind now", stack protector) according to what the selected toolchain dnl can offer dnl dnl --enable-hardening: dnl same effect as --enable-hardening=try when the environment variables dnl in question are suppressed dnl dnl --disable-hardening: dnl do not apply any targeted hardening measures at all dnl dnl The user-injected environment variables that regulate the hardening in dnl default case are as follows: dnl dnl * CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE dnl compiler and linker flags (respectively) for daemon programs dnl (attrd, cib, crmd, lrmd, stonithd, pacemakerd, pacemaker_remoted, dnl pengine) dnl dnl * CFLAGS_HARDENED_LIB, LDFLAGS_HARDENED_LIB dnl compiler and linker flags (respectively) for libraries linked dnl with the daemon programs dnl dnl Note that these are purposedly targeted variables (addressing particular dnl targets all over the scattered Makefiles) and have no effect outside of dnl the predestined scope (e.g., CLI utilities). For a global reach, dnl use CFLAGS, LDFLAGS, etc. as usual. dnl dnl For guidance on the suitable flags consult, for instance: dnl https://fedoraproject.org/wiki/Changes/Harden_All_Packages#Detailed_Harden_Flags_Description dnl https://owasp.org/index.php/C-Based_Toolchain_Hardening#GCC.2FBinutils dnl if test "x${HARDENING}" != "xtry"; then unset CFLAGS_HARDENED_EXE unset CFLAGS_HARDENED_LIB unset LDFLAGS_HARDENED_EXE unset LDFLAGS_HARDENED_LIB fi if test "x${HARDENING}" = "xno"; then AC_MSG_NOTICE([Hardening: explicitly disabled]) elif test "x${HARDENING}" = "xyes" \ || test "$(env | grep -Ec '^(C|LD)FLAGS_HARDENED_(EXE|LIB)=.')" = 0; then dnl We'll figure out on our own... CFLAGS_HARDENED_EXE= CFLAGS_HARDENED_LIB= LDFLAGS_HARDENED_EXE= LDFLAGS_HARDENED_LIB= relro=0 pie=0 bindnow=0 # daemons incl. libs: partial RELRO flag="-Wl,-z,relro" CC_CHECK_LDFLAGS(["${flag}"], [LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"; LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"; relro=1] ) # daemons: PIE for both CFLAGS and LDFLAGS if cc_supports_flag -fPIE; then flag="-pie" CC_CHECK_LDFLAGS(["${flag}"], [CFLAGS_HARDENED_EXE="${CFLAGS_HARDENED_EXE} -fPIE"; LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"; pie=1] ) fi # daemons incl. libs: full RELRO if sensible + as-needed linking # so as to possibly mitigate startup performance # hit caused by excessive linking with unneeded # libraries if test "${relro}" = 1 && test "${pie}" = 1; then flag="-Wl,-z,now" CC_CHECK_LDFLAGS(["${flag}"], [LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"; LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"; bindnow=1] ) fi if test "${bindnow}" = 1; then flag="-Wl,--as-needed" CC_CHECK_LDFLAGS(["${flag}"], [LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}"; LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"] ) fi # universal: prefer strong > all > default stack protector if possible flag= if cc_supports_flag -fstack-protector-strong; then flag="-fstack-protector-strong" elif cc_supports_flag -fstack-protector-all; then flag="-fstack-protector-all" elif cc_supports_flag -fstack-protector; then flag="-fstack-protector" fi if test -n "${flag}"; then CC_EXTRAS="${CC_EXTRAS} ${flag}" stackprot=1 fi if test "${relro}" = 1 \ || test "${pie}" = 1 \ || test "${stackprot}" = 1; then AC_MSG_NOTICE( [Hardening: relro=${relro} pie=${pie} bindnow=${bindnow} stackprot=${flag}]) else AC_MSG_WARN([Hardening: no suitable features in the toolchain detected]) fi else AC_MSG_NOTICE([Hardening: using custom flags]) 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 \ Doxyfile \ coverage.sh \ cts/Makefile \ cts/CTSvars.py \ cts/LSBDummy \ cts/benchmark/Makefile \ cts/benchmark/clubench \ cts/lxc_autogen.sh \ cib/Makefile \ attrd/Makefile \ crmd/Makefile \ pengine/Makefile \ pengine/regression.core.sh \ doc/Makefile \ doc/Clusters_from_Scratch/publican.cfg \ doc/Pacemaker_Development/publican.cfg \ doc/Pacemaker_Explained/publican.cfg \ doc/Pacemaker_Remote/publican.cfg \ include/Makefile \ include/crm/Makefile \ include/crm/cib/Makefile \ include/crm/common/Makefile \ include/crm/cluster/Makefile \ include/crm/fencing/Makefile \ include/crm/pengine/Makefile \ replace/Makefile \ lib/Makefile \ lib/pacemaker.pc \ lib/pacemaker-cib.pc \ lib/pacemaker-lrmd.pc \ lib/pacemaker-service.pc \ lib/pacemaker-pengine.pc \ lib/pacemaker-fencing.pc \ lib/pacemaker-cluster.pc \ 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 \ mcp/pacemaker.upstart \ mcp/pacemaker.combined.upstart \ fencing/Makefile \ fencing/regression.py \ lrmd/Makefile \ lrmd/regression.py \ lrmd/pacemaker_remote.service \ lrmd/pacemaker_remote \ extra/Makefile \ extra/alerts/Makefile \ extra/resources/Makefile \ extra/logrotate/Makefile \ extra/logrotate/pacemaker \ tools/Makefile \ tools/crm_report \ tools/report.common \ tools/cibsecret \ tools/crm_mon.service \ tools/crm_mon.upstart \ 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([]) 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([ CFLAGS_HARDENED_EXE = ${CFLAGS_HARDENED_EXE}]) AC_MSG_RESULT([ CFLAGS_HARDENED_LIB = ${CFLAGS_HARDENED_LIB}]) AC_MSG_RESULT([ LDFLAGS_HARDENED_EXE = ${LDFLAGS_HARDENED_EXE}]) AC_MSG_RESULT([ LDFLAGS_HARDENED_LIB = ${LDFLAGS_HARDENED_LIB}]) AC_MSG_RESULT([ Libraries = ${LIBS}]) AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}]) diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c index 47999f6baf..8819ee9889 100644 --- a/tools/attrd_updater.c +++ b/tools/attrd_updater.c @@ -1,398 +1,391 @@ /* * 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 */ #include #include #include #include #include #include #include #include #include #include #include /* *INDENT-OFF* */ static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\tThis text"}, {"version", 0, 0, '$', "\tVersion information" }, {"verbose", 0, 0, 'V', "\tIncrease debug output\n"}, {"name", 1, 0, 'n', "The attribute's name"}, {"-spacer-",1, 0, '-', "\nCommands:"}, {"update", 1, 0, 'U', "Update the attribute's value in attrd. If this causes the value to change, it will also be updated in the cluster configuration"}, {"update-both", 1, 0, 'B', "Update the attribute's value and time to wait (dampening) in attrd. If this causes the value or dampening to change, the attribute will also be written to the cluster configuration, so be aware that repeatedly changing the dampening reduces its effectiveness."}, #if HAVE_ATOMIC_ATTRD {"update-delay", 0, 0, 'Y', "Update the attribute's dampening in attrd (requires -d/--delay). If this causes the dampening to change, the attribute will also be written to the cluster configuration, so be aware that repeatedly changing the dampening reduces its effectiveness."}, {"query", 0, 0, 'Q', "\tQuery the attribute's value from attrd"}, #endif {"delete", 0, 0, 'D', "\tDelete the attribute in attrd. If a value was previously set, it will also be removed from the cluster configuration"}, {"refresh", 0, 0, 'R', "\t(Advanced) Force the attrd daemon to resend all current values to the CIB\n"}, {"-spacer-",1, 0, '-', "\nAdditional options:"}, {"delay", 1, 0, 'd', "The time to wait (dampening) in seconds for further changes before writing"}, {"set", 1, 0, 's', "(Advanced) The attribute set in which to place the value"}, {"node", 1, 0, 'N', "Set the attribute for the named node (instead of the local one)"}, #if HAVE_ATOMIC_ATTRD {"all", 0, 0, 'A', "Show values of the attribute for all nodes (query only)"}, /* lifetime could be implemented for atomic attrd if there is sufficient user demand */ {"lifetime",1, 0, 'l', "(Deprecated) Lifetime of the node attribute (silently ignored by cluster)"}, {"private", 0, 0, 'p', "\tIf this creates a new attribute, never write the attribute to the CIB"}, #else {"lifetime",1, 0, 'l', "Lifetime of the node attribute. Allowed values: forever, reboot"}, #endif /* Legacy options */ {"quiet", 0, 0, 'q', NULL, pcmk_option_hidden}, {"update", 1, 0, 'v', NULL, pcmk_option_hidden}, {"section", 1, 0, 'S', NULL, pcmk_option_hidden}, {0, 0, 0, 0} }; /* *INDENT-ON* */ #if HAVE_ATOMIC_ATTRD static int do_query(const char *attr_name, const char *attr_node, gboolean query_all); #endif static int do_update(char command, const char *attr_node, const char *attr_name, const char *attr_value, const char *attr_section, const char *attr_set, const char *attr_dampen, int attr_options); int main(int argc, char **argv) { int index = 0; int argerr = 0; int attr_options = attrd_opt_none; int flag; const char *attr_node = NULL; const char *attr_name = NULL; const char *attr_value = NULL; const char *attr_set = NULL; const char *attr_section = NULL; const char *attr_dampen = NULL; char command = 'Q'; #if HAVE_ATOMIC_ATTRD gboolean query_all = FALSE; #endif crm_log_cli_init("attrd_updater"); crm_set_options(NULL, "command -n attribute [options]", long_options, "Tool for updating cluster node attributes"); if (argc < 2) { crm_help('?', EX_USAGE); } while (1) { flag = crm_get_option(argc, argv, &index); if (flag == -1) break; switch (flag) { case 'V': crm_bump_log_level(argc, argv); break; case '?': case '$': crm_help(flag, EX_OK); break; case 'n': attr_name = strdup(optarg); break; case 's': attr_set = strdup(optarg); break; case 'd': attr_dampen = strdup(optarg); break; case 'l': case 'S': attr_section = strdup(optarg); break; case 'N': attr_node = strdup(optarg); break; #if HAVE_ATOMIC_ATTRD case 'A': query_all = TRUE; break; case 'p': set_bit(attr_options, attrd_opt_private); break; #endif case 'q': break; #if HAVE_ATOMIC_ATTRD case 'Y': command = flag; crm_log_args(argc, argv); /* Too much? */ break; case 'Q': #endif case 'B': case 'R': case 'D': case 'U': case 'v': command = flag; attr_value = optarg; crm_log_args(argc, argv); /* Too much? */ break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (command != 'R' && attr_name == NULL) { ++argerr; } if (argerr) { crm_help('?', EX_USAGE); } if (command == 'Q') { #if HAVE_ATOMIC_ATTRD crm_exit(do_query(attr_name, attr_node, query_all)); #else crm_help('?', EX_USAGE); #endif } else { /* @TODO We don't know whether the specified node is a Pacemaker Remote * node or not, so we can't set attrd_opt_remote when appropriate. - * That's OK with atomic attrd, because it will learn and remember a - * node's "remoteness". - * - * Legacy attrd will simply ignore the request if it's a remote node. A - * possible solution would be to call query_node_uuid() (which is the - * approach crm_attribute takes), but that would require linking against - * libcluster, and would add the overhead of a synchronous CIB call to - * every update, even in clusters with no remote nodes. Since we haven't - * had user requests for this support, we'll leave it as it is for now. + * However, it's not a big problem, because attrd will learn and + * remember a node's "remoteness". */ attr_node = attrd_get_target(attr_node); crm_exit(do_update(command, attr_node, attr_name, attr_value, attr_section, attr_set, attr_dampen, attr_options)); } return crm_exit(pcmk_ok); } #if HAVE_ATOMIC_ATTRD /*! * \internal * \brief Submit a query request to attrd and wait for reply * * \param[in] name Name of attribute to query * \param[in] host Query applies to this host only (or all hosts if NULL) * \param[out] reply On success, will be set to new XML tree with reply * * \return pcmk_ok on success, -errno on error * \note On success, caller is responsible for freeing result via free_xml(*reply) */ static int send_attrd_query(const char *name, const char *host, xmlNode **reply) { int rc; crm_ipc_t *ipc; xmlNode *query; /* Build the query XML */ query = create_xml_node(NULL, __FUNCTION__); if (query == NULL) { return -ENOMEM; } crm_xml_add(query, F_TYPE, T_ATTRD); crm_xml_add(query, F_ORIG, crm_system_name); crm_xml_add(query, F_ATTRD_HOST, host); crm_xml_add(query, F_ATTRD_TASK, ATTRD_OP_QUERY); crm_xml_add(query, F_ATTRD_ATTRIBUTE, name); /* Connect to attrd, send query XML and get reply */ crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes")); ipc = crm_ipc_new(T_ATTRD, 0); if (crm_ipc_connect(ipc) == FALSE) { crm_perror(LOG_ERR, "Connection to cluster attribute manager failed"); rc = -ENOTCONN; } else { rc = crm_ipc_send(ipc, query, crm_ipc_flags_none|crm_ipc_client_response, 0, reply); if (rc > 0) { rc = pcmk_ok; } crm_ipc_close(ipc); } free_xml(query); return(rc); } /*! * \brief Validate attrd's XML reply to an query * * param[in] reply Root of reply XML tree to validate * param[in] attr_name Name of attribute that was queried * * \return pcmk_ok on success, * -errno on error (-ENXIO = requested attribute does not exist) */ static int validate_attrd_reply(xmlNode *reply, const char *attr_name) { const char *reply_attr; if (reply == NULL) { fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n", attr_name); return -pcmk_err_schema_validation; } crm_log_xml_trace(reply, "Reply"); reply_attr = crm_element_value(reply, F_ATTRD_ATTRIBUTE); if (reply_attr == NULL) { fprintf(stderr, "Could not query value of %s: attribute does not exist\n", attr_name); return -ENXIO; } if (safe_str_neq(crm_element_value(reply, F_TYPE), T_ATTRD) || (crm_element_value(reply, F_ATTRD_VERSION) == NULL) || strcmp(reply_attr, attr_name)) { fprintf(stderr, "Could not query value of %s: reply did not contain expected identification\n", attr_name); return -pcmk_err_schema_validation; } return pcmk_ok; } /*! * \brief Print the attribute values in an attrd XML query reply * * \param[in] reply Root of XML tree with query reply * \param[in] attr_name Name of attribute that was queried * * \return TRUE if any values were printed */ static gboolean print_attrd_values(xmlNode *reply, const char *attr_name) { xmlNode *child; const char *reply_host, *reply_value; gboolean have_values = FALSE; /* Iterate through reply's XML tags (a node tag for each host-value pair) */ for (child = __xml_first_child(reply); child != NULL; child = __xml_next(child)) { if (safe_str_neq((const char*)child->name, XML_CIB_TAG_NODE)) { crm_warn("Ignoring unexpected %s tag in query reply", child->name); } else { reply_host = crm_element_value(child, F_ATTRD_HOST); reply_value = crm_element_value(child, F_ATTRD_VALUE); if (reply_host == NULL) { crm_warn("Ignoring %s tag without %s attribute in query reply", XML_CIB_TAG_NODE, F_ATTRD_HOST); } else { printf("name=\"%s\" host=\"%s\" value=\"%s\"\n", attr_name, reply_host, (reply_value? reply_value : "")); have_values = TRUE; } } } return have_values; } /*! * \brief Submit a query to attrd and print reply * * \param[in] attr_name Name of attribute to be affected by request * \param[in] attr_node Name of host to query for (or NULL for localhost) * \param[in] query_all If TRUE, ignore attr_node and query all nodes instead * * \return pcmk_ok on success, -errno on error */ static int do_query(const char *attr_name, const char *attr_node, gboolean query_all) { xmlNode *reply = NULL; int rc; /* Decide which node(s) to query */ if (query_all == TRUE) { attr_node = NULL; } else { attr_node = attrd_get_target(attr_node); } /* Build and send attrd request, and get XML reply */ rc = send_attrd_query(attr_name, attr_node, &reply); if (rc != pcmk_ok) { fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc); return rc; } /* Validate the XML reply */ rc = validate_attrd_reply(reply, attr_name); if (rc != pcmk_ok) { if (reply != NULL) { free_xml(reply); } return rc; } /* Print the values from the reply */ if (print_attrd_values(reply, attr_name) == FALSE) { fprintf(stderr, "Could not query value of %s: reply had attribute name but no host values\n", attr_name); free_xml(reply); return -pcmk_err_schema_validation; } return pcmk_ok; } #endif static int do_update(char command, const char *attr_node, const char *attr_name, const char *attr_value, const char *attr_section, const char *attr_set, const char *attr_dampen, int attr_options) { int rc = attrd_update_delegate(NULL, command, attr_node, attr_name, attr_value, attr_section, attr_set, attr_dampen, NULL, attr_options); if (rc != pcmk_ok) { fprintf(stderr, "Could not update %s=%s: %s (%d)\n", attr_name, attr_value, pcmk_strerror(rc), rc); } return rc; }