Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/admin/crm_verify.c b/crm/admin/crm_verify.c
index d3d75400a0..584cf7e1e3 100644
--- a/crm/admin/crm_verify.c
+++ b/crm/admin/crm_verify.c
@@ -1,327 +1,325 @@
/* $Id: crm_verify.c,v 1.20 2006/08/20 10:54:57 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <clplumbing/cl_signal.h>
#include <crm/cib.h>
#include <clplumbing/lsb_exitcodes.h>
#define OPTARGS "V?X:x:pLS:"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <crm/pengine/status.h>
gboolean USE_LIVE_CIB = FALSE;
char *cib_save = NULL;
const char *crm_system_name = NULL;
void usage(const char *cmd, int exit_status);
extern gboolean stage0(pe_working_set_t *data_set);
void cleanup_alloc_calculations(pe_working_set_t *data_set);
int
main(int argc, char **argv)
{
crm_data_t *cib_object = NULL;
crm_data_t *status = NULL;
int argerr = 0;
int flag;
pe_working_set_t data_set;
cib_t * cib_conn = NULL;
int rc = cib_ok;
gboolean xml_stdin = FALSE;
const char *xml_file = NULL;
const char *xml_string = NULL;
crm_system_name = basename(argv[0]);
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... - this enum is a bit field (!) */
g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
cl_log_set_entity(crm_system_name);
cl_log_set_facility(LOG_LOCAL7);
cl_log_enable_stderr(TRUE);
set_crm_log_level(LOG_ERR);
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{F_CRM_DATA, 1, 0, 'X'},
{"xml-file", 1, 0, 'x'},
{"xml-pipe", 0, 0, 'p'},
{"save-xml", 1, 0, 'S'},
{"live-check", 0, 0, 'L'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}
};
#endif
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
#endif
case 'X':
crm_debug_2("Option %c => %s", flag, optarg);
xml_string = crm_strdup(optarg);
break;
case 'x':
crm_debug_2("Option %c => %s", flag, optarg);
xml_file = crm_strdup(optarg);
break;
case 'p':
xml_stdin = TRUE;
break;
case 'S':
cib_save = crm_strdup(optarg);
break;
case 'V':
alter_debug(DEBUG_INC);
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage(crm_system_name, LSB_EXIT_GENERIC);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
- crm_zero_mem_stats(NULL);
#ifdef HA_MALLOC_TRACK
cl_malloc_dump_allocated(LOG_DEBUG_2, TRUE);
#endif
if(USE_LIVE_CIB) {
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_command_synchronous);
}
if(USE_LIVE_CIB) {
if(rc == cib_ok) {
int options = cib_scope_local|cib_sync_call;
crm_info("Reading XML from: live cluster");
rc = cib_conn->cmds->query(
cib_conn, NULL, &cib_object, options);
}
if(rc != cib_ok) {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
cib_object = file2xml(xml_strm, FALSE);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input file: %s\n", xml_file);
return 1;
}
} else if(xml_string != NULL) {
cib_object = string2xml(xml_string);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input string: %s\n", xml_string);
return 1;
}
} else if(xml_stdin) {
cib_object = stdin2xml();
if(cib_object == NULL) {
fprintf(stderr, "Couldn't parse input from STDIN.\n");
return 1;
}
} else {
fprintf(stderr, "No configuration source specified."
" Use --help for usage information.\n");
return 3;
}
if(cib_save != NULL) {
write_xml_file(cib_object, cib_save, FALSE);
}
status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
#if CRM_DEPRECATED_SINCE_2_0_4
xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE,
xml_remove_prop(node_state, XML_CIB_TAG_LRM);
);
#endif
crm_notice("Required feature set: %s", feature_set(cib_object));
if(do_id_check(cib_object, NULL, FALSE, FALSE)) {
crm_config_err("ID Check failed");
}
if(validate_with_dtd(
cib_object, FALSE, HA_LIBDIR"/heartbeat/crm.dtd") == FALSE) {
crm_config_err("CIB did not pass DTD validation");
}
set_working_set_defaults(&data_set);
data_set.input = cib_object;
data_set.now = new_ha_date(TRUE);
stage0(&data_set);
cleanup_alloc_calculations(&data_set);
#if 0
if(USE_LIVE_CIB) {
/* Calling msg2ipcchan() seems to initialize something
* which isn't free'd when we disconnect and free the
* CIB connection.
* Fake this extra free and move along.
*/
volatile cl_mem_stats_t *active_stats = cl_malloc_getstats();
active_stats->numfree++;
}
#endif
if(crm_config_error) {
fprintf(stderr, "Errors found during check: config not valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " -V may provide more details\n");
}
rc = 2;
} else if(crm_config_warning) {
fprintf(stderr, "Warnings found during check: config may not be valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " Use -V for more details\n");
}
rc = 1;
}
if(USE_LIVE_CIB) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
- CRM_CHECK(crm_mem_stats(NULL) == FALSE, ; );
#ifdef HA_MALLOC_TRACK
cl_malloc_dump_allocated(LOG_ERR, TRUE);
#endif
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-V] -(?|L|X|x|p)\n", cmd);
fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c)\t: "
"turn on debug info. additional instances increase verbosity\n",
"verbose", 'V');
fprintf(stream, "\t--%s (-%c)\t: Connect to the running cluster\n",
"live-check", 'L');
fprintf(stream, "\t--%s (-%c) <string>\t: Use the configuration in the supplied string\n",
F_CRM_DATA, 'X');
fprintf(stream, "\t--%s (-%c) <file>\t: Use the configuration in the named file\n",
"xml-file", 'x');
fprintf(stream, "\t--%s (-%c) \t\t: Use the configuration piped in via stdin\n",
"xml-pipe", 'p');
fflush(stream);
exit(exit_status);
}
diff --git a/crm/admin/xml_diff.c b/crm/admin/xml_diff.c
index 21cef1de62..d8688e621f 100644
--- a/crm/admin/xml_diff.c
+++ b/crm/admin/xml_diff.c
@@ -1,273 +1,264 @@
/* $Id: xml_diff.c,v 1.11 2006/07/18 06:15:54 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <ha_msg.h> /* someone complaining about _ha_msg_mod not being found */
#include <crm/dmalloc_wrapper.h>
const char *crm_system_name = "diff";
void usage(const char *cmd, int exit_status);
#define OPTARGS "V?o:n:p:scfO:N:"
int
main(int argc, char **argv)
{
gboolean apply = FALSE;
gboolean raw_1 = FALSE;
gboolean raw_2 = FALSE;
gboolean filter = FALSE;
gboolean use_stdin = FALSE;
gboolean as_cib = FALSE;
int argerr = 0;
int flag;
crm_data_t *object_1 = NULL;
crm_data_t *object_2 = NULL;
crm_data_t *output = NULL;
const char *xml_file_1 = NULL;
const char *xml_file_2 = NULL;
- long new_bytes = 0, new_allocs = 0, new_frees = 0;
- long old_bytes = 0, old_allocs = 0, old_frees = 0;
-
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"original", 1, 0, 'o'},
{"new", 1, 0, 'n'},
{"original-string", 1, 0, 'O'},
{"new-string", 1, 0, 'N'},
{"patch", 1, 0, 'p'},
{"stdin", 0, 0, 's'},
{"cib", 0, 0, 'c'},
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}
};
#endif
cl_log_set_entity(crm_system_name);
cl_log_set_facility(LOG_USER);
set_crm_log_level(LOG_CRIT-1);
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
case 'o':
xml_file_1 = optarg;
break;
case 'O':
xml_file_1 = optarg;
raw_1 = TRUE;
break;
case 'n':
xml_file_2 = optarg;
break;
case 'N':
xml_file_2 = optarg;
raw_2 = TRUE;
break;
case 'p':
xml_file_2 = optarg;
apply = TRUE;
break;
case 'f':
filter = TRUE;
break;
case 's':
use_stdin = TRUE;
break;
case 'c':
as_cib = TRUE;
break;
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
default:
printf("Argument code 0%o (%c)"
" is not (?yet?) supported\n",
flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
- crm_zero_mem_stats(NULL);
-
if(raw_1) {
object_1 = string2xml(xml_file_1);
} else if(use_stdin) {
fprintf(stderr, "Input first XML fragment:");
object_1 = stdin2xml();
} else if(xml_file_1 != NULL) {
FILE *xml_strm = fopen(xml_file_1, "r");
if(xml_strm != NULL) {
crm_debug("Reading: %s", xml_file_1);
object_1 = file2xml(xml_strm, FALSE);
} else {
cl_perror("File not found: %s", xml_file_1);
}
}
if(raw_2) {
object_2 = string2xml(xml_file_2);
} else if(use_stdin) {
fprintf(stderr, "Input second XML fragment:");
object_2 = stdin2xml();
} else if(xml_file_2 != NULL) {
FILE *xml_strm = fopen(xml_file_2, "r");
if(xml_strm != NULL) {
crm_debug("Reading: %s", xml_file_2);
object_2 = file2xml(xml_strm, FALSE);
} else {
cl_perror("File not found: %s", xml_file_2);
}
}
CRM_ASSERT(object_1 != NULL);
CRM_ASSERT(object_2 != NULL);
- crm_zero_mem_stats(NULL);
-
if(apply) {
if(as_cib == FALSE) {
apply_xml_diff(object_1, object_2, &output);
} else {
apply_cib_diff(object_1, object_2, &output);
}
} else {
if(as_cib == FALSE) {
output = diff_xml_object(object_1, object_2, filter);
} else {
output = diff_cib_object(object_1, object_2, filter);
}
}
if(output != NULL) {
char *buffer = dump_xml_formatted(output);
fprintf(stdout, "%s", crm_str(buffer));
crm_free(buffer);
}
- crm_xml_nbytes(output, &new_bytes, &new_allocs, &new_frees);
- crm_adjust_mem_stats(crm_running_stats, new_bytes - old_bytes,
- new_allocs - old_allocs, new_frees - old_frees);
-
- crm_mem_stats(NULL);
-
free_xml(object_1);
free_xml(object_2);
free_xml(output);
+#ifdef HA_MALLOC_TRACK
+ cl_malloc_dump_allocated(LOG_ERR, FALSE);
+#endif
+
if(apply == FALSE && output != NULL) {
return 1;
}
return 0;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status != 0 ? stderr : stdout;
fprintf(stream, "usage: %s [-?V] [oO] [pnN]\n", cmd);
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?');
fprintf(stream, "\t--%s (-%c) <filename>\t\n", "original", 'o');
fprintf(stream, "\t--%s (-%c) <filename>\t\n", "new", 'n');
fprintf(stream, "\t--%s (-%c) <string>\t\n", "original-string", 'O');
fprintf(stream, "\t--%s (-%c) <string>\t\n", "new-string", 'N');
fprintf(stream, "\t--%s (-%c) <filename>\tApply a patch to the original XML\n", "patch", 'p');
fprintf(stream, "\t--%s (-%c)\tCompare/patch the inputs as a CIB\n", "cib", 'c');
fprintf(stream, "\t--%s (-%c)\tRead the inputs from stdin\n", "stdin", 's');
fflush(stream);
exit(exit_status);
}
diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index 414cf9ccee..9ef841ed02 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,1978 +1,1914 @@
/* $Id: callbacks.c,v 1.140 2006/07/18 06:20:07 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/cl_uuid.h>
#include <clplumbing/cl_malloc.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <cibmessages.h>
#include <cibprimatives.h>
#include <notify.h>
#include <crm/dmalloc_wrapper.h>
extern GMainLoop* mainloop;
extern gboolean cib_shutdown_flag;
extern gboolean stand_alone;
extern enum cib_errors cib_update_counter(
crm_data_t *xml_obj, const char *field, gboolean reset);
extern void GHFunc_count_peers(
gpointer key, gpointer value, gpointer user_data);
extern enum cib_errors revision_check(
crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
void initiate_exit(void);
void terminate_ha_connection(const char *caller);
gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
gboolean cib_msg_timeout(gpointer data);
void cib_GHFunc(gpointer key, gpointer value, gpointer user_data);
gboolean can_write(int flags);
HA_Message *cib_msg_copy(HA_Message *msg, gboolean with_data);
gboolean ccm_manual_check(gpointer data);
void send_cib_replace(const HA_Message *sync_request, const char *host);
void cib_process_request(
HA_Message *request, gboolean privileged, gboolean force_synchronous,
gboolean from_peer, cib_client_t *cib_client);
gboolean syncd_once = FALSE;
GHashTable *peer_hash = NULL;
int next_client_id = 0;
gboolean cib_is_master = FALSE;
gboolean cib_have_quorum = FALSE;
char * ccm_transition_id = NULL;
GHashTable *client_list = NULL;
GHashTable *ccm_membership = NULL;
extern const char *cib_our_uname;
extern ll_cluster_t *hb_conn;
extern unsigned long cib_num_ops, cib_num_local, cib_num_updates, cib_num_fail;
extern unsigned long cib_bad_connects, cib_num_timeouts;
extern longclock_t cib_call_time;
extern enum cib_errors cib_status;
static HA_Message *
cib_prepare_common(HA_Message *root, const char *section)
{
HA_Message *data = NULL;
/* extract the CIB from the fragment */
if(root == NULL) {
return NULL;
} else if(safe_str_eq(crm_element_name(root), XML_TAG_FRAGMENT)) {
data = find_xml_node(root, XML_TAG_CIB, TRUE);
if(data != NULL) {
crm_debug_3("Extracted CIB from "XML_TAG_FRAGMENT);
} else {
crm_log_xml_debug_4(root, "No CIB");
}
} else {
data = root;
crm_log_xml_debug_4(root, "cib:input");
}
/* grab the section specified for the command */
if(data != NULL && safe_str_eq(crm_element_name(data), XML_TAG_CIB)){
int rc = revision_check(data, the_cib, 0/* call_options */);
if(rc == cib_ok) {
data = get_object_root(section, data);
if(data != NULL) {
crm_debug_3("Extracted %s from CIB", section);
} else {
crm_log_xml_debug_4(root, "No Section");
}
} else {
crm_debug_2("Revision check failed");
}
}
return data;
}
static gboolean
verify_section(const char *section)
{
if(section == NULL) {
return TRUE;
} else if(safe_str_eq(section, XML_TAG_CIB)) {
return TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
return TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) {
return TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
return TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_RESOURCES)) {
return TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_CONSTRAINTS)) {
return TRUE;
}
return FALSE;
}
static enum cib_errors
cib_prepare_none(HA_Message *request, HA_Message **data, const char **section)
{
*data = NULL;
*section = cl_get_string(request, F_CIB_SECTION);
if(verify_section(*section) == FALSE) {
return cib_bad_section;
}
return cib_ok;
}
static enum cib_errors
cib_prepare_data(HA_Message *request, HA_Message **data, const char **section)
{
HA_Message *input_fragment = cl_get_struct(request, F_CIB_CALLDATA);
*section = cl_get_string(request, F_CIB_SECTION);
*data = cib_prepare_common(input_fragment, *section);
if(verify_section(*section) == FALSE) {
return cib_bad_section;
}
return cib_ok;
}
static enum cib_errors
cib_prepare_sync(HA_Message *request, HA_Message **data, const char **section)
{
*section = cl_get_string(request, F_CIB_SECTION);
*data = request;
if(verify_section(*section) == FALSE) {
return cib_bad_section;
}
return cib_ok;
}
static enum cib_errors
cib_prepare_diff(HA_Message *request, HA_Message **data, const char **section)
{
HA_Message *input_fragment = NULL;
const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
*data = NULL;
*section = NULL;
if(crm_is_true(update)) {
input_fragment = cl_get_struct(request,F_CIB_UPDATE_DIFF);
} else {
input_fragment = cl_get_struct(request, F_CIB_CALLDATA);
}
CRM_CHECK(input_fragment != NULL,crm_log_message(LOG_WARNING, request));
*data = cib_prepare_common(input_fragment, NULL);
return cib_ok;
}
static enum cib_errors
cib_cleanup_query(const char *op, HA_Message **data, HA_Message **output)
{
CRM_DEV_ASSERT(*data == NULL);
return cib_ok;
}
static enum cib_errors
cib_cleanup_output(const char *op, HA_Message **data, HA_Message **output)
{
free_xml(*output);
return cib_ok;
}
static enum cib_errors
cib_cleanup_none(const char *op, HA_Message **data, HA_Message **output)
{
CRM_DEV_ASSERT(*data == NULL);
CRM_DEV_ASSERT(*output == NULL);
return cib_ok;
}
static enum cib_errors
cib_cleanup_sync(const char *op, HA_Message **data, HA_Message **output)
{
/* data is non-NULL but doesnt need to be free'd */
CRM_DEV_ASSERT(*output == NULL);
return cib_ok;
}
/*
typedef struct cib_operation_s
{
const char* operation;
gboolean modifies_cib;
gboolean needs_privileges;
gboolean needs_quorum;
enum cib_errors (*prepare)(HA_Message *, crm_data_t**, const char **);
enum cib_errors (*cleanup)(crm_data_t**, crm_data_t**);
enum cib_errors (*fn)(
const char *, int, const char *,
crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**);
} cib_operation_t;
*/
/* technically bump does modify the cib...
* but we want to split the "bump" from the "sync"
*/
cib_operation_t cib_server_ops[] = {
{NULL, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_default},
{CIB_OP_QUERY, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_query, cib_process_query},
{CIB_OP_MODIFY, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_modify},
{CIB_OP_UPDATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_change},
{CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, cib_prepare_diff, cib_cleanup_sync, cib_process_diff},
{CIB_OP_SLAVE, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite},
{CIB_OP_SLAVEALL, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite},
{CIB_OP_SYNC_ONE, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync_one},
{CIB_OP_MASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite},
{CIB_OP_ISMASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite},
{CIB_OP_BUMP, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_bump},
{CIB_OP_REPLACE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_replace},
{CIB_OP_CREATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_change},
{CIB_OP_DELETE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_delete},
{CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_output, cib_process_change},
{CIB_OP_SYNC, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync},
{CRM_OP_QUIT, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_quit},
{CRM_OP_PING, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_output, cib_process_ping},
{CIB_OP_ERASE, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_erase},
{CRM_OP_NOOP, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_default},
{"cib_shutdown_req",FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_shutdown_req},
};
int send_via_callback_channel(HA_Message *msg, const char *token);
enum cib_errors cib_process_command(
HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged);
gboolean cib_common_callback(IPC_Channel *channel, cib_client_t *cib_client,
gboolean force_synchronous, gboolean privileged);
enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation);
gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client);
int num_clients = 0;
static void
cib_ipc_connection_destroy(gpointer user_data)
{
cib_client_t *cib_client = user_data;
/* cib_process_disconnect */
if(cib_client == NULL) {
crm_debug_4("Destroying %p", user_data);
return;
}
if(cib_client->source != NULL) {
crm_debug_4("Deleting %s (%p) from mainloop",
cib_client->name, cib_client->source);
G_main_del_IPC_Channel(cib_client->source);
cib_client->source = NULL;
}
crm_debug_3("Destroying %s (%p)", cib_client->name, user_data);
num_clients--;
crm_debug("Num unfree'd clients: %d", num_clients);
START_stat_free_op();
crm_free(cib_client->name);
crm_free(cib_client->callback_id);
crm_free(cib_client->id);
crm_free(cib_client);
END_stat_free_op();
crm_debug_4("Freed the cib client");
return;
}
static cib_client_t *
cib_client_connect_common(
IPC_Channel *channel, const char *channel_name,
gboolean (*callback)(IPC_Channel *channel, gpointer user_data))
{
gboolean can_connect = TRUE;
cib_client_t *new_client = NULL;
crm_debug_3("Connecting channel");
if (channel == NULL) {
crm_err("Channel was NULL");
can_connect = FALSE;
cib_bad_connects++;
} else if (channel->ch_status != IPC_CONNECT) {
crm_err("Channel was disconnected");
can_connect = FALSE;
cib_bad_connects++;
} else if(channel_name == NULL) {
crm_err("user_data must contain channel name");
can_connect = FALSE;
cib_bad_connects++;
} else if(cib_shutdown_flag) {
crm_info("Ignoring new client [%d] during shutdown",
channel->farside_pid);
return NULL;
} else {
START_stat_free_op();
crm_malloc0(new_client, sizeof(cib_client_t));
END_stat_free_op();
num_clients++;
new_client->channel = channel;
new_client->channel_name = channel_name;
crm_debug_3("Created channel %p for channel %s",
new_client, new_client->channel_name);
channel->ops->set_recv_qlen(channel, 100);
channel->ops->set_send_qlen(channel, 400);
if(callback != NULL) {
new_client->source = G_main_add_IPC_Channel(
G_PRIORITY_DEFAULT, channel, FALSE, callback,
new_client, cib_ipc_connection_destroy);
}
crm_debug_3("Channel %s connected for client %s",
new_client->channel_name, new_client->id);
}
return new_client;
}
gboolean
cib_client_connect_rw_synch(IPC_Channel *channel, gpointer user_data)
{
- cl_mem_stats_t saved_stats;
cib_client_t *new_client = NULL;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
new_client = cib_client_connect_common(
channel, cib_channel_rw_synchronous, cib_rw_synchronous_callback);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
if(new_client == NULL) {
return FALSE;
}
return TRUE;
}
gboolean
cib_client_connect_ro_synch(IPC_Channel *channel, gpointer user_data)
{
- cl_mem_stats_t saved_stats;
cib_client_t *new_client = NULL;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
new_client = cib_client_connect_common(
channel, cib_channel_ro_synchronous, cib_ro_synchronous_callback);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
if(new_client == NULL) {
return FALSE;
}
return TRUE;
}
gboolean
cib_client_connect_rw_ro(IPC_Channel *channel, gpointer user_data)
{
cl_uuid_t client_id;
HA_Message *reg_msg = NULL;
cib_client_t *new_client = NULL;
char uuid_str[UU_UNPARSE_SIZEOF];
gboolean (*callback)(IPC_Channel *channel, gpointer user_data);
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
callback = cib_ro_callback;
if(safe_str_eq(user_data, cib_channel_rw)) {
callback = cib_rw_callback;
}
new_client = cib_client_connect_common(
channel,
callback==cib_ro_callback?cib_channel_ro:cib_channel_rw,
callback);
if(new_client == NULL) {
return FALSE;
}
cl_uuid_generate(&client_id);
cl_uuid_unparse(&client_id, uuid_str);
START_stat_free_op();
CRM_CHECK(new_client->id == NULL, crm_free(new_client->id));
new_client->id = crm_strdup(uuid_str);
END_stat_free_op();
cl_uuid_generate(&client_id);
cl_uuid_unparse(&client_id, uuid_str);
START_stat_free_op();
CRM_CHECK(new_client->callback_id == NULL, crm_free(new_client->callback_id));
new_client->callback_id = crm_strdup(uuid_str);
END_stat_free_op();
/* make sure we can find ourselves later for sync calls
* redirected to the master instance
*/
START_stat_free_op();
g_hash_table_insert(
client_list, new_client->id, new_client);
END_stat_free_op();
reg_msg = ha_msg_new(3);
ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(reg_msg, F_CIB_CLIENTID, new_client->id);
ha_msg_add(
reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id);
send_ipc_message(channel, reg_msg);
crm_msg_del(reg_msg);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
return TRUE;
}
gboolean
cib_client_connect_null(IPC_Channel *channel, gpointer user_data)
{
- cl_mem_stats_t saved_stats;
cib_client_t *new_client = NULL;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
new_client = cib_client_connect_common(
channel, cib_channel_callback, cib_null_callback);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
if(new_client == NULL) {
return FALSE;
}
return TRUE;
}
gboolean
cib_rw_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean result = FALSE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
result = cib_common_callback(channel, user_data, FALSE, TRUE);
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return result;
}
gboolean
cib_ro_synchronous_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean result = FALSE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
result = cib_common_callback(channel, user_data, TRUE, FALSE);
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return result;
}
gboolean
cib_rw_synchronous_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean result = FALSE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
result = cib_common_callback(channel, user_data, TRUE, TRUE);
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return result;
}
gboolean
cib_ro_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean result = FALSE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
result = cib_common_callback(channel, user_data, FALSE, FALSE);
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return result;
}
gboolean
cib_null_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean keep_connection = TRUE;
HA_Message *op_request = NULL;
HA_Message *registered = NULL;
cib_client_t *cib_client = user_data;
cib_client_t *hash_client = NULL;
const char *type = NULL;
const char *uuid_ticket = NULL;
const char *client_name = NULL;
gboolean register_failed = FALSE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if(cib_client == NULL) {
crm_err("Discarding IPC message from unknown source"
" on callback channel.");
return FALSE;
}
while(IPC_ISRCONN(channel)) {
crm_msg_del(op_request);
if(channel->ops->is_message_pending(channel) == 0) {
break;
}
op_request = msgfromIPC_noauth(channel);
if(op_request == NULL) {
break;
}
type = cl_get_string(op_request, F_CIB_OPERATION);
if(safe_str_eq(type, T_CIB_NOTIFY) ) {
/* Update the notify filters for this client */
int on_off = 0;
ha_msg_value_int(
op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE);
crm_info("Setting %s callbacks for %s: %s",
type, cib_client->name, on_off?"on":"off");
if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
cib_client->post_notify = on_off;
} else if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
cib_client->pre_notify = on_off;
} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
cib_client->confirmations = on_off;
} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
cib_client->diffs = on_off;
} else if(safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
cib_client->replace = on_off;
}
continue;
} else if(safe_str_neq(type, CRM_OP_REGISTER) ) {
crm_warn("Discarding IPC message from %s on callback channel",
cib_client->id);
continue;
}
uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN);
client_name = cl_get_string(op_request, F_CIB_CLIENTNAME);
CRM_DEV_ASSERT(uuid_ticket != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
CRM_DEV_ASSERT(client_name != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
if(register_failed == FALSE) {
hash_client = g_hash_table_lookup(client_list, uuid_ticket);
if(hash_client != NULL) {
crm_err("Duplicate registration request..."
" disconnecting");
register_failed = TRUE;
}
}
if(register_failed) {
crm_err("Registration request failed... disconnecting");
crm_msg_del(op_request);
return FALSE;
}
START_stat_free_op();
CRM_CHECK(cib_client->id == NULL, crm_free(cib_client->id));
CRM_CHECK(cib_client->name == NULL, crm_free(cib_client->name));
cib_client->id = crm_strdup(uuid_ticket);
cib_client->name = crm_strdup(client_name);
g_hash_table_insert(client_list, cib_client->id, cib_client);
END_stat_free_op();
crm_debug_2("Registered %s on %s channel",
cib_client->id, cib_client->channel_name);
if(safe_str_eq(cib_client->name, CRM_SYSTEM_TENGINE)) {
/* The TE is _always_ interested in these
* Enable now to avoid timing issues
*/
cib_client->diffs = TRUE;
}
registered = ha_msg_new(2);
ha_msg_add(registered, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(registered, F_CIB_CLIENTID, cib_client->id);
send_ipc_message(channel, registered);
crm_msg_del(registered);
if(channel->ch_status == IPC_CONNECT) {
break;
}
}
crm_msg_del(op_request);
if(channel->ch_status != IPC_CONNECT) {
crm_debug_2("Client disconnected");
keep_connection = cib_process_disconnect(channel, cib_client);
}
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return keep_connection;
}
void
cib_common_callback_worker(HA_Message *op_request, cib_client_t *cib_client,
gboolean force_synchronous, gboolean privileged);
void
cib_common_callback_worker(HA_Message *op_request, cib_client_t *cib_client,
gboolean force_synchronous, gboolean privileged)
{
int rc = cib_ok;
int call_type = 0;
const char *op = NULL;
longclock_t call_stop = 0;
longclock_t call_start = 0;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
call_start = time_longclock();
cib_client->num_calls++;
op = cl_get_string(op_request, F_CIB_OPERATION);
rc = cib_get_operation_id(op_request, &call_type);
if(rc != cib_ok) {
crm_debug("Invalid operation %s from %s/%s",
op, cib_client->name, cib_client->channel_name);
} else {
crm_debug_2("Processing %s operation from %s/%s",
op, cib_client->name, cib_client->channel_name);
}
if(rc == cib_ok) {
cib_process_request(
op_request, force_synchronous, privileged, FALSE,
cib_client);
}
call_stop = time_longclock();
cib_call_time += (call_stop - call_start);
-
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
gboolean
cib_common_callback(IPC_Channel *channel, cib_client_t *cib_client,
gboolean force_synchronous, gboolean privileged)
{
int lpc = 0;
HA_Message *op_request = NULL;
gboolean keep_channel = TRUE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if(cib_client == NULL) {
crm_err("Receieved call from unknown source. Discarding.");
return FALSE;
}
START_stat_free_op();
if(cib_client->name == NULL) {
cib_client->name = crm_itoa(channel->farside_pid);
}
if(cib_client->id == NULL) {
cib_client->id = crm_strdup(cib_client->name);
g_hash_table_insert(client_list, cib_client->id, cib_client);
}
END_stat_free_op();
crm_debug_2("Callback for %s on %s channel",
cib_client->id, cib_client->channel_name);
while(IPC_ISRCONN(channel)) {
if(channel->ops->is_message_pending(channel) == 0) {
break;
}
op_request = msgfromIPC_noauth(channel);
if (op_request == NULL) {
perror("Receive failure:");
break;
}
lpc++;
crm_assert_failed = FALSE;
crm_log_message_adv(LOG_MSG, "Client[inbound]", op_request);
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id);
ha_msg_add(op_request, F_CIB_CLIENTNAME, cib_client->name);
cib_common_callback_worker(
op_request, cib_client, force_synchronous, privileged);
crm_msg_del(op_request);
if(channel->ch_status == IPC_CONNECT) {
break;
}
}
crm_debug_2("Processed %d messages", lpc);
if(channel->ch_status != IPC_CONNECT) {
crm_debug_2("Client disconnected");
keep_channel = cib_process_disconnect(channel, cib_client);
}
- crm_diff_mem_stats(LOG_WARNING, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
return keep_channel;
}
static void
do_local_notify(HA_Message *notify_src, const char *client_id, gboolean sync_reply, gboolean from_peer)
{
/* send callback to originating child */
cib_client_t *client_obj = NULL;
HA_Message *client_reply = NULL;
enum cib_errors local_rc = cib_ok;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
crm_debug_2("Performing notification");
client_reply = cib_msg_copy(notify_src, TRUE);
if(client_id != NULL) {
client_obj = g_hash_table_lookup(
client_list, client_id);
} else {
crm_debug_2("No client to sent the response to."
" F_CIB_CLIENTID not set.");
}
crm_debug_3("Sending callback to request originator");
if(client_obj == NULL) {
local_rc = cib_reply_failed;
} else {
const char *client_id = client_obj->callback_id;
crm_debug_2("Sending %ssync response to %s %s",
sync_reply?"":"an a-",
client_obj->name,
from_peer?"(originator of delegated request)":"");
if(sync_reply) {
client_id = client_obj->id;
}
local_rc = send_via_callback_channel(client_reply, client_id);
}
if(local_rc != cib_ok && client_obj != NULL) {
crm_warn("%sSync reply to %s failed: %s",
sync_reply?"":"A-",
client_obj?client_obj->name:"<unknown>", cib_error2string(local_rc));
}
ha_msg_del(client_reply);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
static void
parse_local_options(
cib_client_t *cib_client, int call_type, int call_options, const char *host, const char *op,
gboolean *local_notify, gboolean *needs_reply, gboolean *process, gboolean *needs_forward)
{
if(cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_inhibit_bcast)) {
/* we need to send an update anyway */
*needs_reply = TRUE;
} else {
*needs_reply = FALSE;
}
if(host == NULL && (call_options & cib_scope_local)) {
crm_debug("Processing locally scoped %s op from %s",
op, cib_client->name);
*local_notify = TRUE;
} else if(host == NULL && cib_is_master) {
crm_debug("Processing master %s op locally from %s",
op, cib_client->name);
*local_notify = TRUE;
} else if(safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing locally addressed %s op from %s",
op, cib_client->name);
*local_notify = TRUE;
} else {
crm_debug("%s op from %s needs to be forwarded to %s",
op, cib_client->name,
host?host:"the master instance");
*needs_forward = TRUE;
*process = FALSE;
}
}
static gboolean
parse_peer_options(
int call_type, HA_Message *request,
gboolean *local_notify, gboolean *needs_reply, gboolean *process, gboolean *needs_forward)
{
const char *op = cl_get_string(request, F_CIB_OPERATION);
const char *originator = cl_get_string(request, F_ORIG);
const char *host = cl_get_string(request, F_CIB_HOST);
const char *reply_to = cl_get_string(request, F_CIB_ISREPLY);
const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
const char *delegated = cl_get_string(request, F_CIB_DELEGATED);
if(safe_str_eq(op, "cib_shutdown_req")) {
if(reply_to != NULL) {
crm_debug("Processing %s from %s", op, host);
*needs_reply = FALSE;
} else {
crm_debug("Processing %s reply from %s", op, host);
}
return TRUE;
} else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Processing global/peer update from %s"
" that originated from us", originator);
*needs_reply = FALSE;
if(cl_get_string(request, F_CIB_CLIENTID) != NULL) {
*local_notify = TRUE;
}
return TRUE;
} else if(crm_is_true(update)) {
crm_debug("Processing global/peer update from %s", originator);
*needs_reply = FALSE;
return TRUE;
} else if(host != NULL && safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing request sent to us from %s", originator);
return TRUE;
} else if(delegated != NULL && cib_is_master == TRUE) {
crm_debug("Processing request sent to master instance from %s",
originator);
return TRUE;
} else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Forward reply sent from %s to local clients",
originator);
*process = FALSE;
*needs_reply = FALSE;
*local_notify = TRUE;
return TRUE;
} else if(delegated != NULL) {
crm_debug("Ignoring msg for master instance");
} else if(host != NULL) {
/* this is for a specific instance and we're not it */
crm_debug("Ignoring msg for instance on %s", crm_str(host));
} else if(reply_to == NULL && cib_is_master == FALSE) {
/* this is for the master instance and we're not it */
crm_debug("Ignoring reply to %s", crm_str(reply_to));
} else {
crm_err("Nothing for us to do?");
crm_log_message_adv(LOG_ERR, "Peer[inbound]", request);
}
return FALSE;
}
static void
forward_request(HA_Message *request, cib_client_t *cib_client, int call_options)
{
HA_Message *forward_msg = NULL;
- cl_mem_stats_t saved_stats;
const char *op = cl_get_string(request, F_CIB_OPERATION);
const char *host = cl_get_string(request, F_CIB_HOST);
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
forward_msg = cib_msg_copy(request, TRUE);
ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname);
if(host != NULL) {
crm_debug_2("Forwarding %s op to %s", op, host);
send_ha_message(hb_conn, forward_msg, host, FALSE);
} else {
crm_debug_2("Forwarding %s op to master instance", op);
send_ha_message(hb_conn, forward_msg, NULL, FALSE);
}
if(call_options & cib_discard_reply) {
crm_debug_2("Client not interested in reply");
} else if(call_options & cib_sync_call) {
/* keep track of the request so we can time it
* out if required
*/
crm_debug_2("Registering delegated call from %s",
cib_client->id);
cib_client->delegated_calls = g_list_append(
cib_client->delegated_calls, forward_msg);
forward_msg = NULL;
}
crm_msg_del(forward_msg);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
static void
send_peer_reply(
HA_Message *msg, crm_data_t *result_diff, const char *originator, gboolean broadcast)
{
- cl_mem_stats_t saved_stats;
HA_Message *reply_copy = NULL;
CRM_ASSERT(msg != NULL);
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
reply_copy = cib_msg_copy(msg, TRUE);
if(broadcast) {
/* this (successful) call modified the CIB _and_ the
* change needs to be broadcast...
* send via HA to other nodes
*/
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
cib_diff_version_details(
result_diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
crm_debug("Sending update diff %d.%d.%d -> %d.%d.%d",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
ha_msg_add(reply_copy, F_CIB_ISREPLY, originator);
ha_msg_add(reply_copy, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
ha_msg_mod(reply_copy, F_CIB_OPERATION, CIB_OP_APPLY_DIFF);
add_message_xml(reply_copy, F_CIB_UPDATE_DIFF, result_diff);
crm_log_message(LOG_DEBUG_3, reply_copy);
send_ha_message(hb_conn, reply_copy, NULL, TRUE);
} else if(originator != NULL) {
/* send reply via HA to originating node */
crm_debug_2("Sending request result to originator only");
ha_msg_add(reply_copy, F_CIB_ISREPLY, originator);
send_ha_message(hb_conn, reply_copy, originator, FALSE);
}
crm_msg_del(reply_copy);
- crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
void
cib_process_request(
HA_Message *request, gboolean force_synchronous, gboolean privileged,
gboolean from_peer, cib_client_t *cib_client)
{
int call_type = 0;
int call_options = 0;
gboolean process = TRUE;
gboolean needs_reply = TRUE;
gboolean local_notify = FALSE;
gboolean needs_forward = FALSE;
crm_data_t *result_diff = NULL;
enum cib_errors rc = cib_ok;
HA_Message *op_reply = NULL;
const char *op = cl_get_string(request, F_CIB_OPERATION);
const char *originator = cl_get_string(request, F_ORIG);
const char *host = cl_get_string(request, F_CIB_HOST);
const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
-
crm_debug_4("%s Processing msg %s",
cib_our_uname, cl_get_string(request, F_SEQ));
cib_num_ops++;
if(cib_num_ops == 0) {
cib_num_fail = 0;
cib_num_local = 0;
cib_num_updates = 0;
crm_info("Stats wrapped around");
}
if(host != NULL && strlen(host) == 0) {
host = NULL;
}
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Retrieved call options: %d", call_options);
if(force_synchronous) {
call_options |= cib_sync_call;
}
crm_debug_2("Processing %s message (%s) to %s...",
from_peer?"peer":"local",
from_peer?originator:cib_our_uname, host?host:"master");
rc = cib_get_operation_id(request, &call_type);
if(cib_server_ops[call_type].modifies_cib) {
cib_num_updates++;
}
if(rc != cib_ok) {
/* TODO: construct error reply */
crm_err("Pre-processing of command failed: %s",
cib_error2string(rc));
} else if(from_peer == FALSE) {
parse_local_options(cib_client, call_type, call_options, host, op,
&local_notify, &needs_reply, &process, &needs_forward);
} else if(parse_peer_options(call_type, request, &local_notify,
&needs_reply, &process, &needs_forward) == FALSE) {
return;
}
crm_debug_3("Finished determining processing actions");
if(call_options & cib_discard_reply) {
needs_reply = cib_server_ops[call_type].modifies_cib;
local_notify = FALSE;
}
if(needs_forward && stand_alone == FALSE) {
forward_request(request, cib_client, call_options);
return;
}
if(process) {
cib_num_local++;
crm_debug_2("Performing local processing:"
" op=%s origin=%s/%s,%s (update=%s)",
cl_get_string(request, F_CIB_OPERATION), originator,
cl_get_string(request, F_CIB_CLIENTID),
cl_get_string(request, F_CIB_CALLID), update);
rc = cib_process_command(
request, &op_reply, &result_diff, privileged);
crm_debug_2("Processing complete");
if(rc == cib_diff_resync || rc == cib_diff_failed
|| rc == cib_old_data) {
crm_warn("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
} else if(rc != cib_ok) {
cib_num_fail++;
crm_err("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply);
crm_log_message_adv(LOG_INFO, "Input message", request);
}
if(op_reply == NULL && (needs_reply || local_notify)) {
crm_err("Unexpected NULL reply to message");
crm_log_message(LOG_ERR, request);
needs_reply = FALSE;
local_notify = FALSE;
}
}
crm_debug_3("processing response cases");
if(local_notify) {
const char *client_id = cl_get_string(request, F_CIB_CLIENTID);
if(process == FALSE) {
do_local_notify(request, client_id, call_options & cib_sync_call, from_peer);
} else {
do_local_notify(op_reply, client_id, call_options & cib_sync_call, from_peer);
}
}
/* from now on we are the server */
if(needs_reply == FALSE || stand_alone) {
/* nothing more to do...
* this was a non-originating slave update
*/
crm_debug_2("Completed slave update");
} else if(rc == cib_ok
&& result_diff != NULL
&& !(call_options & cib_inhibit_bcast)) {
CRM_DEV_ASSERT(cib_server_ops[call_type].modifies_cib == FALSE
|| result_diff != NULL || rc != cib_ok);
send_peer_reply(request, result_diff, originator, TRUE);
} else if((call_options & cib_discard_reply) == 0) {
CRM_DEV_ASSERT(cib_server_ops[call_type].modifies_cib == FALSE
|| result_diff != NULL || rc != cib_ok);
crm_debug("Directed reply to %s", originator);
if(call_options & cib_inhibit_bcast) {
crm_debug("Request not broadcast: inhibited");
}
if(cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug_2("Request not broadcast: R/O call");
}
if(rc != cib_ok) {
crm_warn("Request not broadcast: call failed: %s",
cib_error2string(rc));
}
if(from_peer) {
send_peer_reply(op_reply, result_diff, originator, FALSE);
}
}
crm_msg_del(op_reply);
free_xml(result_diff);
- if(crm_diff_mem_stats(LOG_ERR, LOG_WARNING, __PRETTY_FUNCTION__, NULL, &saved_stats)) {
-#ifdef HA_MALLOC_TRACK
- cl_malloc_dump_allocated(LOG_DEBUG, FALSE);
-#endif
- }
return;
}
static HA_Message *
cib_construct_reply(HA_Message *request, HA_Message *output, int rc)
{
int lpc = 0;
HA_Message *reply = NULL;
const char *name = NULL;
const char *value = NULL;
const char *names[] = {
F_CIB_OPERATION,
F_CIB_CALLID,
F_CIB_CLIENTID,
F_CIB_CALLOPTS
};
crm_debug_4("Creating a basic reply");
reply = ha_msg_new(8);
ha_msg_add(reply, F_TYPE, T_CIB);
for(lpc = 0; lpc < DIMOF(names); lpc++) {
name = names[lpc];
value = cl_get_string(request, name);
ha_msg_add(reply, name, value);
}
ha_msg_add_int(reply, F_CIB_RC, rc);
if(output != NULL) {
crm_debug_4("Attaching reply output");
add_message_xml(reply, F_CIB_CALLDATA, output);
}
return reply;
}
enum cib_errors
cib_process_command(HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged)
{
crm_data_t *output = NULL;
crm_data_t *input = NULL;
crm_data_t *current_cib = NULL;
crm_data_t *result_cib = NULL;
int call_type = 0;
int call_options = 0;
enum cib_errors rc = cib_ok;
enum cib_errors rc2 = cib_ok;
const char *op = NULL;
const char *section = NULL;
gboolean global_update = crm_is_true(
cl_get_string(request, F_CIB_GLOBAL_UPDATE));
*reply = NULL;
*cib_diff = NULL;
if(per_action_cib) {
CRM_CHECK(the_cib == NULL, free_xml(the_cib));
the_cib = readCibXmlFile(WORKING_DIR, "cib.xml", FALSE);
CRM_CHECK(the_cib != NULL, return cib_NOOBJECT);
}
current_cib = the_cib;
/* Start processing the request... */
op = cl_get_string(request, F_CIB_OPERATION);
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
rc = cib_get_operation_id(request, &call_type);
if(rc == cib_ok &&
cib_server_ops[call_type].needs_privileges
&& privileged == FALSE) {
/* abort */
rc = cib_not_authorized;
}
if(cib_status != cib_ok) {
*reply = cib_construct_reply(request, the_cib, cib_status);
if(per_action_cib) {
uninitializeCib();
}
return cib_status;
}
if(rc == cib_ok
&& global_update == FALSE
&& cib_server_ops[call_type].needs_quorum
&& can_write(call_options) == FALSE) {
rc = cib_no_quorum;
}
/* prevent NUMUPDATES from being incrimented - apply the change as-is */
if(global_update) {
call_options |= cib_inhibit_bcast;
call_options |= cib_force_diff;
}
rc2 = cib_server_ops[call_type].prepare(request, &input, &section);
if(rc == cib_ok) {
rc = rc2;
}
if(rc != cib_ok) {
crm_debug_2("Call setup failed");
} else if(cib_server_ops[call_type].modifies_cib) {
if((call_options & cib_inhibit_notify) == 0) {
cib_pre_notify(
call_options, op,
get_object_root(section, current_cib), input);
}
if(rc == cib_ok) {
result_cib = copy_xml(current_cib);
rc = cib_server_ops[call_type].fn(
op, call_options, section, input,
current_cib, &result_cib, &output);
}
if(rc == cib_ok) {
CRM_DEV_ASSERT(result_cib != NULL);
CRM_DEV_ASSERT(current_cib != result_cib);
update_counters(__FILE__, __FUNCTION__, result_cib);
if(global_update) {
/* skip */
CRM_CHECK(call_type == 4 || call_type == 11,
crm_err("Call type: %d", call_type);
crm_log_message(LOG_ERR, request));
crm_debug_2("Skipping update: global replace");
} else if(cib_server_ops[call_type].fn == cib_process_change
&& (call_options & cib_inhibit_bcast)) {
/* skip */
crm_debug_2("Skipping update: inhibit broadcast");
} else {
const char *op = cl_get_string(
request, F_CIB_OPERATION);
const char *originator = cl_get_string(
request, F_ORIG);
crm_debug_2("Upping counter: %s %s %d %d",
op, originator, call_options,
global_update);
cib_update_counter(result_cib, XML_ATTR_NUMUPDATES, FALSE);
}
if(do_id_check(result_cib, NULL, TRUE, FALSE)) {
rc = cib_id_check;
if(call_options & cib_force_diff) {
crm_err("Global update introduces id collision!");
}
} else {
*cib_diff = diff_cib_object(
current_cib, result_cib, FALSE);
}
}
if(rc != cib_ok) {
free_xml(result_cib);
} else if(activateCibXml(result_cib, CIB_FILENAME) != 0){
crm_warn("Activation failed");
rc = cib_ACTIVATION;
}
if((call_options & cib_inhibit_notify) == 0) {
const char *call_id = cl_get_string(
request, F_CIB_CALLID);
const char *client = cl_get_string(
request, F_CIB_CLIENTNAME);
cib_post_notify(call_options, op, input, rc, the_cib);
cib_diff_notify(call_options, client, call_id, op,
input, rc, *cib_diff);
}
if(rc == cib_ok) {
log_xml_diff(cib_diff_loglevel, *cib_diff, "cib:diff");
} else {
log_xml_diff(cib_diff_loglevel+1, *cib_diff, "cib:diff");
}
} else {
rc = cib_server_ops[call_type].fn(
op, call_options, section, input,
current_cib, &result_cib, &output);
CRM_CHECK(result_cib == NULL, free_xml(result_cib));
}
if((call_options & cib_discard_reply) == 0) {
*reply = cib_construct_reply(request, output, rc);
}
if(call_type >= 0) {
cib_server_ops[call_type].cleanup(op, &input, &output);
}
if(per_action_cib) {
uninitializeCib();
}
return rc;
}
int
send_via_callback_channel(HA_Message *msg, const char *token)
{
cib_client_t *hash_client = NULL;
GList *list_item = NULL;
enum cib_errors rc = cib_ok;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
crm_debug_3("Delivering msg %p to client %s", msg, token);
if(token == NULL) {
crm_err("No client id token, cant send message");
if(rc == cib_ok) {
rc = cib_missing;
}
} else {
/* A client that left before we could reply is not really
* _our_ error. Warn instead.
*/
hash_client = g_hash_table_lookup(client_list, token);
if(hash_client == NULL) {
crm_warn("Cannot find client for token %s", token);
rc = cib_client_gone;
} else if(hash_client->channel == NULL) {
crm_err("Cannot find channel for client %s", token);
rc = cib_client_corrupt;
} else if(hash_client->channel->ops->get_chan_status(
hash_client->channel) == IPC_DISCONNECT) {
crm_warn("Client %s has disconnected", token);
rc = cib_client_gone;
cib_num_timeouts++;
}
}
/* this is a more important error so overwriting rc is warrented */
if(msg == NULL) {
crm_err("No message to send");
rc = cib_reply_failed;
}
if(rc == cib_ok) {
list_item = g_list_find_custom(
hash_client->delegated_calls, msg, cib_GCompareFunc);
}
if(list_item != NULL) {
/* remove it - no need to time it out */
HA_Message *orig_msg = list_item->data;
crm_debug_3("Removing msg from delegated list");
hash_client->delegated_calls = g_list_remove(
hash_client->delegated_calls, orig_msg);
CRM_DEV_ASSERT(orig_msg != msg);
crm_msg_del(orig_msg);
}
if(rc == cib_ok) {
crm_debug_3("Delivering reply to client %s", token);
if(send_ipc_message(hash_client->channel, msg) == FALSE) {
crm_warn("Delivery of reply to client %s/%s failed",
hash_client->name, token);
rc = cib_reply_failed;
}
}
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
return rc;
}
gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const HA_Message *a_msg = a;
const HA_Message *b_msg = b;
int msg_a_id = 0;
int msg_b_id = 0;
ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id);
ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id);
if(msg_a_id == msg_b_id) {
return 0;
} else if(msg_a_id < msg_b_id) {
return -1;
}
return 1;
}
gboolean
cib_msg_timeout(gpointer data)
{
crm_debug_4("Checking if any clients have timed out messages");
/* g_hash_table_foreach(client_list, cib_GHFunc, NULL); */
return TRUE;
}
void
cib_GHFunc(gpointer key, gpointer value, gpointer user_data)
{
int timeout = 0; /* 1 iteration == 10 seconds */
HA_Message *msg = NULL;
HA_Message *reply = NULL;
const char *host_to = NULL;
cib_client_t *client = value;
GListPtr list = client->delegated_calls;
while(list != NULL) {
msg = list->data;
ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout);
if(timeout <= 0) {
list = list->next;
continue;
} else {
int seen = 0;
ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen);
crm_debug_4("Timeout %d, seen %d", timeout, seen);
if(seen < timeout) {
crm_debug_4("Updating seen count for msg from client %s",
client->id);
seen += 10;
ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen);
list = list->next;
continue;
}
}
cib_num_timeouts++;
host_to = cl_get_string(msg, F_CIB_HOST);
crm_warn("Sending operation timeout msg to client %s",
client->id);
reply = ha_msg_new(4);
ha_msg_add(reply, F_TYPE, T_CIB);
ha_msg_add(reply, F_CIB_OPERATION,
cl_get_string(msg, F_CIB_OPERATION));
ha_msg_add(reply, F_CIB_CALLID,
cl_get_string(msg, F_CIB_CALLID));
if(host_to == NULL) {
ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout);
} else {
ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout);
}
send_ipc_message(client->channel, reply);
list = list->next;
client->delegated_calls = g_list_remove(
client->delegated_calls, msg);
crm_msg_del(msg);
crm_msg_del(reply);
}
}
gboolean
cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client)
{
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
-
if (channel == NULL) {
CRM_DEV_ASSERT(cib_client == NULL);
} else if (cib_client == NULL) {
crm_err("No client");
} else {
CRM_DEV_ASSERT(channel->ch_status != IPC_CONNECT);
crm_debug_2("Cleaning up after client disconnect: %s/%s/%s",
crm_str(cib_client->name),
cib_client->channel_name,
cib_client->id);
if(cib_client->id != NULL) {
START_stat_free_op();
if(!g_hash_table_remove(client_list, cib_client->id)) {
crm_err("Client %s not found in the hashtable",
cib_client->name);
}
END_stat_free_op();
}
}
if(cib_shutdown_flag && g_hash_table_size(client_list) == 0) {
crm_info("All clients disconnected...");
initiate_exit();
}
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
return FALSE;
}
gboolean
cib_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
crm_debug_3("Invoked");
if(IPC_ISRCONN(channel)) {
if(hb_cluster->llc_ops->msgready(hb_cluster) == 0) {
crm_debug_2("no message ready yet");
}
/* invoke the callbacks but dont block */
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
- crm_diff_mem_stats(LOG_DEBUG, LOG_DEBUG, __PRETTY_FUNCTION__, NULL, &saved_stats);
return (channel->ch_status == IPC_CONNECT);
}
void
cib_peer_callback(HA_Message * msg, void* private_data)
{
int call_type = 0;
int call_options = 0;
const char *originator = cl_get_string(msg, F_ORIG);
const char *seq = cl_get_string(msg, F_SEQ);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
crm_log_message_adv(LOG_MSG, "Peer[inbound]", msg);
crm_debug_2("Peer %s message (%s) from %s", op, seq, originator);
if(originator == NULL || safe_str_eq(originator, cib_our_uname)) {
crm_debug("Discarding %s message %s from ourselves", op, seq);
return;
} else if(ccm_membership == NULL) {
crm_info("Discarding %s message (%s) from %s:"
" membership not established", op, seq, originator);
return;
} else if(g_hash_table_lookup(ccm_membership, originator) == NULL) {
crm_warn("Discarding %s message (%s) from %s:"
" not in our membership", op, seq, originator);
return;
} else if(cib_get_operation_id(msg, &call_type) != cib_ok) {
crm_debug("Discarding %s message (%s) from %s:"
" Invalid operation", op, seq, originator);
return;
}
crm_debug_2("Processing %s msg (%s) from %s",op, seq, originator);
ha_msg_value_int(msg, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Retrieved call options: %d", call_options);
if(cl_get_string(msg, F_CIB_CLIENTNAME) == NULL) {
ha_msg_add(msg, F_CIB_CLIENTNAME, originator);
}
cib_process_request(msg, FALSE, TRUE, TRUE, NULL);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
return;
}
HA_Message *
cib_msg_copy(HA_Message *msg, gboolean with_data)
{
int lpc = 0;
const char *field = NULL;
const char *value = NULL;
const HA_Message *value_struct = NULL;
static const char *field_list[] = {
F_TYPE ,
F_CIB_CLIENTID ,
F_CIB_CALLOPTS ,
F_CIB_CALLID ,
F_CIB_OPERATION ,
F_CIB_ISREPLY ,
F_CIB_SECTION ,
F_CIB_HOST ,
F_CIB_RC ,
F_CIB_DELEGATED ,
F_CIB_OBJID ,
F_CIB_OBJTYPE ,
F_CIB_EXISTING ,
F_CIB_SEENCOUNT ,
F_CIB_TIMEOUT ,
F_CIB_CALLBACK_TOKEN ,
F_CIB_GLOBAL_UPDATE ,
F_CIB_CLIENTNAME ,
F_CIB_NOTIFY_TYPE ,
F_CIB_NOTIFY_ACTIVATE
};
static const char *data_list[] = {
F_CIB_CALLDATA ,
F_CIB_UPDATE ,
F_CIB_UPDATE_RESULT
};
HA_Message *copy = NULL;
copy = ha_msg_new(10);
if(copy == NULL) {
return copy;
}
for(lpc = 0; lpc < DIMOF(field_list); lpc++) {
field = field_list[lpc];
value = cl_get_string(msg, field);
if(value != NULL) {
ha_msg_add(copy, field, value);
}
}
for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) {
field = data_list[lpc];
value_struct = cl_get_struct(msg, field);
if(value_struct != NULL) {
add_message_xml(copy, field, value_struct);
}
}
return copy;
}
enum cib_errors
cib_get_operation_id(const HA_Message * msg, int *operation)
{
int lpc = 0;
int max_msg_types = DIMOF(cib_server_ops);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
for (lpc = 0; lpc < max_msg_types; lpc++) {
if (safe_str_eq(op, cib_server_ops[lpc].operation)) {
*operation = lpc;
return cib_ok;
}
}
crm_err("Operation %s is not valid", op);
*operation = -1;
return cib_operation;
}
void
cib_client_status_callback(const char * node, const char * client,
const char * status, void * private)
{
if(safe_str_eq(client, CRM_SYSTEM_CIB)) {
crm_info("Status update: Client %s/%s now has status [%s]",
node, client, status);
g_hash_table_replace(peer_hash, crm_strdup(node), crm_strdup(status));
set_connected_peers(the_cib);
}
return;
}
extern oc_ev_t *cib_ev_token;
gboolean
ccm_manual_check(gpointer data)
{
int rc = 0;
oc_ev_t *ccm_token = cib_ev_token;
crm_debug("manual check");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
gboolean cib_ccm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
crm_debug_2("received callback");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
static void crm_ghash_clfree(gpointer data)
{
crm_free(data);
}
void
cib_ccm_msg_callback(
oc_ed_t event, void *cookie, size_t size, const void *data)
{
int instance = -1;
gboolean update_id = FALSE;
gboolean update_quorum = FALSE;
const oc_ev_membership_t *membership = data;
if(membership != NULL) {
instance = membership->m_instance;
}
crm_debug("Process CCM event=%s (id=%d)",
ccm_event_name(event), instance);
switch(event) {
case OC_EV_MS_NEW_MEMBERSHIP:
case OC_EV_MS_INVALID:
update_id = TRUE;
update_quorum = TRUE;
break;
case OC_EV_MS_PRIMARY_RESTORED:
update_id = TRUE;
break;
case OC_EV_MS_NOT_PRIMARY:
crm_debug_2("Ignoring transitional CCM event: %s",
ccm_event_name(event));
break;
case OC_EV_MS_EVICTED:
crm_err("Evicted from CCM: %s", ccm_event_name(event));
update_quorum = TRUE;
break;
default:
crm_err("Unknown CCM event: %d", event);
}
if(update_id) {
CRM_DEV_ASSERT(membership != NULL);
if(crm_assert_failed) { return; }
if(ccm_transition_id != NULL) {
crm_free(ccm_transition_id);
ccm_transition_id = NULL;
}
ccm_transition_id = crm_itoa(instance);
set_transition(the_cib);
}
if(update_quorum) {
unsigned int members = 0;
int offset = 0;
unsigned int lpc = 0;
cib_have_quorum = ccm_have_quorum(event);
if(cib_have_quorum) {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE);
} else {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE);
}
crm_debug("Quorum %s after event=%s (id=%d)",
cib_have_quorum?"(re)attained":"lost",
ccm_event_name(event), instance);
if(ccm_membership == NULL) {
ccm_membership = g_hash_table_new_full(
g_str_hash, g_str_equal,
crm_ghash_clfree, NULL);
}
if(membership != NULL && membership->m_n_out != 0) {
members = membership->m_n_out;
offset = membership->m_out_idx;
for(lpc = 0; lpc < members; lpc++) {
oc_node_t a_node = membership->m_array[lpc+offset];
crm_info("LOST: %s", a_node.node_uname);
g_hash_table_remove(
ccm_membership, a_node.node_uname);
}
}
if(membership != NULL && membership->m_n_member != 0) {
members = membership->m_n_member;
offset = membership->m_memb_idx;
for(lpc = 0; lpc < members; lpc++) {
oc_node_t a_node = membership->m_array[lpc+offset];
char *uname = crm_strdup(a_node.node_uname);
crm_info("PEER: %s", uname);
g_hash_table_replace(
ccm_membership, uname, uname);
}
}
}
oc_ev_callback_done(cookie);
set_connected_peers(the_cib);
return;
}
gboolean
can_write(int flags)
{
if(cib_have_quorum) {
return TRUE;
} else if((flags & cib_quorum_override) != 0) {
return TRUE;
}
return FALSE;
}
static gboolean
cib_force_exit(gpointer data)
{
crm_notice("Forcing exit!");
terminate_ha_connection(__FUNCTION__);
return FALSE;
}
void
initiate_exit(void)
{
int active = 0;
HA_Message *leaving = NULL;
g_hash_table_foreach(peer_hash, GHFunc_count_peers, &active);
if(active < 2) {
terminate_ha_connection(__FUNCTION__);
return;
}
crm_info("Sending disconnect notification to %d peers...", active);
leaving = ha_msg_new(3);
ha_msg_add(leaving, F_TYPE, "cib");
ha_msg_add(leaving, F_CIB_OPERATION, "cib_shutdown_req");
send_ha_message(hb_conn, leaving, NULL, TRUE);
crm_msg_del(leaving);
Gmain_timeout_add(crm_get_msec("5s"), cib_force_exit, NULL);
}
void
terminate_ha_connection(const char *caller)
{
if(hb_conn != NULL) {
crm_info("%s: Disconnecting heartbeat", caller);
hb_conn->llc_ops->signoff(hb_conn, FALSE);
} else {
crm_err("%s: No heartbeat connection", caller);
exit(LSB_EXIT_OK);
}
}
diff --git a/crm/cib/main.c b/crm/cib/main.c
index 18c5c4db1e..11645909bc 100644
--- a/crm/cib/main.c
+++ b/crm/cib/main.c
@@ -1,530 +1,517 @@
/* $Id: main.c,v 1.56 2006/07/18 06:14:18 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <heartbeat.h>
#include <clplumbing/cl_misc.h>
#include <clplumbing/uids.h>
#include <clplumbing/coredumps.h>
#include <clplumbing/Gmain_timeout.h>
/* #include <portability.h> */
#include <ocf/oc_event.h>
/* #include <ocf/oc_membership.h> */
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <crm/dmalloc_wrapper.h>
gboolean cib_shutdown_flag = FALSE;
gboolean stand_alone = FALSE;
gboolean per_action_cib = FALSE;
enum cib_errors cib_status = cib_ok;
extern char *ccm_transition_id;
extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
GMainLoop* mainloop = NULL;
const char* crm_system_name = CRM_SYSTEM_CIB;
char *cib_our_uname = NULL;
oc_ev_t *cib_ev_token;
gboolean cib_writes_enabled = TRUE;
void usage(const char* cmd, int exit_status);
int init_start(void);
gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name);
gboolean cib_shutdown(int nsig, gpointer unused);
void cib_ha_connection_destroy(gpointer user_data);
gboolean startCib(const char *filename);
extern gboolean cib_msg_timeout(gpointer data);
extern int write_cib_contents(gpointer p);
ll_cluster_t *hb_conn = NULL;
GTRIGSource *cib_writer = NULL;
#define OPTARGS "hVsf"
static void
cib_diskwrite_complete(gpointer userdata, int status, int signo, int exitcode)
{
if(exitcode != LSB_EXIT_OK || signo != 0 || status != 0) {
crm_err("Disk write failed: status=%d, signo=%d, exitcode=%d",
status, signo, exitcode);
if(cib_writes_enabled) {
crm_err("Disabling disk writes after write failure");
cib_writes_enabled = FALSE;
}
} else {
crm_debug_2("Disk write passed");
}
}
int
main(int argc, char ** argv)
{
int flag;
int argerr = 0;
crm_log_init(crm_system_name);
G_main_add_SignalHandler(
G_PRIORITY_HIGH, SIGTERM, cib_shutdown, NULL, NULL);
cib_writer = G_main_add_tempproc_trigger(
G_PRIORITY_LOW, write_cib_contents, "write_cib_contents",
NULL, NULL, NULL, cib_diskwrite_complete);
EnableProcLogging();
set_sigchld_proctrack(G_PRIORITY_HIGH);
client_list = g_hash_table_new(g_str_hash, g_str_equal);
peer_hash = g_hash_table_new(g_str_hash, g_str_equal);
while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
switch(flag) {
case 'V':
alter_debug(DEBUG_INC);
break;
case 's':
stand_alone = TRUE;
cl_log_enable_stderr(1);
break;
case 'h': /* Help message */
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'f':
per_action_cib = TRUE;
break;
default:
++argerr;
break;
}
}
crm_info("Retrieval of a per-action CIB: %s",
per_action_cib?"enabled":"disabled");
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name,LSB_EXIT_GENERIC);
}
/* read local config file */
return init_start();
}
unsigned long cib_num_ops = 0;
const char *cib_stat_interval = "10min";
unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0;
unsigned long cib_bad_connects = 0, cib_num_timeouts = 0;
longclock_t cib_call_time = 0;
gboolean cib_stats(gpointer data);
gboolean
cib_stats(gpointer data)
{
int local_log_level = LOG_DEBUG;
static unsigned long last_stat = 0;
unsigned int cib_calls_ms = 0;
static unsigned long cib_stat_interval_ms = 0;
- cl_mem_stats_t saved_stats;
- if(crm_running_stats == NULL) {
- START_stat_free_op();
- crm_malloc0(crm_running_stats, sizeof(cl_mem_stats_t));
- END_stat_free_op();
- crm_zero_mem_stats(crm_running_stats);
- }
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, crm_running_stats);
- *crm_running_stats = saved_stats;
- crm_debug_2("Total alloc's %ld for %ld bytes",
- crm_running_stats->numalloc, crm_running_stats->nbytes_alloc);
-
if(cib_stat_interval_ms == 0) {
cib_stat_interval_ms = crm_get_msec(cib_stat_interval);
}
cib_calls_ms = longclockto_ms(cib_call_time);
if((cib_num_ops - last_stat) > 0) {
unsigned long calls_diff = cib_num_ops - last_stat;
double stat_1 = (1000*cib_calls_ms)/calls_diff;
local_log_level = LOG_INFO;
do_crm_log(local_log_level,
"Processed %lu operations"
" (%.2fus average, %lu%% utilization) in the last %s",
calls_diff, stat_1,
(100*cib_calls_ms)/cib_stat_interval_ms,
cib_stat_interval);
}
do_crm_log(local_log_level+1,
"\tDetail: %lu operations (%ums total)"
" (%lu local, %lu updates, %lu failures,"
" %lu timeouts, %lu bad connects)",
cib_num_ops, cib_calls_ms, cib_num_local, cib_num_updates,
cib_num_fail, cib_bad_connects, cib_num_timeouts);
#ifdef HA_MALLOC_TRACK
- cl_malloc_dump_allocated(LOG_ERR, TRUE);
+ cl_malloc_dump_allocated(LOG_DEBUG, TRUE);
#endif
last_stat = cib_num_ops;
cib_call_time = 0;
return TRUE;
}
int
init_start(void)
{
gboolean was_error = FALSE;
if(stand_alone == FALSE) {
hb_conn = ll_cluster_new("heartbeat");
if(cib_register_ha(hb_conn, CRM_SYSTEM_CIB) == FALSE) {
crm_crit("Cannot sign in to heartbeat... terminating");
exit(1);
}
}
if(startCib("cib.xml") == FALSE){
crm_crit("Cannot start CIB... terminating");
exit(1);
}
was_error = init_server_ipc_comms(
crm_strdup(cib_channel_callback), cib_client_connect_null,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup(cib_channel_ro), cib_client_connect_rw_ro,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup(cib_channel_rw), cib_client_connect_rw_ro,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup(cib_channel_rw_synchronous), cib_client_connect_rw_synch,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup(cib_channel_ro_synchronous), cib_client_connect_ro_synch,
default_ipc_connection_destroy);
if(stand_alone) {
if(was_error) {
crm_err("Couldnt start");
return 1;
}
cib_is_master = TRUE;
/* Create the mainloop and run it... */
mainloop = g_main_new(FALSE);
crm_info("Starting %s mainloop", crm_system_name);
/* Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL); */
/* Gmain_timeout_add( */
/* crm_get_msec(cib_stat_interval), cib_stats, NULL); */
g_main_run(mainloop);
return_to_orig_privs();
return 0;
}
if(was_error == FALSE) {
crm_debug_3("Be informed of CRM Client Status changes");
if (HA_OK != hb_conn->llc_ops->set_cstatus_callback(
hb_conn, cib_client_status_callback, hb_conn)) {
crm_err("Cannot set cstatus callback: %s",
hb_conn->llc_ops->errmsg(hb_conn));
was_error = TRUE;
} else {
crm_debug_3("Client Status callback set");
}
}
if(was_error == FALSE) {
gboolean did_fail = TRUE;
int num_ccm_fails = 0;
int max_ccm_fails = 30;
int ret;
int cib_ev_fd;
while(did_fail && was_error == FALSE) {
did_fail = FALSE;
crm_debug_3("Registering with CCM");
ret = oc_ev_register(&cib_ev_token);
if (ret != 0) {
crm_warn("CCM registration failed");
did_fail = TRUE;
}
if(did_fail == FALSE) {
crm_debug_3("Setting up CCM callbacks");
ret = oc_ev_set_callback(
cib_ev_token, OC_EV_MEMB_CLASS,
cib_ccm_msg_callback, NULL);
if (ret != 0) {
crm_warn("CCM callback not set");
did_fail = TRUE;
}
}
if(did_fail == FALSE) {
oc_ev_special(cib_ev_token, OC_EV_MEMB_CLASS, 0);
crm_debug_3("Activating CCM token");
ret = oc_ev_activate(cib_ev_token, &cib_ev_fd);
if (ret != 0){
crm_warn("CCM Activation failed");
did_fail = TRUE;
}
}
if(did_fail) {
num_ccm_fails++;
oc_ev_unregister(cib_ev_token);
if(num_ccm_fails < max_ccm_fails){
crm_warn("CCM Connection failed"
" %d times (%d max)",
num_ccm_fails, max_ccm_fails);
sleep(1);
} else {
crm_err("CCM Activation failed"
" %d (max) times",
num_ccm_fails);
was_error = TRUE;
}
}
}
if(was_error == FALSE) {
crm_debug_3("CCM Activation passed... all set to go!");
G_main_add_fd(G_PRIORITY_HIGH, cib_ev_fd, FALSE,
cib_ccm_dispatch, cib_ev_token,
default_ipc_connection_destroy);
}
}
if(was_error == FALSE) {
/* Async get client status information in the cluster */
crm_debug_3("Requesting an initial dump of CIB client_status");
hb_conn->llc_ops->client_status(
hb_conn, NULL, CRM_SYSTEM_CIB, -1);
/* Create the mainloop and run it... */
mainloop = g_main_new(FALSE);
crm_info("Starting %s mainloop", crm_system_name);
Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL);
Gmain_timeout_add(
crm_get_msec(cib_stat_interval), cib_stats, NULL);
g_main_run(mainloop);
return_to_orig_privs();
} else {
crm_err("Couldnt start all communication channels, exiting.");
}
return 0;
}
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);
exit(exit_status);
}
gboolean
cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name)
{
const char *uname = NULL;
crm_info("Signing in with Heartbeat");
if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) {
crm_err("Cannot sign on with heartbeat: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
crm_debug_3("Be informed of CIB messages");
if (HA_OK != hb_cluster->llc_ops->set_msg_callback(
hb_cluster, T_CIB, cib_peer_callback, hb_cluster)){
crm_err("Cannot set msg callback: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
crm_debug_3("Finding our node name");
if ((uname = hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) {
crm_err("get_mynodeid() failed");
return FALSE;
}
cib_our_uname = crm_strdup(uname);
crm_info("FSA Hostname: %s", cib_our_uname);
crm_debug_3("Adding channel to mainloop");
G_main_add_IPC_Channel(
G_PRIORITY_DEFAULT, hb_cluster->llc_ops->ipcchan(hb_cluster),
FALSE, cib_ha_dispatch, hb_cluster /* userdata */,
cib_ha_connection_destroy);
return TRUE;
}
void
cib_ha_connection_destroy(gpointer user_data)
{
if(cib_shutdown_flag) {
crm_info("Heartbeat disconnection complete... exiting");
} else {
crm_err("Heartbeat connection lost! Exiting.");
}
uninitializeCib();
crm_free(ccm_transition_id);
#ifdef HA_MALLOC_TRACK
cl_malloc_dump_allocated(LOG_ERR, FALSE);
#endif
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(LSB_EXIT_OK);
}
}
static void
disconnect_cib_client(gpointer key, gpointer value, gpointer user_data)
{
cib_client_t *a_client = value;
crm_debug_2("Processing client %s/%s... send=%d, recv=%d",
a_client->name, a_client->channel_name,
(int)a_client->channel->send_queue->current_qlen,
(int)a_client->channel->recv_queue->current_qlen);
if(a_client->channel->ch_status == IPC_CONNECT) {
a_client->channel->ops->resume_io(a_client->channel);
if(a_client->channel->send_queue->current_qlen != 0
|| a_client->channel->recv_queue->current_qlen != 0) {
crm_info("Flushed messages to/from %s/%s... send=%d, recv=%d",
a_client->name, a_client->channel_name,
(int)a_client->channel->send_queue->current_qlen,
(int)a_client->channel->recv_queue->current_qlen);
}
}
if(a_client->channel->ch_status == IPC_CONNECT) {
crm_warn("Disconnecting %s/%s...",
a_client->name, a_client->channel_name);
a_client->channel->ops->disconnect(a_client->channel);
}
}
extern gboolean cib_process_disconnect(
IPC_Channel *channel, cib_client_t *cib_client);
gboolean
cib_shutdown(int nsig, gpointer unused)
{
if(cib_shutdown_flag == FALSE) {
cib_shutdown_flag = TRUE;
crm_debug("Disconnecting %d clients",
g_hash_table_size(client_list));
g_hash_table_foreach(client_list, disconnect_cib_client, NULL);
crm_info("Disconnected %d clients",
g_hash_table_size(client_list));
cib_process_disconnect(NULL, NULL);
} else {
crm_info("Waiting for %d clients to disconnect...",
g_hash_table_size(client_list));
}
return TRUE;
}
gboolean
startCib(const char *filename)
{
gboolean active = FALSE;
crm_data_t *cib = readCibXmlFile(WORKING_DIR, filename, TRUE);
CRM_ASSERT(cib != NULL);
if(activateCibXml(cib, filename) == 0) {
active = TRUE;
crm_info("CIB Initialization completed successfully");
if(per_action_cib) {
uninitializeCib();
}
}
return active;
}
diff --git a/crm/cib/notify.c b/crm/cib/notify.c
index 0f10adb7ef..4787bacc01 100644
--- a/crm/cib/notify.c
+++ b/crm/cib/notify.c
@@ -1,430 +1,415 @@
/* $Id: notify.c,v 1.39 2006/07/07 20:59:30 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/cl_log.h>
#include <time.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <cibio.h>
#include <callbacks.h>
#include <notify.h>
#include <crm/dmalloc_wrapper.h>
extern GHashTable *client_list;
int pending_updates = 0;
void cib_notify_client(gpointer key, gpointer value, gpointer user_data);
void attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib);
void do_cib_notify(
int options, const char *op, crm_data_t *update,
enum cib_errors result, crm_data_t *result_data, const char *msg_type);
void
cib_notify_client(gpointer key, gpointer value, gpointer user_data)
{
IPC_Channel *ipc_client = NULL;
HA_Message *update_msg = user_data;
cib_client_t *client = value;
const char *type = NULL;
gboolean is_pre = FALSE;
gboolean is_post = FALSE;
gboolean is_confirm = FALSE;
gboolean is_replace = FALSE;
gboolean is_diff = FALSE;
gboolean do_send = FALSE;
int qlen = 0;
int max_qlen = 0;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
CRM_DEV_ASSERT(client != NULL);
CRM_DEV_ASSERT(update_msg != NULL);
type = cl_get_string(update_msg, F_SUBTYPE);
CRM_DEV_ASSERT(type != NULL);
if(client == NULL) {
crm_warn("Skipping NULL client");
return;
} else if(client->channel == NULL) {
crm_warn("Skipping client with NULL channel");
return;
} else if(client->name == NULL) {
crm_debug_2("Skipping unnammed client / comamnd channel");
return;
}
if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
is_pre = TRUE;
} else if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
is_post = TRUE;
} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
is_confirm = TRUE;
} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
is_diff = TRUE;
} else if(safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
is_replace = TRUE;
}
ipc_client = client->channel;
qlen = ipc_client->send_queue->current_qlen;
max_qlen = ipc_client->send_queue->max_qlen;
#if 1
/* get_chan_status() causes memory to be allocated that isnt free'd
* until the message is read (which messes up the memory stats)
*/
if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
crm_debug_2("Skipping notification to disconnected"
" client %s/%s", client->name, client->id);
} else if(client->pre_notify && is_pre) {
if(qlen < (int)(0.4 * max_qlen)) {
do_send = TRUE;
} else {
crm_warn("Throttling pre-notifications due to"
" high load: queue=%d (max=%d)",
qlen, max_qlen);
}
} else if(client->post_notify && is_post) {
if(qlen < (int)(0.7 * max_qlen)) {
do_send = TRUE;
} else {
crm_warn("Throttling post-notifications due to"
" extreme load: queue=%d (max=%d)",
qlen, max_qlen);
}
/* these are critical */
} else
#endif
if(client->diffs && is_diff) {
do_send = TRUE;
} else if(client->confirmations && is_confirm) {
do_send = TRUE;
} else if(client->replace && is_replace) {
do_send = TRUE;
}
if(do_send) {
crm_debug_2("Notifying client %s/%s of %s update (queue=%d)",
client->name, client->channel_name, type, qlen);
if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) {
/* We never want the CIB to exit because our client is slow */
crm_crit("%s-notification of client %s/%s failed - queue saturated",
is_confirm?"Confirmation":is_post?"Post":"Pre",
client->name, client->id);
} else if(send_ipc_message(ipc_client, update_msg) == FALSE) {
crm_warn("Notification of client %s/%s failed",
client->name, client->id);
}
} else {
crm_debug_3("Client %s/%s not interested in %s notifications",
client->name, client->channel_name, type);
}
- crm_diff_mem_stats(LOG_DEBUG, LOG_DEBUG, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
void
cib_pre_notify(
int options, const char *op, crm_data_t *existing, crm_data_t *update)
{
HA_Message *update_msg = NULL;
const char *type = NULL;
const char *id = NULL;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
update_msg = ha_msg_new(6);
if(update != NULL) {
id = crm_element_value(update, XML_ATTR_ID);
}
ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY);
ha_msg_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY);
ha_msg_add(update_msg, F_CIB_OPERATION, op);
if(id != NULL) {
ha_msg_add(update_msg, F_CIB_OBJID, id);
}
if(update != NULL) {
ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
} else if(existing != NULL) {
ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing));
}
type = cl_get_string(update_msg, F_CIB_OBJTYPE);
attach_cib_generation(update_msg, "cib_generation", the_cib);
if(existing != NULL) {
add_message_xml(update_msg, F_CIB_EXISTING, existing);
}
if(update != NULL) {
add_message_xml(update_msg, F_CIB_UPDATE, update);
}
g_hash_table_foreach(client_list, cib_notify_client, update_msg);
if(update == NULL) {
crm_debug_2("Performing operation %s (on section=%s)",
op, type);
} else {
crm_debug_2("Performing %s on <%s%s%s>",
op, type, id?" id=":"", id?id:"");
}
crm_msg_del(update_msg);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
void
cib_post_notify(int options, const char *op, crm_data_t *update,
enum cib_errors result, crm_data_t *new_obj)
{
do_cib_notify(
options, op, update, result, new_obj, T_CIB_UPDATE_CONFIRM);
}
void
cib_diff_notify(
int options, const char *client, const char *call_id, const char *op,
crm_data_t *update, enum cib_errors result, crm_data_t *diff)
{
int add_updates = 0;
int add_epoch = 0;
int add_admin_epoch = 0;
int del_updates = 0;
int del_epoch = 0;
int del_admin_epoch = 0;
int log_level = LOG_INFO;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if(diff == NULL) {
return;
}
if(result != cib_ok) {
log_level = LOG_WARNING;
}
cib_diff_version_details(
diff, &add_admin_epoch, &add_epoch, &add_updates,
&del_admin_epoch, &del_epoch, &del_updates);
if(add_updates != del_updates) {
do_crm_log(log_level,
"Update (client: %s%s%s): %d.%d.%d -> %d.%d.%d (%s)",
client, call_id?", call:":"", call_id?call_id:"",
del_admin_epoch, del_epoch, del_updates,
add_admin_epoch, add_epoch, add_updates,
cib_error2string(result));
} else if(diff != NULL) {
do_crm_log(log_level,
"Local-only Change (client:%s%s%s): %d.%d.%d (%s)",
client, call_id?", call: ":"", call_id?call_id:"",
add_admin_epoch, add_epoch, add_updates,
cib_error2string(result));
}
do_cib_notify(options, op, update, result, diff, T_CIB_DIFF_NOTIFY);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
void
do_cib_notify(
int options, const char *op, crm_data_t *update,
enum cib_errors result, crm_data_t *result_data, const char *msg_type)
{
HA_Message *update_msg = NULL;
const char *type = NULL;
const char *id = NULL;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
update_msg = ha_msg_new(8);
if(result_data != NULL) {
id = crm_element_value(result_data, XML_ATTR_ID);
}
ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY);
ha_msg_add(update_msg, F_SUBTYPE, msg_type);
ha_msg_add(update_msg, F_CIB_OPERATION, op);
ha_msg_add_int(update_msg, F_CIB_RC, result);
if(id != NULL) {
ha_msg_add(update_msg, F_CIB_OBJID, id);
}
if(update != NULL) {
crm_debug_4("Setting type to update->name: %s",
crm_element_name(update));
ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
type = crm_element_name(update);
} else if(result_data != NULL) {
crm_debug_4("Setting type to new_obj->name: %s",
crm_element_name(result_data));
ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data));
type = crm_element_name(result_data);
} else {
crm_debug_4("Not Setting type");
}
attach_cib_generation(update_msg, "cib_generation", the_cib);
if(update != NULL) {
add_message_xml(update_msg, F_CIB_UPDATE, update);
}
if(result_data != NULL) {
add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data);
}
crm_debug_3("Notifying clients");
g_hash_table_foreach(client_list, cib_notify_client, update_msg);
crm_msg_del(update_msg);
if(update == NULL) {
if(result == cib_ok) {
crm_debug_2("Operation %s (on section=%s) completed",
op, crm_str(type));
} else {
crm_warn("Operation %s (on section=%s) FAILED: (%d) %s",
op, crm_str(type), result,
cib_error2string(result));
}
} else {
if(result == cib_ok) {
crm_debug_2("Completed %s of <%s %s%s>",
op, crm_str(type), id?"id=":"", id?id:"");
} else {
crm_warn("%s of <%s %s%s> FAILED: %s", op,crm_str(type),
id?"id=":"", id?id:"", cib_error2string(result));
}
}
crm_debug_3("Notify complete");
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
void
attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib)
{
crm_data_t *generation = create_xml_node(
NULL, XML_CIB_TAG_GENERATION_TUPPLE);
if(a_cib != NULL) {
copy_in_properties(generation, a_cib);
}
add_message_xml(msg, field, generation);
free_xml(generation);
}
void
cib_replace_notify(crm_data_t *update, enum cib_errors result, crm_data_t *diff)
{
const char *origin = NULL;
HA_Message *replace_msg = NULL;
int add_updates = 0;
int add_epoch = 0;
int add_admin_epoch = 0;
int del_updates = 0;
int del_epoch = 0;
int del_admin_epoch = 0;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if(diff == NULL) {
return;
}
cib_diff_version_details(
diff, &add_admin_epoch, &add_epoch, &add_updates,
&del_admin_epoch, &del_epoch, &del_updates);
origin = crm_element_value(update, F_CRM_ORIGIN);
if(add_updates != del_updates) {
crm_info("Replaced: %d.%d.%d -> %d.%d.%d from %s",
del_admin_epoch, del_epoch, del_updates,
add_admin_epoch, add_epoch, add_updates, origin);
} else if(diff != NULL) {
crm_info("Local-only Replace: %d.%d.%d from %s",
add_admin_epoch, add_epoch, add_updates, origin);
}
replace_msg = ha_msg_new(8);
ha_msg_add(replace_msg, F_TYPE, T_CIB_NOTIFY);
ha_msg_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY);
ha_msg_add(replace_msg, F_CIB_OPERATION, CIB_OP_REPLACE);
ha_msg_add_int(replace_msg, F_CIB_RC, result);
attach_cib_generation(replace_msg, "cib-replace-generation", update);
crm_log_message_adv(LOG_DEBUG_2,"CIB Replaced", replace_msg);
g_hash_table_foreach(client_list, cib_notify_client, replace_msg);
crm_msg_del(replace_msg);
- crm_diff_mem_stats(LOG_ERR, LOG_ERR, __PRETTY_FUNCTION__, NULL, &saved_stats);
}
diff --git a/crm/pengine/pengine.c b/crm/pengine/pengine.c
index 5a2b88e6e0..76c350031e 100755
--- a/crm/pengine/pengine.c
+++ b/crm/pengine/pengine.c
@@ -1,323 +1,317 @@
/* $Id: pengine.c,v 1.122 2006/08/14 16:31:38 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <glib.h>
#include <crm/pengine/status.h>
#include <pengine.h>
#include <allocate.h>
#include <lib/crm/pengine/utils.h>
#include <utils.h>
crm_data_t * do_calculations(
pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now);
#define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine"
extern int transition_id;
#define get_series() was_processing_error?1:was_processing_warning?2:3
typedef struct series_s
{
int id;
const char *name;
const char *param;
int wrap;
} series_t;
series_t series[] = {
{ 0, "pe-unknown", "_dont_match_anything_", -1 },
{ 0, "pe-error", "pe-error-series-max", -1 },
{ 0, "pe-warn", "pe-warn-series-max", 200 },
{ 0, "pe-input", "pe-input-series-max", 400 },
};
gboolean
process_pe_message(HA_Message *msg, crm_data_t * xml_data, IPC_Channel *sender)
{
gboolean send_via_disk = FALSE;
const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO);
const char *op = cl_get_string(msg, F_CRM_TASK);
const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE);
crm_debug_3("Processing %s op (ref=%s)...", op, ref);
if(op == NULL){
/* error */
} else if(strcasecmp(op, CRM_OP_HELLO) == 0) {
/* ignore */
} else if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE),
XML_ATTR_RESPONSE)) {
/* ignore */
} else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
crm_debug_3("Bad sys-to %s", crm_str(sys_to));
return FALSE;
} else if(strcasecmp(op, CRM_OP_PECALC) == 0) {
int seq = -1;
int series_id = 0;
int series_wrap = 0;
char *filename = NULL;
char *graph_file = NULL;
const char *value = NULL;
pe_working_set_t data_set;
crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB);
crm_data_t *log_input = copy_xml(xml_data);
HA_Message *reply = NULL;
#if HAVE_BZLIB_H
gboolean compress = TRUE;
#else
gboolean compress = FALSE;
#endif
copy_in_properties(generation, xml_data);
crm_log_xml_info(generation, "[generation]");
crm_config_error = FALSE;
crm_config_warning = FALSE;
was_processing_error = FALSE;
was_processing_warning = FALSE;
graph_file = crm_strdup(WORKING_DIR"/graph.XXXXXX");
mktemp(graph_file);
- crm_zero_mem_stats(NULL);
-
do_calculations(&data_set, xml_data, NULL);
series_id = get_series();
series_wrap = series[series_id].wrap;
value = pe_pref(data_set.config_hash, series[series_id].param);
if(value != NULL) {
series_wrap = crm_int_helper(value, NULL);
if(errno != 0) {
series_wrap = series[series_id].wrap;
}
} else {
crm_config_warn("No value specified for cluster"
" preference: %s",
series[series_id].param);
}
seq = get_last_sequence(PE_WORKING_DIR, series[series_id].name);
data_set.input = NULL;
reply = create_reply(msg, data_set.graph);
CRM_ASSERT(reply != NULL);
filename = generate_series_filename(
PE_WORKING_DIR, series[series_id].name, seq, compress);
ha_msg_add(reply, F_CRM_TGRAPH_INPUT, filename);
crm_free(filename); filename = NULL;
if(send_ipc_message(sender, reply) == FALSE) {
send_via_disk = TRUE;
crm_err("Answer could not be sent via IPC, send via the disk instead");
crm_info("Writing the TE graph to %s", graph_file);
if(write_xml_file(data_set.graph, graph_file, FALSE) < 0) {
crm_err("TE graph could not be written to disk");
}
}
crm_msg_del(reply);
cleanup_alloc_calculations(&data_set);
- if(crm_mem_stats(NULL)) {
- pe_warn("Unfree'd memory");
- }
-
filename = generate_series_filename(
PE_WORKING_DIR, series[series_id].name, seq, compress);
write_xml_file(log_input, filename, compress);
write_last_sequence(PE_WORKING_DIR, series[series_id].name,
seq+1, series_wrap);
if(was_processing_error) {
crm_err("Transition %d:"
" ERRORs found during PE processing."
" PEngine Input stored in: %s",
transition_id, filename);
} else if(was_processing_warning) {
crm_warn("Transition %d:"
" WARNINGs found during PE processing."
" PEngine Input stored in: %s",
transition_id, filename);
} else {
crm_info("Transition %d: PEngine Input stored in: %s",
transition_id, filename);
}
if(crm_config_error) {
crm_info("Configuration ERRORs found during PE processing."
" Please run \"crm_verify -L\" to identify issues.");
} else if(crm_config_warning) {
crm_info("Configuration WARNINGs found during PE processing."
" Please run \"crm_verify -L\" to identify issues.");
}
if(send_via_disk) {
reply = create_reply(msg, NULL);
ha_msg_add(reply, F_CRM_TGRAPH, graph_file);
ha_msg_add(reply, F_CRM_TGRAPH_INPUT, filename);
CRM_ASSERT(reply != NULL);
if(send_ipc_message(sender, reply) == FALSE) {
crm_err("Answer could not be sent");
}
}
free_xml(generation);
crm_free(graph_file);
free_xml(log_input);
crm_free(filename);
crm_msg_del(reply);
} else if(strcasecmp(op, CRM_OP_QUIT) == 0) {
crm_warn("Received quit message, terminating");
exit(0);
}
return TRUE;
}
#define MEMCHECK_STAGE_0 0
#define check_and_exit(stage) cleanup_calculations(data_set); \
crm_mem_stats(NULL); \
crm_err("Exiting: stage %d", stage); \
exit(1);
crm_data_t *
do_calculations(pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now)
{
int rsc_log_level = LOG_INFO;
/* pe_debug_on(); */
set_working_set_defaults(data_set);
data_set->input = xml_input;
data_set->now = now;
if(data_set->now == NULL) {
data_set->now = new_ha_date(TRUE);
}
#if MEMCHECK_STAGE_SETUP
check_and_exit(-1);
#endif
crm_debug_5("unpack constraints");
stage0(data_set);
#if MEMCHECK_STAGE_0
check_and_exit(0);
#endif
slist_iter(rsc, resource_t, data_set->resources, lpc,
rsc->fns->print(rsc, NULL, pe_print_log, &rsc_log_level);
);
crm_debug_5("apply placement constraints");
stage1(data_set);
#if MEMCHECK_STAGE_1
check_and_exit(1);
#endif
crm_debug_5("color resources");
stage2(data_set);
#if MEMCHECK_STAGE_2
check_and_exit(2);
#endif
/* unused */
stage3(data_set);
#if MEMCHECK_STAGE_3
check_and_exit(3);
#endif
crm_debug_5("assign nodes to colors");
stage4(data_set);
#if MEMCHECK_STAGE_4
check_and_exit(4);
#endif
crm_debug_5("creating actions and internal ording constraints");
stage5(data_set);
#if MEMCHECK_STAGE_5
check_and_exit(5);
#endif
crm_debug_5("processing fencing and shutdown cases");
stage6(data_set);
#if MEMCHECK_STAGE_6
check_and_exit(6);
#endif
crm_debug_5("applying ordering constraints");
stage7(data_set);
#if MEMCHECK_STAGE_7
check_and_exit(7);
#endif
crm_debug_5("creating transition graph");
stage8(data_set);
#if MEMCHECK_STAGE_8
check_and_exit(8);
#endif
crm_debug_2("=#=#=#=#= Summary =#=#=#=#=");
crm_debug_2("\t========= Set %d (Un-runnable) =========", -1);
if(crm_log_level > LOG_DEBUG) {
slist_iter(action, action_t, data_set->actions, lpc,
if(action->optional == FALSE
&& action->runnable == FALSE
&& action->pseudo == FALSE) {
log_action(LOG_DEBUG_2, "\t", action, TRUE);
}
);
}
return data_set->graph;
}
diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c
index 1d3075e70f..312a5a6d85 100644
--- a/crm/pengine/ptest.c
+++ b/crm/pengine/ptest.c
@@ -1,456 +1,453 @@
/* $Id: ptest.c,v 1.80 2006/07/18 06:15:54 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/transition.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#define OPTARGS "V?X:D:G:I:Lwxd:a"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <pengine.h>
#include <lib/crm/pengine/utils.h>
#include <allocate.h>
gboolean use_stdin = FALSE;
gboolean inhibit_exit = FALSE;
gboolean all_actions = FALSE;
extern crm_data_t * do_calculations(
pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now);
extern void cleanup_calculations(pe_working_set_t *data_set);
char *use_date = NULL;
FILE *dot_strm = NULL;
#define DOT_PREFIX "PE_DOT: "
/* #define DOT_PREFIX "" */
#define dot_write(fmt...) if(dot_strm != NULL) { \
fprintf(dot_strm, fmt); \
fprintf(dot_strm, "\n"); \
fflush(dot_strm); \
} else { \
crm_debug(DOT_PREFIX""fmt); \
}
static void
init_dotfile(void)
{
dot_write(" digraph \"g\" {");
/* dot_write(" size = \"30,30\""); */
/* dot_write(" graph ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" bb = \"0,0,398.922306,478.927856\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" node ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" shape = \"ellipse\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" edge ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
}
static void
usage(const char *cli, int exitcode)
{
FILE *out = exitcode?stderr:stdout;
fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli);
fprintf(out, " --%s (-%c): This text\n\n", "help", '?');
fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V');
fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L');
fprintf(out, " --%s (-%c): Look for xml on stdin\n", "xml-stream", 'x');
fprintf(out, " --%s (-%c)\t<filename> : Look for xml in the named file\n\n", "xml-file", 'X');
fprintf(out, " --%s (-%c)\t<filename> : Save the transition graph to the named file\n", "save-graph", 'G');
fprintf(out, " --%s (-%c)\t<filename> : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D');
fprintf(out, " --%s (-%c)\t<filename> : Save the input to the named file\n", "save-input", 'I');
exit(exitcode);
}
static char *
create_action_name(action_t *action)
{
char *action_name = NULL;
const char *action_host = NULL;
if(action->node) {
action_host = action->node->details->uname;
action_name = crm_concat(action->uuid, action_host, ' ');
} else if(action->pseudo) {
action_name = crm_strdup(action->uuid);
} else {
action_host = "<none>";
action_name = crm_concat(action->uuid, action_host, ' ');
}
return action_name;
}
gboolean USE_LIVE_CIB = FALSE;
int
main(int argc, char **argv)
{
gboolean all_good = TRUE;
enum transition_status graph_rc = -1;
crm_graph_t *transition = NULL;
ha_time_t *a_date = NULL;
cib_t * cib_conn = NULL;
crm_data_t * cib_object = NULL;
int argerr = 0;
int flag;
char *msg_buffer = NULL;
gboolean optional = FALSE;
pe_working_set_t data_set;
const char *xml_file = NULL;
const char *dot_file = NULL;
const char *graph_file = NULL;
const char *input_file = NULL;
cl_log_set_entity("ptest");
cl_log_set_facility(LOG_USER);
set_crm_log_level(LOG_CRIT-1);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?'},
{"verbose", 0, 0, 'V'},
{"live-check", 0, 0, 'L'},
{"xml-stream", 0, 0, 'x'},
{"xml-file", 1, 0, 'X'},
{"save-graph", 1, 0, 'G'},
{"save-dotfile",1, 0, 'D'},
{"save-input", 1, 0, 'I'},
{0, 0, 0, 0}
};
#endif
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
#endif
case 'a':
all_actions = TRUE;
break;
case 'w':
inhibit_exit = TRUE;
break;
case 'x':
use_stdin = TRUE;
break;
case 'X':
xml_file = crm_strdup(optarg);
break;
case 'd':
use_date = crm_strdup(optarg);
break;
case 'D':
dot_file = crm_strdup(optarg);
break;
case 'G':
graph_file = crm_strdup(optarg);
break;
case 'I':
input_file = crm_strdup(optarg);
break;
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage("ptest", 0);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage("ptest", 1);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
if(USE_LIVE_CIB) {
int rc = cib_ok;
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, "ptest", cib_command_synchronous);
if(rc == cib_ok) {
crm_info("Reading XML from: live cluster");
cib_object = get_cib_copy(cib_conn);
} else {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
if(strstr(xml_file, ".bz2") != NULL) {
cib_object = file2xml(xml_strm, TRUE);
} else {
cib_object = file2xml(xml_strm, FALSE);
}
} else if(use_stdin) {
cib_object = stdin2xml();
} else {
usage("ptest", 1);
}
#ifdef MCHECK
mtrace();
#endif
CRM_CHECK(cib_object != NULL, return 4);
crm_notice("Required feature set: %s", feature_set(cib_object));
do_id_check(cib_object, NULL, FALSE, FALSE);
if(!validate_with_dtd(cib_object,FALSE,HA_LIBDIR"/heartbeat/crm.dtd")) {
crm_crit("%s is not a valid configuration", xml_file?xml_file:"stding");
all_good = FALSE;
}
if(input_file != NULL) {
FILE *input_strm = fopen(input_file, "w");
msg_buffer = dump_xml_formatted(cib_object);
fprintf(input_strm, "%s\n", msg_buffer);
fflush(input_strm);
fclose(input_strm);
crm_free(msg_buffer);
}
- crm_zero_mem_stats(NULL);
#ifdef HA_MALLOC_TRACK
cl_malloc_dump_allocated(LOG_DEBUG_2, TRUE);
#endif
if(use_date != NULL) {
a_date = parse_date(&use_date);
log_date(LOG_WARNING, "Set fake 'now' to",
a_date, ha_log_date|ha_log_time);
log_date(LOG_WARNING, "Set fake 'now' to (localtime)",
a_date, ha_log_date|ha_log_time|ha_log_local);
}
do_calculations(&data_set, cib_object, a_date);
msg_buffer = dump_xml_formatted(data_set.graph);
if(graph_file != NULL) {
FILE *graph_strm = fopen(graph_file, "w");
fprintf(graph_strm, "%s\n", msg_buffer);
fflush(graph_strm);
fclose(graph_strm);
} else {
fprintf(stdout, "%s\n", msg_buffer);
fflush(stdout);
}
crm_free(msg_buffer);
dot_strm = fopen(dot_file, "w");
init_dotfile();
slist_iter(
action, action_t, data_set.actions, lpc,
const char *style = "filled";
const char *font = "black";
const char *color = "black";
const char *fill = NULL;
char *action_name = create_action_name(action);
crm_debug_3("Action %d: %p", action->id, action);
if(action->pseudo) {
font = "orange";
}
if(action->dumped) {
style = "bold";
color = "green";
} else if(action->rsc != NULL && action->rsc->is_managed == FALSE) {
fill = "purple";
if(all_actions == FALSE) {
goto dont_write;
}
} else if(action->optional) {
style = "dashed";
color = "blue";
if(all_actions == FALSE) {
goto dont_write;
}
} else {
fill = "red";
CRM_CHECK(action->runnable == FALSE, ;);
}
dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]",
action_name, style, color, font, fill?"fillcolor=":"", fill?fill:"");
dont_write:
crm_free(action_name);
);
slist_iter(
action, action_t, data_set.actions, lpc,
int last_action = -1;
slist_iter(
before, action_wrapper_t, action->actions_before, lpc2,
char *before_name = NULL;
char *after_name = NULL;
optional = FALSE;
if(last_action == before->action->id) {
continue;
}
last_action = before->action->id;
if(action->dumped && before->action->dumped) {
} else if(action->optional || before->action->optional) {
optional = TRUE;
}
before_name = create_action_name(before->action);
after_name = create_action_name(action);
if(all_actions || optional == FALSE) {
dot_write("\"%s\" -> \"%s\" [ style = %s]",
before_name, after_name,
optional?"dashed":"bold");
}
crm_free(before_name);
crm_free(after_name);
);
);
dot_write("}");
transition = unpack_graph(data_set.graph);
print_graph(LOG_NOTICE, transition);
do {
graph_rc = run_graph(transition);
} while(graph_rc == transition_active);
if(graph_rc != transition_complete) {
crm_crit("Transition failed: %s", transition_status(graph_rc));
print_graph(LOG_ERR, transition);
}
data_set.input = NULL;
cleanup_alloc_calculations(&data_set);
destroy_graph(transition);
- crm_mem_stats(NULL);
-#ifdef HA_MALLOC_TRACK
- cl_malloc_dump_allocated(LOG_ERR, TRUE);
-#endif
- CRM_CHECK(crm_mem_stats(NULL) == FALSE, all_good = FALSE; crm_err("Memory leak detected"));
CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced"));
crm_free(cib_object);
#ifdef MCHECK
muntrace();
#endif
+#ifdef HA_MALLOC_TRACK
+ cl_malloc_dump_allocated(LOG_ERR, TRUE);
+#endif
/* required for MallocDebug.app */
if(inhibit_exit) {
GMainLoop* mainloop = g_main_new(FALSE);
g_main_run(mainloop);
}
if(all_good) {
return 0;
}
return 5;
}
diff --git a/include/crm/common/util.h b/include/crm/common/util.h
index c40161de8e..8ec729b941 100644
--- a/include/crm/common/util.h
+++ b/include/crm/common/util.h
@@ -1,194 +1,179 @@
/* $Id: util.h,v 1.39 2006/08/14 09:06:31 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CRM_COMMON_UTIL__H
#define CRM_COMMON_UTIL__H
#include <signal.h>
#include <crm/common/xml.h>
#include <hb_api.h>
#include <ocf/oc_event.h>
#include <lrm/lrm_api.h>
#define DEBUG_INC SIGUSR1
#define DEBUG_DEC SIGUSR2
extern unsigned int crm_log_level;
extern gboolean crm_config_error;
extern gboolean crm_config_warning;
#define crm_config_err(fmt...) { crm_config_error = TRUE; crm_err(fmt); }
#define crm_config_warn(fmt...) { crm_config_warning = TRUE; crm_warn(fmt); }
extern gboolean crm_log_init(const char *entity);
/* returns the old value */
extern unsigned int set_crm_log_level(unsigned int level);
extern unsigned int get_crm_log_level(void);
extern char *crm_itoa(int an_int);
extern char *crm_strdup_fn(const char *a, const char *file, const char *fn, int line);
extern char *generate_hash_key(const char *crm_msg_reference, const char *sys);
extern char *generate_hash_value(const char *src_node, const char *src_subsys);
extern gboolean decodeNVpair(const char *srcstring,
char separator, char **name, char **value);
extern int compare_version(const char *version1, const char *version2);
extern char *generateReference(const char *custom1, const char *custom2);
extern void alter_debug(int nsig);
extern void g_hash_destroy_str(gpointer data);
extern void empty_uuid_cache(void);
extern const char *get_uuid(ll_cluster_t *hb, const char *uname);
extern const char *get_uname(ll_cluster_t *hb, const char *uuid);
extern void unget_uuid(const char *uname);
extern void set_uuid(
ll_cluster_t* hb, crm_data_t *node, const char *attr, const char *uname);
extern gboolean crm_is_true(const char * s);
extern int crm_str_to_boolean(const char * s, int * ret);
extern long crm_get_msec(const char * input);
extern gboolean ccm_have_quorum(oc_ed_t event);
extern const char *ccm_event_name(oc_ed_t event);
extern const char *op_status2text(op_status_t status);
extern char *generate_op_key(
const char *rsc_id, const char *op_type, int interval);
extern gboolean parse_op_key(
const char *key, char **rsc_id, char **op_type, int *interval);
extern char *generate_notify_key(
const char *rsc_id, const char *notify_type, const char *op_type);
-extern gboolean crm_mem_stats(volatile cl_mem_stats_t *mem_stats);
-
-extern void crm_zero_mem_stats(volatile cl_mem_stats_t *stats);
-
-extern void crm_save_mem_stats(const char *location, cl_mem_stats_t *saved_stats);
-
-extern gboolean crm_diff_mem_stats(
- int log_level_up, int log_level_down, const char *location,
- volatile cl_mem_stats_t *stats, volatile cl_mem_stats_t *saved_stats);
-
-extern void crm_xml_nbytes(crm_data_t *xml, long *bytes, long *allocs, long *frees);
-
-extern void crm_adjust_mem_stats(
- volatile cl_mem_stats_t *stats, long bytes, long allocs, long frees);
-
extern char *generate_transition_magic_v202(
const char *transition_key, int op_status);
extern char *generate_transition_magic(
const char *transition_key, int op_status, int op_rc);
extern gboolean decode_transition_magic(
const char *magic, char **uuid,
int *transition_id, int *action_id, int *op_status, int *op_rc);
extern char *generate_transition_key(int action, int transition_id, const char *node);
extern gboolean decode_transition_key(
const char *key, char **uuid, int *action, int *transition_id);
extern char *crm_concat(const char *prefix, const char *suffix, char join);
extern gboolean decode_op_key(
const char *key, char **rsc_id, char **op_type, int *interval);
extern void filter_action_parameters(crm_data_t *param_set, const char *version);
extern void filter_reload_parameters(crm_data_t *param_set, const char *restart_string);
#define safe_str_eq(a, b) crm_str_eq(a, b, FALSE)
extern gboolean crm_str_eq(const char *a, const char *b, gboolean use_case);
extern gboolean safe_str_neq(const char *a, const char *b);
extern int crm_parse_int(const char *text, const char *default_text);
extern int crm_int_helper(const char *text, char **end_text);
#define crm_atoi(text, default_text) crm_parse_int(text, default_text)
extern void crm_abort(const char *file, const char *function, int line,
const char *condition, gboolean do_fork);
extern char *generate_series_filename(
const char *directory, const char *series, int sequence, gboolean bzip);
extern int get_last_sequence(const char *directory, const char *series);
extern void write_last_sequence(
const char *directory, const char *series, int sequence, int max);
extern void crm_make_daemon(
const char *name, gboolean daemonize, const char *pidfile);
extern cl_mem_stats_t *crm_running_stats;
typedef struct pe_cluster_option_s {
const char *name;
const char *alt_name;
const char *type;
const char *values;
const char *default_value;
gboolean (*is_valid)(const char *);
const char *description_short;
const char *description_long;
} pe_cluster_option;
extern const char *cluster_option(
GHashTable* options, gboolean(*validate)(const char*),
const char *name, const char *old_name, const char *def_value);
extern const char *get_cluster_pref(
GHashTable *options, pe_cluster_option *option_list, int len, const char *name);
extern void config_metadata(
const char *name, const char *version, const char *desc_short, const char *desc_long,
pe_cluster_option *option_list, int len);
extern void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len);
extern gboolean check_time(const char *value);
extern gboolean check_timer(const char *value);
extern gboolean check_boolean(const char *value);
extern gboolean check_number(const char *value);
extern int char2score(const char *score);
extern char *score2char(int score);
extern gboolean crm_is_writable(
const char *dir, const char *file,
const char *user, const char *group, gboolean need_both);
#endif
diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c
index 8794758c8f..9e26e956d7 100644
--- a/lib/crm/common/ipc.c
+++ b/lib/crm/common/ipc.c
@@ -1,439 +1,433 @@
/* $Id: ipc.c,v 1.28 2006/08/14 08:52:08 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/crm.h>
#include <clplumbing/ipc.h>
#include <clplumbing/Gmain_timeout.h>
#include <clplumbing/cl_log.h>
#include <clplumbing/cl_signal.h>
#include <clplumbing/lsb_exitcodes.h>
#include <clplumbing/uids.h>
#include <clplumbing/realtime.h>
#include <clplumbing/GSource.h>
#include <clplumbing/cl_poll.h>
#include <crm/common/ipc.h>
#include <crm/msg_xml.h>
#include <ha_msg.h>
#include <crm/dmalloc_wrapper.h>
gboolean
send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, const char *node, gboolean force_ordered)
{
gboolean all_is_good = TRUE;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if (msg == NULL) {
crm_err("cant send NULL message");
all_is_good = FALSE;
} else if(hb_conn == NULL) {
crm_err("No heartbeat connection specified");
all_is_good = FALSE;
} else if(hb_conn->llc_ops->chan_is_connected(hb_conn) == FALSE) {
crm_err("Not connected to Heartbeat");
all_is_good = FALSE;
} else if(node != NULL) {
if(hb_conn->llc_ops->send_ordered_nodemsg(
hb_conn, msg, node) != HA_OK) {
all_is_good = FALSE;
crm_err("Send failed");
} else {
crm_debug_2("Message sent...");
}
} else if(force_ordered) {
if(hb_conn->llc_ops->send_ordered_clustermsg(hb_conn, msg) != HA_OK) {
all_is_good = FALSE;
crm_err("Broadcast Send failed");
} else {
crm_debug_2("Broadcast message sent...");
}
} else {
if(hb_conn->llc_ops->sendclustermsg(hb_conn, msg) != HA_OK) {
all_is_good = FALSE;
crm_err("Broadcast Send failed");
} else {
crm_debug_2("Broadcast message sent...");
}
}
if(all_is_good == FALSE && hb_conn != NULL) {
IPC_Channel *ipc = NULL;
IPC_Queue *send_q = NULL;
if(hb_conn->llc_ops->chan_is_connected(hb_conn) != HA_OK) {
ipc = hb_conn->llc_ops->ipcchan(hb_conn);
}
if(ipc != NULL) {
/* ipc->ops->resume_io(ipc); */
send_q = ipc->send_queue;
}
if(send_q != NULL) {
CRM_CHECK(send_q->current_qlen < send_q->max_qlen, ;);
}
}
crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"HA[outbound]",msg);
- crm_diff_mem_stats(LOG_DEBUG, LOG_DEBUG, __PRETTY_FUNCTION__, NULL, &saved_stats);
return all_is_good;
}
/* frees msg */
gboolean
send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg)
{
gboolean all_is_good = TRUE;
int fail_level = LOG_WARNING;
- cl_mem_stats_t saved_stats;
- crm_save_mem_stats(__PRETTY_FUNCTION__, &saved_stats);
if(ipc_client != NULL && ipc_client->conntype == IPC_CLIENT) {
fail_level = LOG_ERR;
}
if (msg == NULL) {
crm_err("cant send NULL message");
all_is_good = FALSE;
} else if (ipc_client == NULL) {
crm_err("cant send message without an IPC Channel");
all_is_good = FALSE;
} else if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
do_crm_log(fail_level, "IPC Channel to %d is not connected",
(int)ipc_client->farside_pid);
all_is_good = FALSE;
}
if(all_is_good && msg2ipcchan(msg, ipc_client) != HA_OK) {
do_crm_log(fail_level, "Could not send IPC message to %d",
(int)ipc_client->farside_pid);
all_is_good = FALSE;
if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
do_crm_log(fail_level,
"IPC Channel to %d is no longer connected",
(int)ipc_client->farside_pid);
} else if(ipc_client->conntype == IPC_CLIENT) {
if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) {
crm_err("Send queue to %d (size=%d) full.",
ipc_client->farside_pid,
(int)ipc_client->send_queue->max_qlen);
}
}
}
/* ipc_client->ops->resume_io(ipc_client); */
crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg);
- crm_diff_mem_stats(LOG_DEBUG, LOG_DEBUG, __PRETTY_FUNCTION__, NULL, &saved_stats);
return all_is_good;
}
void
default_ipc_connection_destroy(gpointer user_data)
{
return;
}
int
init_server_ipc_comms(
char *channel_name,
gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data),
void (*channel_connection_destroy)(gpointer user_data))
{
/* the clients wait channel is the other source of events.
* This source delivers the clients connection events.
* listen to this source at a relatively lower priority.
*/
char commpath[SOCKET_LEN];
IPC_WaitConnection *wait_ch;
sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name);
wait_ch = wait_channel_init(commpath);
if (wait_ch == NULL) {
return 1;
}
G_main_add_IPC_WaitConnection(
G_PRIORITY_LOW, wait_ch, NULL, FALSE,
channel_client_connect, channel_name,
channel_connection_destroy);
crm_debug_3("Listening on: %s", commpath);
return 0;
}
GCHSource*
init_client_ipc_comms(const char *channel_name,
gboolean (*dispatch)(
IPC_Channel* source_data, gpointer user_data),
void *client_data, IPC_Channel **ch)
{
IPC_Channel *a_ch = NULL;
GCHSource *the_source = NULL;
void *callback_data = client_data;
a_ch = init_client_ipc_comms_nodispatch(channel_name);
if(ch != NULL) {
*ch = a_ch;
if(callback_data == NULL) {
callback_data = a_ch;
}
}
if(a_ch == NULL) {
crm_warn("Setup of client connection failed,"
" not adding channel to mainloop");
return NULL;
}
if(dispatch == NULL) {
crm_warn("No dispatch method specified..."
"maybe you meant init_client_ipc_comms_nodispatch()?");
} else {
crm_debug_3("Adding dispatch method to channel");
the_source = G_main_add_IPC_Channel(
G_PRIORITY_HIGH, a_ch, FALSE, dispatch, callback_data,
default_ipc_connection_destroy);
}
return the_source;
}
IPC_Channel *
init_client_ipc_comms_nodispatch(const char *channel_name)
{
IPC_Channel *ch;
GHashTable *attrs;
static char path[] = IPC_PATH_ATTR;
char *commpath = NULL;
int local_socket_len = 2; /* 2 = '/' + '\0' */
local_socket_len += strlen(channel_name);
local_socket_len += strlen(CRM_SOCK_DIR);
crm_malloc0(commpath, local_socket_len);
if(commpath != NULL) {
sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name);
commpath[local_socket_len - 1] = '\0';
crm_debug_3("Attempting to talk on: %s", commpath);
}
attrs = g_hash_table_new(g_str_hash,g_str_equal);
g_hash_table_insert(attrs, path, commpath);
ch = ipc_channel_constructor(IPC_ANYTYPE, attrs);
g_hash_table_destroy(attrs);
if (ch == NULL) {
crm_err("Could not access channel on: %s", commpath);
crm_free(commpath);
return NULL;
} else if (ch->ops->initiate_connection(ch) != IPC_OK) {
crm_debug("Could not init comms on: %s", commpath);
ch->ops->destroy(ch);
crm_free(commpath);
return NULL;
}
ch->ops->set_recv_qlen(ch, 100);
ch->ops->set_send_qlen(ch, 100);
/* ch->should_send_block = TRUE; */
crm_debug_3("Processing of %s complete", commpath);
crm_free(commpath);
return ch;
}
IPC_WaitConnection *
wait_channel_init(char daemonsocket[])
{
IPC_WaitConnection *wait_ch;
mode_t mask;
char path[] = IPC_PATH_ATTR;
GHashTable * attrs;
attrs = g_hash_table_new(g_str_hash,g_str_equal);
g_hash_table_insert(attrs, path, daemonsocket);
mask = umask(0);
wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs);
if (wait_ch == NULL) {
cl_perror("Can't create wait channel of type %s",
IPC_ANYTYPE);
exit(1);
}
mask = umask(mask);
g_hash_table_destroy(attrs);
return wait_ch;
}
longclock_t ipc_call_start = 0;
longclock_t ipc_call_stop = 0;
longclock_t ipc_call_diff = 0;
gboolean
subsystem_msg_dispatch(IPC_Channel *sender, void *user_data)
{
int lpc = 0;
HA_Message *msg = NULL;
ha_msg_input_t *new_input = NULL;
gboolean all_is_well = TRUE;
const char *sys_to;
const char *task;
while(IPC_ISRCONN(sender)) {
gboolean process = FALSE;
if(sender->ops->is_message_pending(sender) == 0) {
break;
}
msg = msgfromIPC_noauth(sender);
if (msg == NULL) {
crm_err("No message from %d this time",
sender->farside_pid);
continue;
}
lpc++;
new_input = new_ha_msg_input(msg);
crm_msg_del(msg);
msg = NULL;
crm_log_message(LOG_MSG, new_input->msg);
sys_to = cl_get_string(new_input->msg, F_CRM_SYS_TO);
task = cl_get_string(new_input->msg, F_CRM_TASK);
if(safe_str_eq(task, CRM_OP_HELLO)) {
process = TRUE;
} else if(sys_to == NULL) {
crm_err("Value of %s was NULL!!", F_CRM_SYS_TO);
} else if(task == NULL) {
crm_err("Value of %s was NULL!!", F_CRM_TASK);
} else {
process = TRUE;
}
if(process){
gboolean (*process_function)
(HA_Message *msg, crm_data_t *data, IPC_Channel *sender) = NULL;
process_function = user_data;
#ifdef MSG_LOG
crm_log_message_adv(
LOG_MSG, __FUNCTION__, new_input->msg);
#endif
if(ipc_call_diff_max_ms > 0) {
ipc_call_start = time_longclock();
}
if(FALSE == process_function(
new_input->msg, new_input->xml, sender)) {
crm_warn("Received a message destined for %s"
" by mistake", sys_to);
}
if(ipc_call_diff_max_ms > 0) {
unsigned int ipc_call_diff_ms = 0;
ipc_call_stop = time_longclock();
ipc_call_diff = sub_longclock(
ipc_call_stop, ipc_call_start);
ipc_call_diff_ms = longclockto_ms(
ipc_call_diff);
if(ipc_call_diff_ms > ipc_call_diff_max_ms) {
crm_err("%s took %dms to complete",
sys_to, ipc_call_diff_ms);
}
}
} else {
#ifdef MSG_LOG
crm_log_message_adv(
LOG_ERR, NULL, new_input->msg);
#endif
}
delete_ha_msg_input(new_input);
new_input = NULL;
if(sender->ch_status == IPC_CONNECT) {
break;
}
}
crm_debug_2("Processed %d messages", lpc);
if (sender->ch_status != IPC_CONNECT) {
crm_err("The server %d has left us: Shutting down...NOW",
sender->farside_pid);
exit(1); /* shutdown properly later */
return !all_is_well;
}
return all_is_well;
}
gboolean
is_ipc_empty(IPC_Channel *ch)
{
if(ch == NULL) {
return TRUE;
} else if(ch->send_queue->current_qlen == 0
&& ch->recv_queue->current_qlen == 0) {
return TRUE;
}
return FALSE;
}
diff --git a/lib/crm/common/utils.c b/lib/crm/common/utils.c
index e828a76e1a..2d3914f7ef 100644
--- a/lib/crm/common/utils.c
+++ b/lib/crm/common/utils.c
@@ -1,1867 +1,1700 @@
/* $Id: utils.c,v 1.64 2006/08/14 09:06:31 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <heartbeat.h>
#include <ha_msg.h>
#include <clplumbing/cl_log.h>
#include <clplumbing/cl_signal.h>
#include <clplumbing/cl_syslog.h>
#include <clplumbing/cl_misc.h>
#include <clplumbing/coredumps.h>
#include <clplumbing/lsb_exitcodes.h>
#include <clplumbing/cl_pidfile.h>
#include <time.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/dmalloc_wrapper.h>
#ifndef MAXLINE
# define MAXLINE 512
#endif
static uint ref_counter = 0;
gboolean crm_assert_failed = FALSE;
unsigned int crm_log_level = LOG_INFO;
gboolean crm_config_error = FALSE;
gboolean crm_config_warning = FALSE;
void crm_set_env_options(void);
gboolean
check_time(const char *value)
{
if(crm_get_msec(value) < 5000) {
return FALSE;
}
return TRUE;
}
gboolean
check_timer(const char *value)
{
if(crm_get_msec(value) < 0) {
return FALSE;
}
return TRUE;
}
gboolean
check_boolean(const char *value)
{
int tmp = FALSE;
if(crm_str_to_boolean(value, &tmp) != 1) {
return FALSE;
}
return TRUE;
}
gboolean
check_number(const char *value)
{
errno = 0;
if(value == NULL) {
return FALSE;
} else if(safe_str_eq(value, MINUS_INFINITY_S)) {
} else if(safe_str_eq(value, INFINITY_S)) {
} else {
crm_int_helper(value, NULL);
}
if(errno != 0) {
return FALSE;
}
return TRUE;
}
int
char2score(const char *score)
{
int score_f = 0;
if(score == NULL) {
} else if(safe_str_eq(score, MINUS_INFINITY_S)) {
score_f = -INFINITY;
} else if(safe_str_eq(score, INFINITY_S)) {
score_f = INFINITY;
} else if(safe_str_eq(score, "+"INFINITY_S)) {
score_f = INFINITY;
} else {
score_f = crm_parse_int(score, NULL);
if(score_f > 0 && score_f > INFINITY) {
score_f = INFINITY;
} else if(score_f < 0 && score_f < -INFINITY) {
score_f = -INFINITY;
}
}
return score_f;
}
char *
score2char(int score)
{
if(score >= INFINITY) {
return crm_strdup("+"INFINITY_S);
} else if(score <= -INFINITY) {
return crm_strdup("-"INFINITY_S);
}
return crm_itoa(score);
}
const char *
cluster_option(GHashTable* options, gboolean(*validate)(const char*),
const char *name, const char *old_name, const char *def_value)
{
const char *value = NULL;
CRM_ASSERT(name != NULL);
if(options != NULL) {
value = g_hash_table_lookup(options, name);
}
if(value == NULL && old_name && options != NULL) {
value = g_hash_table_lookup(options, old_name);
if(value != NULL) {
crm_config_warn("Using deprecated name '%s' for"
" cluster option '%s'", old_name, name);
g_hash_table_insert(
options, crm_strdup(name), crm_strdup(value));
value = g_hash_table_lookup(options, old_name);
}
}
if(value == NULL) {
crm_notice("Using default value '%s' for cluster option '%s'",
value, name);
if(options == NULL) {
return def_value;
}
g_hash_table_insert(
options, crm_strdup(name), crm_strdup(def_value));
value = g_hash_table_lookup(options, name);
}
if(validate && validate(value) == FALSE) {
crm_config_err("Value '%s' for cluster option '%s' is invalid."
" Defaulting to %s", value, name, def_value);
g_hash_table_replace(options, crm_strdup(name),
crm_strdup(def_value));
value = g_hash_table_lookup(options, name);
}
return value;
}
const char *
get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
{
int lpc = 0;
const char *value = NULL;
gboolean found = FALSE;
for(lpc = 0; lpc < len; lpc++) {
if(safe_str_eq(name, option_list[lpc].name)) {
found = TRUE;
value = cluster_option(options,
option_list[lpc].is_valid,
option_list[lpc].name,
option_list[lpc].alt_name,
option_list[lpc].default_value);
}
}
CRM_CHECK(found, crm_err("No option named: %s", name));
CRM_ASSERT(value != NULL);
return value;
}
void
config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long,
pe_cluster_option *option_list, int len)
{
int lpc = 0;
fprintf(stdout, "<?xml version=\"1.0\"?>"
"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
"<resource-agent name=\"%s\">\n"
" <version>%s</version>\n"
" <longdesc lang=\"en\">%s</longdesc>\n"
" <shortdesc lang=\"en\">%s</shortdesc>\n"
" <parameters>\n", name, version, desc_long, desc_short);
for(lpc = 0; lpc < len; lpc++) {
if(option_list[lpc].description_long == NULL
&& option_list[lpc].description_short == NULL) {
continue;
}
fprintf(stdout, " <parameter name=\"%s\" unique=\"0\">\n"
" <shortdesc lang=\"en\">%s</shortdesc>\n"
" <content type=\"%s\" default=\"%s\"/>\n"
" <longdesc lang=\"en\">%s%s%s</longdesc>\n"
" </parameter>\n",
option_list[lpc].name,
option_list[lpc].description_short,
option_list[lpc].type,
option_list[lpc].default_value,
option_list[lpc].description_long?option_list[lpc].description_long:option_list[lpc].description_short,
option_list[lpc].values?" Allowed values: ":"",
option_list[lpc].values?option_list[lpc].values:"");
}
fprintf(stdout, " </parameters>\n</resource-agent>\n");
}
void
verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
{
int lpc = 0;
for(lpc = 0; lpc < len; lpc++) {
cluster_option(options,
option_list[lpc].is_valid,
option_list[lpc].name,
option_list[lpc].alt_name,
option_list[lpc].default_value);
}
}
char *
generateReference(const char *custom1, const char *custom2)
{
const char *local_cust1 = custom1;
const char *local_cust2 = custom2;
int reference_len = 4;
char *since_epoch = NULL;
reference_len += 20; /* too big */
reference_len += 40; /* too big */
if(local_cust1 == NULL) { local_cust1 = "_empty_"; }
reference_len += strlen(local_cust1);
if(local_cust2 == NULL) { local_cust2 = "_empty_"; }
reference_len += strlen(local_cust2);
crm_malloc0(since_epoch, reference_len);
if(since_epoch != NULL) {
sprintf(since_epoch, "%s-%s-%ld-%u",
local_cust1, local_cust2,
(unsigned long)time(NULL), ref_counter++);
}
return since_epoch;
}
gboolean
decodeNVpair(const char *srcstring, char separator, char **name, char **value)
{
int lpc = 0;
int len = 0;
const char *temp = NULL;
CRM_ASSERT(name != NULL && value != NULL);
*name = NULL;
*value = NULL;
crm_debug_4("Attempting to decode: [%s]", srcstring);
if (srcstring != NULL) {
len = strlen(srcstring);
while(lpc <= len) {
if (srcstring[lpc] == separator) {
crm_malloc0(*name, lpc+1);
if(*name == NULL) {
break; /* and return FALSE */
}
strncpy(*name, srcstring, lpc);
(*name)[lpc] = '\0';
/* this sucks but as the strtok manpage says..
* it *is* a bug
*/
len = len-lpc; len--;
if(len <= 0) {
*value = NULL;
} else {
crm_malloc0(*value, len+1);
if(*value == NULL) {
crm_free(*name);
break; /* and return FALSE */
}
temp = srcstring+lpc+1;
strncpy(*value, temp, len);
(*value)[len] = '\0';
}
return TRUE;
}
lpc++;
}
}
if(*name != NULL) {
crm_free(*name);
}
*name = NULL;
*value = NULL;
return FALSE;
}
char *
crm_concat(const char *prefix, const char *suffix, char join)
{
int len = 0;
char *new_str = NULL;
CRM_ASSERT(prefix != NULL);
CRM_ASSERT(suffix != NULL);
len = strlen(prefix) + strlen(suffix) + 2;
crm_malloc0(new_str, (len));
sprintf(new_str, "%s%c%s", prefix, join, suffix);
new_str[len-1] = 0;
return new_str;
}
char *
generate_hash_key(const char *crm_msg_reference, const char *sys)
{
char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_');
crm_debug_3("created hash key: (%s)", hash_key);
return hash_key;
}
char *
generate_hash_value(const char *src_node, const char *src_subsys)
{
char *hash_value = NULL;
if (src_node == NULL || src_subsys == NULL) {
return NULL;
}
if (strcasecmp(CRM_SYSTEM_DC, src_subsys) == 0) {
hash_value = crm_strdup(src_subsys);
if (!hash_value) {
crm_err("memory allocation failed in "
"generate_hash_value()");
}
return hash_value;
}
hash_value = crm_concat(src_node, src_subsys, '_');
crm_info("created hash value: (%s)", hash_value);
return hash_value;
}
char *
crm_itoa(int an_int)
{
int len = 32;
char *buffer = NULL;
crm_malloc0(buffer, (len+1));
if(buffer != NULL) {
snprintf(buffer, len, "%d", an_int);
}
return buffer;
}
extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str);
gboolean
crm_log_init(const char *entity)
{
/* const char *test = "Testing log daemon connection"; */
/* Redirect messages from glib functions to our handler */
/* cl_malloc_forced_for_glib(); */
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... - this enum is a bit field (!) */
g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
cl_log_set_entity(entity);
cl_log_set_facility(LOG_LOCAL7);
cl_set_corerootdir(HA_COREDIR);
cl_cdtocoredir();
crm_set_env_options();
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
return TRUE;
}
/* returns the old value */
unsigned int
set_crm_log_level(unsigned int level)
{
unsigned int old = crm_log_level;
while(crm_log_level < 100 && crm_log_level < level) {
alter_debug(DEBUG_INC);
}
while(crm_log_level > 0 && crm_log_level > level) {
alter_debug(DEBUG_DEC);
}
return old;
}
unsigned int
get_crm_log_level(void)
{
return crm_log_level;
}
void
crm_log_message_adv(int level, const char *prefix, const HA_Message *msg)
{
if((int)crm_log_level >= level) {
do_crm_log(level, "#========= %s message start ==========#", prefix?prefix:"");
if(level > LOG_DEBUG) {
cl_log_message(LOG_DEBUG, msg);
} else {
cl_log_message(level, msg);
}
}
}
int
compare_version(const char *version1, const char *version2)
{
int rc = 0;
int lpc = 0;
char *step1 = NULL, *step2 = NULL;
char *rest1 = NULL, *rest2 = NULL;
if(version1 == NULL && version2 == NULL) {
return 0;
} else if(version1 == NULL) {
return -1;
} else if(version2 == NULL) {
return 1;
}
rest1 = crm_strdup(version1);
rest2 = crm_strdup(version2);
while(1) {
int cmp = 0;
int step1_i = 0;
int step2_i = 0;
char *tmp1 = NULL, *tmp2 = NULL;
decodeNVpair(rest1, '.', &step1, &tmp1);
decodeNVpair(rest2, '.', &step2, &tmp2);
if(step1 == NULL && step2 == NULL) {
CRM_CHECK(tmp1 == tmp2 && tmp1 == NULL,
crm_err("Leftover data: %s, %s",
crm_str(tmp1), crm_str(tmp2)));
break;
}
if(step1 != NULL) {
step1_i = crm_parse_int(step1, NULL);
}
if(step2 != NULL) {
step2_i = crm_parse_int(step2, NULL);
}
if(step1_i < step2_i){
cmp = -1;
} else if (step1_i > step2_i){
cmp = 1;
}
crm_debug_4("compare[%d (%d)]: %d(%s) %d(%s)",
lpc++, cmp,
step1_i, crm_str(step1),
step2_i, crm_str(step2));
crm_free(rest1);
crm_free(rest2);
crm_free(step1);
crm_free(step2);
rest1 = tmp1;
rest2 = tmp2;
if(cmp < 0) {
rc = -1;
break;
} else if(cmp > 0) {
rc = 1;
break;
}
}
crm_free(rest1);
crm_free(rest2);
if(rc == 0) {
crm_debug_3("%s == %s", version1, version2);
} else if(rc < 0) {
crm_debug_3("%s < %s", version1, version2);
} else if(rc > 0) {
crm_debug_3("%s > %s", version1, version2);
}
return rc;
}
gboolean do_stderr = FALSE;
void
alter_debug(int nsig)
{
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
switch(nsig) {
case DEBUG_INC:
if (crm_log_level < 100) {
crm_log_level++;
}
break;
case DEBUG_DEC:
if (crm_log_level > 0) {
crm_log_level--;
}
break;
default:
fprintf(stderr, "Unknown signal %d\n", nsig);
cl_log(LOG_ERR, "Unknown signal %d", nsig);
break;
}
}
void g_hash_destroy_str(gpointer data)
{
crm_free(data);
}
int
crm_int_helper(const char *text, char **end_text)
{
int atoi_result = -1;
char *local_end_text = NULL;
errno = 0;
if(text != NULL) {
if(end_text != NULL) {
atoi_result = (int)strtol(text, end_text, 10);
} else {
atoi_result = (int)strtol(text, &local_end_text, 10);
}
/* CRM_CHECK(errno != EINVAL); */
if(errno == EINVAL) {
crm_err("Conversion of %s failed", text);
atoi_result = -1;
} else {
if(errno == ERANGE) {
crm_err("Conversion of %s was clipped", text);
}
if(end_text == NULL && local_end_text[0] != '\0') {
crm_err("Characters left over after parsing "
"\"%s\": \"%s\"", text, local_end_text);
}
}
}
return atoi_result;
}
int
crm_parse_int(const char *text, const char *default_text)
{
int atoi_result = -1;
if(text != NULL) {
atoi_result = crm_int_helper(text, NULL);
if(errno == 0) {
return atoi_result;
}
}
if(default_text != NULL) {
atoi_result = crm_int_helper(default_text, NULL);
if(errno == 0) {
return atoi_result;
}
} else {
crm_err("No default conversion value supplied");
}
return -1;
}
gboolean
crm_str_eq(const char *a, const char *b, gboolean use_case)
{
if(a == NULL || b == NULL) {
/* shouldn't be comparing NULLs */
CRM_CHECK(a != b, return TRUE);
return FALSE;
} else if(use_case && a[0] != b[0]) {
return FALSE;
} else if(a == b) {
return TRUE;
} else if(strcasecmp(a, b) == 0) {
return TRUE;
}
return FALSE;
}
gboolean
safe_str_neq(const char *a, const char *b)
{
if(a == b) {
return FALSE;
} else if(a==NULL || b==NULL) {
return TRUE;
} else if(strcasecmp(a, b) == 0) {
return FALSE;
}
return TRUE;
}
char *
crm_strdup_fn(const char *src, const char *file, const char *fn, int line)
{
char *dup = NULL;
CRM_CHECK(src != NULL, return NULL);
#ifdef HA_MALLOC_TRACK
dup = cl_malloc_track(strlen(src) + 1, file, fn, line);
#else
crm_malloc0(dup, strlen(src) + 1);
#endif
return strcpy(dup, src);
}
static GHashTable *crm_uuid_cache = NULL;
static GHashTable *crm_uname_cache = NULL;
void
empty_uuid_cache(void)
{
if(crm_uuid_cache != NULL) {
g_hash_table_destroy(crm_uuid_cache);
crm_uuid_cache = NULL;
}
}
void
unget_uuid(const char *uname)
{
if(crm_uuid_cache == NULL) {
return;
}
g_hash_table_remove(crm_uuid_cache, uname);
}
const char *
get_uuid(ll_cluster_t *hb, const char *uname)
{
cl_uuid_t uuid_raw;
char *uuid_calc = NULL;
const char *unknown = "00000000-0000-0000-0000-000000000000";
if(crm_uuid_cache == NULL) {
crm_uuid_cache = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
CRM_CHECK(uname != NULL, return NULL);
/* avoid blocking calls where possible */
uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname);
if(uuid_calc != NULL) {
return uuid_calc;
}
if(hb->llc_ops->get_uuid_by_name(hb, uname, &uuid_raw) == HA_FAIL) {
crm_err("get_uuid_by_name() call failed for host %s", uname);
crm_free(uuid_calc);
return NULL;
}
crm_malloc0(uuid_calc, 50);
if(uuid_calc == NULL) {
return NULL;
}
cl_uuid_unparse(&uuid_raw, uuid_calc);
if(safe_str_eq(uuid_calc, unknown)) {
crm_warn("Could not calculate UUID for %s", uname);
crm_free(uuid_calc);
return NULL;
}
g_hash_table_insert(crm_uuid_cache, crm_strdup(uname), uuid_calc);
uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname);
return uuid_calc;
}
const char *
get_uname(ll_cluster_t *hb, const char *uuid)
{
char *uname = NULL;
if(crm_uuid_cache == NULL) {
crm_uname_cache = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
CRM_CHECK(uuid != NULL, return NULL);
/* avoid blocking calls where possible */
uname = g_hash_table_lookup(crm_uname_cache, uuid);
if(uname != NULL) {
return uname;
}
if(uuid != NULL) {
cl_uuid_t uuid_raw;
char *uuid_copy = crm_strdup(uuid);
cl_uuid_parse(uuid_copy, &uuid_raw);
if(hb->llc_ops->get_name_by_uuid(
hb, &uuid_raw, uname, 256) == HA_FAIL) {
crm_err("Could not calculate UUID for %s", uname);
uname = NULL;
crm_free(uuid_copy);
} else {
g_hash_table_insert(
crm_uuid_cache,
uuid_copy, crm_strdup(uname));
uname = g_hash_table_lookup(crm_uname_cache, uuid);
}
return uname;
}
return NULL;
}
void
set_uuid(ll_cluster_t *hb,crm_data_t *node,const char *attr,const char *uname)
{
const char *uuid_calc = get_uuid(hb, uname);
crm_xml_add(node, attr, uuid_calc);
return;
}
#define ENV_PREFIX "HA_"
void
crm_set_env_options(void)
{
char *param_val = NULL;
const char *param_name = NULL;
/* apparently we're not allowed to free the result of getenv */
param_name = ENV_PREFIX "" KEY_DEBUGLEVEL;
param_val = getenv(param_name);
if(param_val != NULL) {
int debug_level = crm_parse_int(param_val, NULL);
if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) {
set_crm_log_level(LOG_INFO + debug_level);
}
crm_debug("%s = %s", param_name, param_val);
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_FACILITY;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int facility = cl_syslogfac_str2int(param_val);
if(facility >= 0) {
cl_log_set_facility(facility);
}
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_LOGFILE;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
if(safe_str_eq("/dev/null", param_val)) {
param_val = NULL;
}
cl_log_set_logfile(param_val);
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_DBGFILE;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
if(safe_str_eq("/dev/null", param_val)) {
param_val = NULL;
}
cl_log_set_debugfile(param_val);
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_LOGDAEMON;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int uselogd;
cl_str_to_boolean(param_val, &uselogd);
cl_log_set_uselogd(uselogd);
if(uselogd) {
cl_set_logging_wqueue_maxlen(500);
cl_log_set_logd_channel_source(NULL, NULL);
}
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_CONNINTVAL;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int logdtime;
logdtime = crm_get_msec(param_val);
cl_log_set_logdtime(logdtime);
param_val = NULL;
}
inherit_compress();
}
gboolean
crm_is_true(const char * s)
{
gboolean ret = FALSE;
if(s != NULL) {
cl_str_to_boolean(s, &ret);
}
return ret;
}
int
crm_str_to_boolean(const char * s, int * ret)
{
if(s == NULL) {
return -1;
} else if (strcasecmp(s, "true") == 0
|| strcasecmp(s, "on") == 0
|| strcasecmp(s, "yes") == 0
|| strcasecmp(s, "y") == 0
|| strcasecmp(s, "1") == 0){
*ret = TRUE;
return 1;
} else if (strcasecmp(s, "false") == 0
|| strcasecmp(s, "off") == 0
|| strcasecmp(s, "no") == 0
|| strcasecmp(s, "n") == 0
|| strcasecmp(s, "0") == 0){
*ret = FALSE;
return 1;
}
return -1;
}
#ifndef NUMCHARS
# define NUMCHARS "0123456789."
#endif
#ifndef WHITESPACE
# define WHITESPACE " \t\n\r\f"
#endif
long
crm_get_msec(const char * input)
{
const char * cp = input;
const char * units;
long multiplier = 1000;
long divisor = 1;
long ret = -1;
double dret;
if(input == NULL) {
return 0;
}
cp += strspn(cp, WHITESPACE);
units = cp + strspn(cp, NUMCHARS);
units += strspn(units, WHITESPACE);
if (strchr(NUMCHARS, *cp) == NULL) {
return ret;
}
if (strncasecmp(units, "ms", 2) == 0
|| strncasecmp(units, "msec", 4) == 0) {
multiplier = 1;
divisor = 1;
}else if (strncasecmp(units, "us", 2) == 0
|| strncasecmp(units, "usec", 4) == 0) {
multiplier = 1;
divisor = 1000;
}else if (strncasecmp(units, "s", 1) == 0
|| strncasecmp(units, "sec", 3) == 0) {
multiplier = 1000;
divisor = 1;
}else if (strncasecmp(units, "m", 1) == 0
|| strncasecmp(units, "min", 3) == 0) {
multiplier = 60*1000;
divisor = 1;
}else if (strncasecmp(units, "h", 1) == 0
|| strncasecmp(units, "hr", 2) == 0) {
multiplier = 60*60*1000;
divisor = 1;
}else if (*units != EOS && *units != '\n'
&& *units != '\r') {
return ret;
}
dret = atof(cp);
dret *= (double)multiplier;
dret /= (double)divisor;
dret += 0.5;
ret = (long)dret;
return(ret);
}
gboolean
ccm_have_quorum(oc_ed_t event)
{
if(event==OC_EV_MS_NEW_MEMBERSHIP) {
return TRUE;
}
return FALSE;
}
const char *
ccm_event_name(oc_ed_t event)
{
if(event==OC_EV_MS_NEW_MEMBERSHIP) {
return "NEW MEMBERSHIP";
} else if(event==OC_EV_MS_NOT_PRIMARY) {
return "NOT PRIMARY";
} else if(event==OC_EV_MS_PRIMARY_RESTORED) {
return "PRIMARY RESTORED";
} else if(event==OC_EV_MS_EVICTED) {
return "EVICTED";
} else if(event==OC_EV_MS_INVALID) {
return "INVALID";
}
return "NO QUORUM MEMBERSHIP";
}
const char *
op_status2text(op_status_t status)
{
switch(status) {
case LRM_OP_PENDING:
return "pending";
break;
case LRM_OP_DONE:
return "complete";
break;
case LRM_OP_ERROR:
return "Error";
break;
case LRM_OP_TIMEOUT:
return "Timed Out";
break;
case LRM_OP_NOTSUPPORTED:
return "NOT SUPPORTED";
break;
case LRM_OP_CANCELLED:
return "Cancelled";
break;
}
CRM_CHECK(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED,
crm_err("Unknown status: %d", status));
return "UNKNOWN!";
}
char *
generate_op_key(const char *rsc_id, const char *op_type, int interval)
{
int len = 35;
char *op_id = NULL;
CRM_CHECK(rsc_id != NULL, return NULL);
CRM_CHECK(op_type != NULL, return NULL);
len += strlen(op_type);
len += strlen(rsc_id);
crm_malloc0(op_id, len);
CRM_CHECK(op_id != NULL, return NULL);
sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval);
return op_id;
}
gboolean
parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
{
char *mutable_key = NULL;
char *mutable_key_ptr = NULL;
int len = 0, offset = 0, ch = 0;
CRM_CHECK(key != NULL, return FALSE);
*interval = 0;
len = strlen(key);
offset = len-1;
crm_debug_3("Source: %s", key);
while(offset > 0 && isdigit(key[offset])) {
int digits = len-offset;
ch = key[offset] - '0';
CRM_CHECK(ch < 10, return FALSE);
CRM_CHECK(ch >= 0, return FALSE);
while(digits > 1) {
digits--;
ch = ch * 10;
}
*interval += ch;
offset--;
}
crm_debug_3(" Interval: %d", *interval);
CRM_CHECK(key[offset] == '_', return FALSE);
mutable_key = crm_strdup(key);
mutable_key_ptr = mutable_key_ptr;
mutable_key[offset] = 0;
offset--;
while(offset > 0 && key[offset] != '_') {
offset--;
}
CRM_CHECK(key[offset] == '_',
crm_free(mutable_key); return FALSE);
mutable_key_ptr = mutable_key+offset+1;
crm_debug_3(" Action: %s", mutable_key_ptr);
*op_type = crm_strdup(mutable_key_ptr);
mutable_key[offset] = 0;
offset--;
CRM_CHECK(mutable_key != mutable_key_ptr,
crm_free(mutable_key); return FALSE);
crm_debug_3(" Resource: %s", mutable_key);
*rsc_id = crm_strdup(mutable_key);
crm_free(mutable_key);
return TRUE;
}
char *
generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
{
int len = 12;
char *op_id = NULL;
CRM_CHECK(rsc_id != NULL, return NULL);
CRM_CHECK(op_type != NULL, return NULL);
CRM_CHECK(notify_type != NULL, return NULL);
len += strlen(op_type);
len += strlen(rsc_id);
len += strlen(notify_type);
crm_malloc0(op_id, len);
if(op_id != NULL) {
sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
}
return op_id;
}
char *
generate_transition_magic_v202(const char *transition_key, int op_status)
{
int len = 80;
char *fail_state = NULL;
CRM_CHECK(transition_key != NULL, return NULL);
len += strlen(transition_key);
crm_malloc0(fail_state, len);
if(fail_state != NULL) {
snprintf(fail_state, len, "%d:%s", op_status,transition_key);
}
return fail_state;
}
char *
generate_transition_magic(const char *transition_key, int op_status, int op_rc)
{
int len = 80;
char *fail_state = NULL;
CRM_CHECK(transition_key != NULL, return NULL);
len += strlen(transition_key);
crm_malloc0(fail_state, len);
if(fail_state != NULL) {
snprintf(fail_state, len, "%d:%d;%s",
op_status, op_rc, transition_key);
}
return fail_state;
}
gboolean
decode_transition_magic(
const char *magic, char **uuid, int *transition_id, int *action_id,
int *op_status, int *op_rc)
{
char *rc = NULL;
char *key = NULL;
char *magic2 = NULL;
char *status = NULL;
if(decodeNVpair(magic, ':', &status, &magic2) == FALSE) {
crm_err("Couldn't find ':' in: %s", magic);
return FALSE;
}
if(decodeNVpair(magic2, ';', &rc, &key) == FALSE) {
crm_err("Couldn't find ';' in: %s", magic2);
return FALSE;
}
CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id),
return FALSE);
*op_rc = crm_parse_int(rc, NULL);
*op_status = crm_parse_int(status, NULL);
crm_free(rc);
crm_free(key);
crm_free(magic2);
crm_free(status);
return TRUE;
}
char *
generate_transition_key(int transition_id, int action_id, const char *node)
{
int len = 40;
char *fail_state = NULL;
CRM_CHECK(node != NULL, return NULL);
len += strlen(node);
crm_malloc0(fail_state, len);
if(fail_state != NULL) {
snprintf(fail_state, len, "%d:%d:%s",
action_id, transition_id, node);
}
return fail_state;
}
gboolean
decode_transition_key(
const char *key, char **uuid, int *transition_id, int *action_id)
{
char *tmp = NULL;
char *action = NULL;
char *transition = NULL;
*uuid = NULL;
*action_id = -1;
*transition_id = -1;
if(decodeNVpair(key, ':', &action, &tmp) == FALSE) {
crm_err("Couldn't find ':' in: %s", key);
return FALSE;
}
*action_id = crm_parse_int(action, NULL);
crm_free(action);
if(decodeNVpair(tmp, ':', &transition, uuid) == FALSE) {
/* this would be an error but some versions dont
* have the action
*/
*transition_id = *action_id;
*action_id = -1;
*uuid = tmp;
} else {
*transition_id = crm_parse_int(transition, NULL);
crm_free(transition);
crm_free(tmp);
}
return TRUE;
}
void
filter_action_parameters(crm_data_t *param_set, const char *version)
{
#if CRM_DEPRECATED_SINCE_2_0_5
const char *filter_205[] = {
XML_ATTR_TE_TARGET_RC,
XML_ATTR_LRM_PROBE,
XML_RSC_ATTR_START,
XML_RSC_ATTR_NOTIFY,
XML_RSC_ATTR_UNIQUE,
XML_RSC_ATTR_MANAGED,
XML_RSC_ATTR_PRIORITY,
XML_RSC_ATTR_MULTIPLE,
XML_RSC_ATTR_STICKINESS,
XML_RSC_ATTR_FAIL_STICKINESS,
XML_RSC_ATTR_TARGET_ROLE,
/* ignore clone fields */
XML_RSC_ATTR_INCARNATION,
XML_RSC_ATTR_INCARNATION_MAX,
XML_RSC_ATTR_INCARNATION_NODEMAX,
XML_RSC_ATTR_MASTER_MAX,
XML_RSC_ATTR_MASTER_NODEMAX,
/* old field names */
"role",
"crm_role",
"te-target-rc",
/* ignore notify fields */
"notify_stop_resource",
"notify_stop_uname",
"notify_start_resource",
"notify_start_uname",
"notify_active_resource",
"notify_active_uname",
"notify_inactive_resource",
"notify_inactive_uname",
"notify_promote_resource",
"notify_promote_uname",
"notify_demote_resource",
"notify_demote_uname",
"notify_master_resource",
"notify_master_uname",
"notify_slave_resource",
"notify_slave_uname"
};
#endif
const char *attr_filter[] = {
XML_ATTR_ID,
XML_ATTR_CRM_VERSION,
XML_LRM_ATTR_OP_DIGEST,
};
gboolean do_delete = FALSE;
int lpc = 0;
static int meta_len = 0;
if(meta_len == 0) {
meta_len = strlen(CRM_META);
}
if(param_set == NULL) {
return;
}
#if CRM_DEPRECATED_SINCE_2_0_5
if(version == NULL || compare_version("1.0.5", version)) {
for(lpc = 0; lpc < DIMOF(filter_205); lpc++) {
xml_remove_prop(param_set, filter_205[lpc]);
}
}
#endif
for(lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
xml_remove_prop(param_set, attr_filter[lpc]);
}
xml_prop_iter(param_set, prop_name, prop_value,
do_delete = FALSE;
if(strncasecmp(prop_name, CRM_META, meta_len) == 0) {
do_delete = TRUE;
}
if(do_delete) {
/* remove it */
xml_remove_prop(param_set, prop_name);
/* unwind the counetr */
__counter--;
}
);
}
void
filter_reload_parameters(crm_data_t *param_set, const char *restart_string)
{
int len = 0;
char *name = NULL;
char *match = NULL;
if(param_set == NULL) {
return;
}
xml_prop_iter(param_set, prop_name, prop_value,
name = NULL;
len = strlen(prop_name) + 3;
crm_malloc0(name, len);
sprintf(name, " %s ", prop_name);
name[len-1] = 0;
match = strstr(restart_string, name);
if(match == NULL) {
/* remove it */
crm_debug_3("%s not found in %s",
prop_name, restart_string);
xml_remove_prop(param_set, prop_name);
/* unwind the counetr */
__counter--;
}
crm_free(name);
);
}
-gboolean
-crm_mem_stats(volatile cl_mem_stats_t *mem_stats)
-{
- volatile cl_mem_stats_t *active_stats = mem_stats;
- if(active_stats == NULL) {
- active_stats = cl_malloc_getstats();
- }
- CRM_CHECK(active_stats != NULL, ;);
-#ifndef CRM_USE_MALLOC
- if(active_stats->numalloc > active_stats->numfree) {
- crm_warn("Potential memory leak detected:"
- " %lu alloc's vs. %lu free's (%lu)"
- " (%lu bytes not freed: req=%lu, alloc'd=%lu)",
- active_stats->numalloc, active_stats->numfree,
- active_stats->numalloc - active_stats->numfree,
- active_stats->nbytes_alloc, active_stats->nbytes_req,
- active_stats->mallocbytes);
- return TRUE;
-
- } else if(active_stats->numalloc < active_stats->numfree) {
- crm_debug("Process shrank: %lu alloc's vs. %lu free's (%lu)",
- active_stats->numalloc, active_stats->numfree,
- active_stats->numalloc - active_stats->numfree);
- }
-#endif
- return FALSE;
-}
-
-void
-crm_zero_mem_stats(volatile cl_mem_stats_t *stats)
-{
- if(stats == NULL) {
- crm_debug("Resetting global memory stats");
- stats = cl_malloc_getstats();
- }
- stats->numalloc = 0;
- stats->numfree = 0;
- stats->numrealloc = 0;
- stats->nbytes_req = 0;
- stats->nbytes_alloc = 0;
- stats->mallocbytes = 0;
- stats->arena = 0;
-}
-
-void
-crm_save_mem_stats(const char *location, cl_mem_stats_t *saved_stats)
-{
- volatile cl_mem_stats_t *stats = cl_malloc_getstats();
- if(saved_stats == NULL) {
- return;
- }
- crm_debug_2("Saving memory stats: %s", location);
- *saved_stats = *stats;
-}
-
-void
-crm_xml_nbytes(crm_data_t *xml, long *bytes, long *allocs, long *frees)
-{
- crm_data_t *xml_copy = NULL;
- volatile cl_mem_stats_t *stats = cl_malloc_getstats();
-
- if(xml == NULL) {
- *bytes = 0;
- *allocs = 0;
- *frees = 0;
- return;
- }
-
- *bytes = 0 - stats->nbytes_alloc;
- *allocs = 0 - stats->numalloc;
- *frees = 0 - stats->numfree;
-
- xml_copy = copy_xml(xml);
-
- *bytes += stats->nbytes_alloc;
- *allocs += stats->numalloc;
- *frees += stats->numfree;
-
- crm_debug_3("XML size: %ld bytes, %ld allocs, %ld frees",
- *bytes, *allocs, *frees);
-
- free_xml(xml_copy);
-}
-
-void
-crm_adjust_mem_stats(volatile cl_mem_stats_t *stats, long bytes, long allocs, long frees)
-{
- if(bytes == 0&& allocs == 0 && frees == 0) {
- return;
- }
-
- if(stats == NULL) {
- stats = cl_malloc_getstats();
- }
-
- stats->nbytes_alloc -= bytes;
- stats->numalloc -= allocs;
- stats->numfree -= frees;
-
- crm_debug("Adjusted CIB Memory usage by: %10ld bytes, %5ld allocs, %5ld frees",
- bytes, allocs, frees);
-}
-
-cl_mem_stats_t *crm_running_stats = NULL;
-
-gboolean
-crm_diff_mem_stats(int log_level_up, int log_level_down, const char *location,
- volatile cl_mem_stats_t *stats, volatile cl_mem_stats_t *saved_stats)
-{
- long delta_allocs = 0;
- long delta_frees = 0;
- long delta_bytes = 0;
- long delta_req = 0;
-
- gboolean increase = TRUE;
- gboolean reset_on_change = (log_level_up == LOG_DEBUG);
-
-/* long delta_malloc = stats->mallocbytes - saved_stats->mallocbytes; */
-#ifndef HA_MALLOC_TRACK
- crm_err("Skipping comparision");
- return FALSE;
-#endif
- if(stats == NULL && saved_stats == NULL) {
- crm_err("Comparision doesnt make sense");
- return FALSE;
-
- } else if(stats == NULL) {
- stats = cl_malloc_getstats();
-
- } else if(saved_stats == NULL) {
- saved_stats = cl_malloc_getstats();
- }
-
- delta_allocs = stats->numalloc - saved_stats->numalloc;
- delta_frees = stats->numfree - saved_stats->numfree;
- delta_bytes = stats->nbytes_alloc - saved_stats->nbytes_alloc;
- delta_req = stats->nbytes_req - saved_stats->nbytes_req;
-
- if(delta_bytes == 0) {
- crm_info("Memory usage constant at %s: %ld alloc's %ld free's",
- location, delta_allocs, delta_frees);
- return FALSE;
- }
-
- if(delta_bytes < 0) {
- increase = FALSE;
- reset_on_change = (log_level_down == LOG_DEBUG);
- }
-
- do_crm_log(increase?log_level_up:log_level_down,
- "Memory usage %s detected at %s:\t"
- " %10ld alloc's vs. %10ld free's (%5ld change"
- " %10ld bytes leaked)",
- increase?"increase":"decrease", location,
- delta_allocs, delta_frees, delta_allocs - delta_frees,
- delta_bytes);
-
- if(reset_on_change) {
- crm_info("Resetting %s stats", location);
- *stats = *saved_stats;
- if(crm_running_stats) {
- crm_adjust_mem_stats(crm_running_stats, delta_bytes, delta_allocs, delta_frees);
- }
- }
- return TRUE;
-}
-
void
crm_abort(const char *file, const char *function, int line,
const char *assert_condition, gboolean do_fork)
{
int pid = 0;
if(do_fork == FALSE) {
do_crm_log(LOG_ERR,
"%s: Triggered fatal assert at %s:%d : %s",
function, file, line, assert_condition);
} else if(crm_log_level < LOG_DEBUG) {
do_crm_log(LOG_ERR,
"%s: Triggered non-fatal assert at %s:%d : %s",
function, file, line, assert_condition);
return;
} else {
pid=fork();
}
switch(pid) {
case -1:
crm_err("Cannot fork!");
return;
default: /* Parent */
do_crm_log(LOG_ERR,
"%s: Forked child %d to record non-fatal assert at %s:%d : %s",
function, pid, file, line, assert_condition);
return;
case 0: /* Child */
abort();
break;
}
}
char *
generate_series_filename(
const char *directory, const char *series, int sequence, gboolean bzip)
{
int len = 40;
char *filename = NULL;
const char *ext = "raw";
CRM_CHECK(directory != NULL, return NULL);
CRM_CHECK(series != NULL, return NULL);
len += strlen(directory);
len += strlen(series);
crm_malloc0(filename, len);
CRM_CHECK(filename != NULL, return NULL);
if(bzip) {
ext = "bz2";
}
sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext);
return filename;
}
int
get_last_sequence(const char *directory, const char *series)
{
FILE *file_strm = NULL;
int start = 0, length = 0, read_len = 0;
char *series_file = NULL;
char *buffer = NULL;
int seq = 0;
int len = 36;
CRM_CHECK(directory != NULL, return 0);
CRM_CHECK(series != NULL, return 0);
len += strlen(directory);
len += strlen(series);
crm_malloc0(series_file, len);
CRM_CHECK(series_file != NULL, return 0);
sprintf(series_file, "%s/%s.last", directory, series);
file_strm = fopen(series_file, "r");
if(file_strm == NULL) {
crm_debug("%s does not exist", series_file);
crm_free(series_file);
return 0;
}
/* see how big the file is */
start = ftell(file_strm);
fseek(file_strm, 0L, SEEK_END);
length = ftell(file_strm);
fseek(file_strm, 0L, start);
CRM_ASSERT(start == ftell(file_strm));
crm_debug_3("Reading %d bytes from file", length);
crm_malloc0(buffer, (length+1));
read_len = fread(buffer, 1, length, file_strm);
if(read_len != length) {
crm_err("Calculated and read bytes differ: %d vs. %d",
length, read_len);
crm_free(buffer);
buffer = NULL;
} else if(length <= 0) {
crm_info("%s was not valid", series_file);
crm_free(buffer);
buffer = NULL;
}
crm_free(series_file);
seq = crm_parse_int(buffer, "0");
crm_free(buffer);
fclose(file_strm);
return seq;
}
void
write_last_sequence(
const char *directory, const char *series, int sequence, int max)
{
int rc = 0;
int len = 36;
char *buffer = NULL;
FILE *file_strm = NULL;
char *series_file = NULL;
CRM_CHECK(directory != NULL, return);
CRM_CHECK(series != NULL, return);
if(max == 0) {
return;
}
while(max > 0 && sequence > max) {
sequence -= max;
}
buffer = crm_itoa(sequence);
len += strlen(directory);
len += strlen(series);
crm_malloc0(series_file, len);
CRM_CHECK(series_file != NULL, return);
sprintf(series_file, "%s/%s.last", directory, series);
file_strm = fopen(series_file, "w");
if(file_strm == NULL) {
crm_err("%s does not exist", series_file);
crm_free(series_file);
return;
}
rc = fprintf(file_strm, "%s", buffer);
if(rc < 0) {
cl_perror("Cannot write output to %s", series_file);
}
fflush(file_strm);
fclose(file_strm);
crm_free(series_file);
crm_free(buffer);
}
void
crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
{
long pid;
const char *devnull = "/dev/null";
if(daemonize == FALSE) {
return;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "%s: could not start daemon\n", name);
cl_perror("fork");
exit(LSB_EXIT_GENERIC);
} else if (pid > 0) {
exit(LSB_EXIT_OK);
}
if (cl_lock_pidfile(pidfile) < 0 ) {
pid = cl_read_pidfile_no_checking(pidfile);
crm_warn("%s: already running [pid %ld] (%s).\n",
name, pid, pidfile);
exit(LSB_EXIT_OK);
}
umask(022);
close(FD_STDIN);
(void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
close(FD_STDOUT);
(void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
close(FD_STDERR);
(void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
}
gboolean
crm_is_writable(const char *dir, const char *file,
const char *user, const char *group, gboolean need_both)
{
int s_res = -1;
struct stat buf;
char *full_file = NULL;
const char *target = NULL;
gboolean pass = TRUE;
gboolean readwritable = FALSE;
CRM_ASSERT(dir != NULL);
if(file != NULL) {
full_file = crm_concat(dir, file, '/');
target = full_file;
s_res = stat(full_file, &buf);
if( s_res == 0 && S_ISREG(buf.st_mode) == FALSE ) {
crm_err("%s must be a regular file", target);
pass = FALSE;
goto out;
}
}
if (s_res != 0) {
target = dir;
s_res = stat(dir, &buf);
if(s_res != 0) {
crm_err("%s must exist and be a directory", dir);
pass = FALSE;
goto out;
} else if( S_ISDIR(buf.st_mode) == FALSE ) {
crm_err("%s must be a directory", dir);
pass = FALSE;
}
}
if(user) {
struct passwd *sys_user = NULL;
sys_user = getpwnam(user);
readwritable = (sys_user != NULL
&& buf.st_uid == sys_user->pw_uid
&& (buf.st_mode & (S_IRUSR|S_IWUSR)));
if(readwritable == FALSE) {
crm_err("%s must be owned and r/w by user %s",
target, user);
if(need_both) {
pass = FALSE;
}
}
}
if(group) {
struct group *sys_grp = getgrnam(group);
readwritable = (
sys_grp != NULL
&& buf.st_gid == sys_grp->gr_gid
&& (buf.st_mode & (S_IRGRP|S_IWGRP)));
if(readwritable == FALSE) {
if(need_both || user == NULL) {
pass = FALSE;
crm_err("%s must be owned and r/w by group %s",
target, group);
} else {
crm_warn("%s should be owned and r/w by group %s",
target, group);
}
}
}
out:
crm_free(full_file);
return pass;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 2:11 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009704
Default Alt Text
(176 KB)

Event Timeline