22 #include <sys/types.h> 31 #define CIB_SERIES "cib" 32 #define CIB_SERIES_MAX 100 33 #define CIB_SERIES_BZIP FALSE 37 #define CIB_LIVE_NAME CIB_SERIES ".xml" 40 static GHashTable *client_table = NULL;
47 typedef struct cib_file_opaque_s {
54 static int cib_file_process_commit_transaction(
const char *op,
int options,
56 xmlNode *req, xmlNode *
input,
57 xmlNode *existing_cib,
68 register_client(
const cib_t *cib)
72 if (client_table == NULL) {
75 g_hash_table_insert(client_table, private->id, (gpointer) cib);
85 unregister_client(
const cib_t *cib)
89 if (client_table == NULL) {
93 g_hash_table_remove(client_table, private->id);
98 if (g_hash_table_size(client_table) == 0) {
99 g_hash_table_destroy(client_table);
113 get_client(
const char *client_id)
115 if (client_table == NULL) {
118 return g_hash_table_lookup(client_table, (gpointer) client_id);
138 static uid_t cib_file_owner = 0;
139 static uid_t cib_file_group = 0;
140 static gboolean cib_do_chown = FALSE;
142 #define cib_set_file_flags(cibfile, flags_to_set) do { \ 143 (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \ 144 LOG_TRACE, "CIB file", \ 151 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \ 152 (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ 153 LOG_TRACE, "CIB file", \ 178 return cib_op_functions[
type];
190 cib_file_is_live(
const char *filename)
192 gboolean same = FALSE;
194 if (filename != NULL) {
196 char *real_filename = NULL;
199 char *real_livename = NULL;
203 same = !strcmp(real_filename, real_livename);
213 cib_file_process_request(
cib_t *cib, xmlNode *request, xmlNode **output)
227 bool changed =
false;
228 bool read_only =
false;
229 xmlNode *result_cib = NULL;
230 xmlNode *cib_diff = NULL;
236 op_function = file_get_op_function(operation);
253 rc =
cib_perform_op(cib, op, call_options, op_function, read_only, section,
254 request,
data,
true, &changed, &private->cib_xml,
255 &result_cib, &cib_diff, output);
268 }
else if ((rc ==
pcmk_ok) && !read_only) {
271 if (result_cib != private->cib_xml) {
273 private->cib_xml = result_cib;
284 if ((result_cib != private->cib_xml) && (result_cib != *output)) {
292 cib_file_perform_op_delegate(
cib_t *cib,
const char *op,
const char *
host,
293 const char *section, xmlNode *
data,
294 xmlNode **output_data,
int call_options,
295 const char *user_name)
298 xmlNode *request = NULL;
299 xmlNode *output = NULL;
304 crm_info(
"Handling %s operation for %s as %s",
305 pcmk__s(op,
"invalid"), pcmk__s(section,
"entire CIB"),
306 pcmk__s(user_name,
"default user"));
308 if (output_data != NULL) {
320 return -EPROTONOSUPPORT;
323 if (file_get_op_function(operation) == NULL) {
325 crm_err(
"Operation %s is not supported by CIB file clients", op);
326 return -EPROTONOSUPPORT;
344 rc = cib_file_process_request(cib, request, &output);
346 if ((output_data != NULL) && (output != NULL)) {
347 if (output->doc == private->cib_xml->doc) {
350 *output_data = output;
356 && (output->doc != private->cib_xml->doc)
357 && ((output_data == NULL) || (output != *output_data))) {
381 load_file_cib(
const char *filename, xmlNode **output)
384 xmlNode *root = NULL;
387 if (strcmp(filename,
"-") && (stat(filename, &buf) < 0)) {
406 crm_err(
"CIB does not validate against %s, or that schema is unknown", schema);
422 if (private->filename == NULL) {
425 rc = load_file_cib(private->filename, &private->cib_xml);
429 crm_debug(
"Opened connection to local file '%s' for %s",
430 private->filename,
name);
433 register_client(cib);
436 crm_info(
"Connection to local file '%s' for %s (client %s) failed: %s",
452 cib_file_write_live(xmlNode *cib_root,
char *
path)
454 uid_t uid = geteuid();
455 struct passwd *daemon_pwent;
456 char *sep = strrchr(
path,
'/');
457 const char *cib_dirname, *cib_filename;
463 if (daemon_pwent == NULL) {
472 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
473 crm_perror(LOG_ERR,
"Must be root or %s to modify live CIB",
485 }
else if (sep ==
path) {
487 cib_filename =
path + 1;
491 cib_filename = sep + 1;
496 cib_file_owner = daemon_pwent->pw_uid;
497 cib_file_group = daemon_pwent->pw_gid;
509 cib_do_chown = FALSE;
513 if ((sep != NULL) && (*sep ==
'\0')) {
534 cib_file_signoff(
cib_t *cib)
539 crm_debug(
"Disconnecting from the CIB manager");
542 unregister_client(cib);
550 if (cib_file_write_live(private->cib_xml, private->filename) < 0) {
565 crm_info(
"Wrote CIB to %s", private->filename);
568 crm_err(
"Could not write CIB to %s", private->filename);
574 private->cib_xml = NULL;
579 cib_file_free(
cib_t *cib)
584 rc = cib_file_signoff(cib);
591 free(private->filename);
598 fprintf(stderr,
"Couldn't sign off: %d\n", rc);
605 cib_file_inputfd(
cib_t *cib)
607 return -EPROTONOSUPPORT;
611 cib_file_register_notification(
cib_t *cib,
const char *callback,
int enabled)
613 return -EPROTONOSUPPORT;
617 cib_file_set_connection_dnotify(
cib_t *cib,
618 void (*dnotify) (gpointer user_data))
620 return -EPROTONOSUPPORT;
637 cib_file_client_id(
const cib_t *cib,
const char **async_id,
638 const char **sync_id)
642 if (async_id != NULL) {
643 *async_id =
private->id;
645 if (sync_id != NULL) {
646 *sync_id =
private->id;
656 char *filename = NULL;
658 if (cib_location == NULL) {
659 cib_location = getenv(
"CIB_file");
660 if (cib_location == NULL) {
670 filename = strdup(cib_location);
671 if (filename == NULL) {
677 if (
private == NULL) {
684 private->filename = filename;
690 if (cib_file_is_live(cib_location)) {
692 crm_trace(
"File %s detected as live CIB", cib_location);
720 cib_file_verify_digest(xmlNode *root,
const char *sigfile)
722 gboolean passed = FALSE;
728 if (expected == NULL) {
729 crm_err(
"On-disk digest at %s is empty", sigfile);
734 crm_warn(
"No on-disk digest present at %s", sigfile);
737 crm_err(
"Could not read on-disk digest from %s: %s",
766 char *local_sigfile = NULL;
767 xmlNode *local_root = NULL;
775 s_res = stat(filename, &buf);
777 crm_perror(LOG_WARNING,
"Could not verify cluster configuration file %s", filename);
779 }
else if (buf.st_size == 0) {
780 crm_warn(
"Cluster configuration file %s is corrupt (size is zero)", filename);
786 if (local_root == NULL) {
787 crm_warn(
"Cluster configuration file %s is corrupt (unparseable as XML)", filename);
792 if (sigfile == NULL) {
797 if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
822 cib_file_backup(
const char *cib_dirname,
const char *cib_filename)
825 unsigned int seq = 0U;
843 unlink(backup_digest);
846 if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
847 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
848 cib_path, backup_path);
852 }
else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
853 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
854 cib_digest, backup_digest);
864 if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
865 && (errno != ENOENT)) {
866 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_path);
869 if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
870 && (errno != ENOENT)) {
871 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_digest);
875 cib_file_owner, cib_file_group);
877 crm_err(
"Could not set owner of sequence file in %s: %s",
883 crm_info(
"Archived previous version as %s", backup_path);
905 cib_file_prepare_xml(xmlNode *root)
907 xmlNode *cib_status_root = NULL;
916 CRM_CHECK(cib_status_root != NULL,
return);
935 const char *cib_filename)
954 crm_trace(
"Reading cluster configuration file %s", cib_path);
956 if ((rc !=
pcmk_ok) && (rc != -ENOENT)) {
957 crm_err(
"%s was manually modified while the cluster was active!",
964 if (cib_file_backup(cib_dirname, cib_filename) < 0) {
970 umask(S_IWGRP | S_IWOTH | S_IROTH);
971 cib_file_prepare_xml(cib_root);
974 fd = mkstemp(tmp_cib);
976 crm_perror(LOG_ERR,
"Couldn't open temporary file %s for writing CIB",
983 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
984 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
989 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
990 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
998 crm_err(
"Changes couldn't be written to %s", tmp_cib);
1006 crm_info(
"Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
1007 (admin_epoch ? admin_epoch :
"0"), (epoch ? epoch :
"0"), digest);
1010 fd = mkstemp(tmp_digest);
1012 crm_perror(LOG_ERR,
"Could not create temporary file for CIB digest");
1016 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
1017 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
1025 crm_err(
"Could not write digest to %s: %s",
1032 crm_debug(
"Wrote digest %s to disk", digest);
1035 crm_info(
"Reading cluster configuration file %s (digest: %s)",
1036 tmp_cib, tmp_digest);
1042 if (rename(tmp_cib, cib_path) < 0) {
1043 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_cib, cib_path);
1046 if (rename(tmp_digest, digest_path) < 0) {
1047 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_digest,
1074 cib_file_process_transaction_requests(
cib_t *cib, xmlNode *transaction)
1083 xmlNode *output = NULL;
1086 int rc = cib_file_process_request(cib, request, &output);
1090 crm_err(
"Aborting transaction for CIB file client (%s) on file " 1091 "'%s' due to failed %s request: %s",
1092 private->id, private->filename, op,
pcmk_rc_str(rc));
1097 crm_trace(
"Applied %s request to transaction working CIB for CIB file " 1098 "client (%s) on file '%s'",
1099 op, private->id, private->filename);
1121 cib_file_commit_transaction(
cib_t *cib, xmlNode *transaction,
1122 xmlNode **result_cib)
1126 xmlNode *saved_cib =
private->cib_xml;
1138 CRM_CHECK((*result_cib != NULL) && (*result_cib != private->cib_xml),
1141 crm_trace(
"Committing transaction for CIB file client (%s) on file '%s' to " 1143 private->id, private->filename);
1146 private->cib_xml = *result_cib;
1148 rc = cib_file_process_transaction_requests(cib, transaction);
1150 crm_trace(
"Transaction commit %s for CIB file client (%s) on file '%s'",
1151 ((rc ==
pcmk_rc_ok)?
"succeeded" :
"failed"),
1152 private->id, private->filename);
1160 *result_cib =
private->cib_xml;
1163 private->cib_xml = saved_cib;
1169 cib_file_process_commit_transaction(
const char *op,
int options,
1170 const char *section, xmlNode *req,
1171 xmlNode *
input, xmlNode *existing_cib,
1172 xmlNode **result_cib, xmlNode **answer)
1178 CRM_CHECK(client_id != NULL,
return -EINVAL);
1180 cib = get_client(client_id);
1183 rc = cib_file_commit_transaction(cib,
input, result_cib);
1187 crm_err(
"Could not commit transaction for CIB file client (%s) on "
#define CRM_CHECK(expr, failure_action)
#define pcmk_err_schema_validation
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
const char * pcmk_strerror(int rc)
char * crm_generate_uuid(void)
int pcmk_rc2legacy(int rc)
int cib_process_delete(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
const char * pcmk__xe_add_last_written(xmlNode *xe)
#define PCMK__XA_CIB_CLIENTID
int cib_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
void pcmk__write_series_sequence(const char *directory, const char *series, unsigned int sequence, int max)
int(* signoff)(cib_t *cib)
#define PCMK__XE_CIB_COMMAND
int pcmk__chown_series_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
#define PCMK_XA_NUM_UPDATES
int cib_process_erase(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int cib_process_bump(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
int(* inputfd)(cib_t *cib)
enum crm_ais_msg_types type
int pcmk__write_sync(int fd, const char *contents)
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
#define PCMK__XA_CIB_SECTION
struct cib_file_opaque_s cib_file_opaque_t
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
#define pcmk_err_cib_backup
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
cib_t * cib_new_variant(void)
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
#define crm_warn(fmt, args...)
#define pcmk_err_cib_save
cib_api_operations_t * cmds
#define crm_debug(fmt, args...)
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
#define PCMK__XA_CIB_CALLOPT
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
#define crm_trace(fmt, args...)
bool pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidityErrorFunc error_handler, void *error_handler_context)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
#define PCMK__XE_CIB_CALLDATA
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
void pcmk__sync_directory(const char *name)
Wrappers for and extensions to libxml2.
int pcmk_legacy2rc(int legacy_rc)
#define pcmk_err_cib_modified
char * pcmk__series_filename(const char *directory, const char *series, unsigned int sequence, bool bzip)
void free_xml(xmlNode *child)
int cib__create_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name, const char *client_name, xmlNode **op_msg)
#define cib_clear_file_flags(cibfile, flags_to_clear)
#define PCMK_XA_VALIDATE_WITH
int pcmk__xml_write_file(const xmlNode *xml, const char *filename, bool compress, unsigned int *nbytes)
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
xmlNode * pcmk__xml_read(const char *filename)
#define pcmk__assert(expr)
int(* cib__op_fn_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
int cib_process_query(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
#define cib_set_file_flags(cibfile, flags_to_set)
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
int pcmk__file_contents(const char *filename, char **contents)
#define cib__set_call_options(cib_call_opts, call_for, flags_to_set)
#define PCMK_XE_ACL_TARGET
cib_t * cib_file_new(const char *cib_location)
int(* end_transaction)(cib_t *cib, bool commit, int call_options)
End and optionally commit this client's CIB transaction.
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define crm_err(fmt, args...)
int cib__extend_transaction(cib_t *cib, xmlNode *request)
#define crm_log_xml_info(xml, text)
uint32_t flags
Group of enum cib__op_attr flags.
IPC interface to Pacemaker daemons.
bool pcmk__verify_digest(xmlNode *input, const char *expected)
#define pcmk__log_xml_patchset(level, patchset)
#define crm_log_xml_trace(xml, text)
int pcmk__xe_get_flags(const xmlNode *xml, const char *name, uint32_t *dest, uint32_t default_value)
Retrieve a flag group from an XML attribute value.
bool pcmk__configured_schema_validates(xmlNode *xml)
int pcmk__real_path(const char *path, char **resolved_path)
int cib__get_operation(const char *op, const cib__operation_t **operation)
int pcmk__xml_write_fd(const xmlNode *xml, const char *filename, int fd, bool compress, unsigned int *nbytes)
#define PCMK_XA_ADMIN_EPOCH
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
#define PCMK__XE_CIB_TRANSACTION
xmlNode * pcmk__xe_next_same(const xmlNode *node)
int(* client_id)(const cib_t *cib, const char **async_id, const char **sync_id)
Get the given CIB connection's unique client identifier(s)
#define pcmk_err_cib_corrupt
#define PCMK__XA_CIB_CALLID
int cib_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
#define crm_info(fmt, args...)
Process request when the client commits the active transaction.
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
bool pcmk__ends_with_ext(const char *s, const char *match)
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, cib__op_fn_t fn, bool is_query, const char *section, xmlNode *req, xmlNode *input, bool manage_counters, bool *config_changed, xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)