22 #include <sys/types.h> 32 #define CIB_SERIES "cib" 33 #define CIB_SERIES_MAX 100 34 #define CIB_SERIES_BZIP FALSE 38 #define CIB_LIVE_NAME CIB_SERIES ".xml" 45 typedef struct cib_file_opaque_s {
50 struct cib_func_entry {
56 static struct cib_func_entry cib_file_ops[] = {
68 static xmlNode *in_mem_cib = NULL;
74 static uid_t cib_file_owner = 0;
75 static uid_t cib_file_group = 0;
76 static gboolean cib_do_chown = FALSE;
78 #define cib_set_file_flags(cibfile, flags_to_set) do { \ 79 (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \ 80 LOG_TRACE, "CIB file", \ 87 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \ 88 (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ 89 LOG_TRACE, "CIB file", \ 105 cib_file_is_live(
const char *filename)
107 gboolean same = FALSE;
109 if (filename != NULL) {
111 char *real_filename = NULL;
114 char *real_livename = NULL;
118 same = !strcmp(real_filename, real_livename);
128 cib_file_perform_op_delegate(
cib_t *cib,
const char *op,
const char *
host,
129 const char *section, xmlNode *
data,
130 xmlNode **output_data,
int call_options,
131 const char *user_name)
134 char *effective_user = NULL;
135 gboolean query = FALSE;
136 gboolean changed = FALSE;
137 xmlNode *request = NULL;
138 xmlNode *output = NULL;
139 xmlNode *cib_diff = NULL;
140 xmlNode *result_cib = NULL;
143 static int max_msg_types =
PCMK__NELEM(cib_file_ops);
146 crm_info(
"Handling %s operation for %s as %s",
147 (op? op :
"invalid"), (section? section :
"entire CIB"),
148 (user_name? user_name :
"default user"));
157 if (output_data != NULL) {
165 for (lpc = 0; lpc < max_msg_types; lpc++) {
167 fn = &(cib_file_ops[lpc].fn);
168 query = cib_file_ops[lpc].read_only;
174 return -EPROTONOSUPPORT;
190 section, request,
data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
201 }
else if (query == FALSE) {
208 rc = out->
message(out,
"xml-patchset", cib_diff);
214 in_mem_cib = result_cib;
222 if ((output_data != NULL) && (output != NULL)) {
223 *output_data = (output == in_mem_cib)?
copy_xml(output) : output;
229 if ((output_data == NULL) && (output != in_mem_cib)) {
235 free(effective_user);
254 load_file_cib(
const char *filename)
257 xmlNode *root = NULL;
260 if (strcmp(filename,
"-") && (stat(filename, &buf) < 0)) {
279 crm_err(
"CIB does not validate against %s", schema);
295 if (private->filename == NULL) {
298 rc = load_file_cib(private->filename);
302 crm_debug(
"Opened connection to local file '%s' for %s",
303 private->filename,
name);
308 crm_info(
"Connection to local file '%s' for %s failed: %s\n",
323 cib_file_write_live(
char *
path)
325 uid_t uid = geteuid();
326 struct passwd *daemon_pwent;
327 char *sep = strrchr(
path,
'/');
328 const char *cib_dirname, *cib_filename;
334 if (daemon_pwent == NULL) {
343 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
344 crm_perror(LOG_ERR,
"Must be root or %s to modify live CIB",
356 }
else if (sep ==
path) {
358 cib_filename =
path + 1;
362 cib_filename = sep + 1;
367 cib_file_owner = daemon_pwent->pw_uid;
368 cib_file_group = daemon_pwent->pw_gid;
380 cib_do_chown = FALSE;
384 if ((sep != NULL) && (*sep ==
'\0')) {
405 cib_file_signoff(
cib_t *cib)
410 crm_debug(
"Disconnecting from the CIB manager");
419 if (cib_file_write_live(private->filename) < 0) {
427 if (
write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
433 crm_info(
"Wrote CIB to %s", private->filename);
436 crm_err(
"Could not write CIB to %s", private->filename);
447 cib_file_free(
cib_t *cib)
452 rc = cib_file_signoff(cib);
458 free(private->filename);
464 fprintf(stderr,
"Couldn't sign off: %d\n", rc);
471 cib_file_inputfd(
cib_t *cib)
473 return -EPROTONOSUPPORT;
477 cib_file_register_notification(
cib_t *cib,
const char *callback,
int enabled)
479 return -EPROTONOSUPPORT;
483 cib_file_set_connection_dnotify(
cib_t *cib,
484 void (*dnotify) (gpointer user_data))
486 return -EPROTONOSUPPORT;
505 cib_file_client_id(
const cib_t *cib,
const char **async_id,
506 const char **sync_id)
508 if (async_id != NULL) {
511 if (sync_id != NULL) {
514 return -EPROTONOSUPPORT;
529 if (
private == NULL) {
537 if (cib_location == NULL) {
538 cib_location = getenv(
"CIB_file");
539 CRM_CHECK(cib_location != NULL,
return NULL);
542 if (cib_file_is_live(cib_location)) {
544 crm_trace(
"File %s detected as live CIB", cib_location);
546 private->filename = strdup(cib_location);
573 cib_file_verify_digest(xmlNode *root,
const char *sigfile)
575 gboolean passed = FALSE;
581 if (expected == NULL) {
582 crm_err(
"On-disk digest at %s is empty", sigfile);
587 crm_warn(
"No on-disk digest present at %s", sigfile);
590 crm_err(
"Could not read on-disk digest from %s: %s",
619 char *local_sigfile = NULL;
620 xmlNode *local_root = NULL;
628 s_res = stat(filename, &buf);
630 crm_perror(LOG_WARNING,
"Could not verify cluster configuration file %s", filename);
632 }
else if (buf.st_size == 0) {
633 crm_warn(
"Cluster configuration file %s is corrupt (size is zero)", filename);
639 if (local_root == NULL) {
640 crm_warn(
"Cluster configuration file %s is corrupt (unparseable as XML)", filename);
645 if (sigfile == NULL) {
650 if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
675 cib_file_backup(
const char *cib_dirname,
const char *cib_filename)
696 unlink(backup_digest);
699 if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
700 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
701 cib_path, backup_path);
705 }
else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
706 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
707 cib_digest, backup_digest);
717 if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
718 && (errno != ENOENT)) {
719 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_path);
722 if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
723 && (errno != ENOENT)) {
724 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_digest);
728 cib_file_owner, cib_file_group);
730 crm_err(
"Could not set owner of sequence file in %s: %s",
736 crm_info(
"Archived previous version as %s", backup_path);
758 cib_file_prepare_xml(xmlNode *root)
760 xmlNode *cib_status_root = NULL;
770 if (cib_status_root != NULL) {
790 const char *cib_filename)
809 CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
810 && (tmp_cib != NULL) && (tmp_digest != NULL));
813 crm_trace(
"Reading cluster configuration file %s", cib_path);
815 if ((rc !=
pcmk_ok) && (rc != -ENOENT)) {
816 crm_err(
"%s was manually modified while the cluster was active!",
823 if (cib_file_backup(cib_dirname, cib_filename) < 0) {
829 umask(S_IWGRP | S_IWOTH | S_IROTH);
830 cib_file_prepare_xml(cib_root);
833 fd = mkstemp(tmp_cib);
835 crm_perror(LOG_ERR,
"Couldn't open temporary file %s for writing CIB",
842 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
843 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
848 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
849 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
857 crm_err(
"Changes couldn't be written to %s", tmp_cib);
865 crm_info(
"Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
866 (admin_epoch ? admin_epoch :
"0"), (epoch ? epoch :
"0"), digest);
869 fd = mkstemp(tmp_digest);
871 crm_perror(LOG_ERR,
"Could not create temporary file for CIB digest");
875 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
876 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
884 crm_err(
"Could not write digest to %s: %s",
891 crm_debug(
"Wrote digest %s to disk", digest);
894 crm_info(
"Reading cluster configuration file %s (digest: %s)",
895 tmp_cib, tmp_digest);
901 if (rename(tmp_cib, cib_path) < 0) {
902 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_cib, cib_path);
905 if (rename(tmp_digest, digest_path) < 0) {
906 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_digest,
#define CRM_CHECK(expr, failure_action)
#define pcmk_err_schema_validation
const char * pcmk_strerror(int rc)
#define XML_ATTR_NUMUPDATES
int pcmk_rc2legacy(int rc)
#define PCMK__CIB_REQUEST_CREATE
int(* message)(pcmk__output_t *out, const char *message_id,...)
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)
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__CIB_REQUEST_QUERY
int pcmk__chown_series_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
int cib_process_erase(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
bool pcmk__verify_digest(xmlNode *input, const char *expected)
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 write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
#define CRM_LOG_ASSERT(expr)
char * pcmk__series_filename(const char *directory, const char *series, int sequence, bool bzip)
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)
xmlNode * filename2xml(const char *filename)
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
void pcmk__output_set_log_level(pcmk__output_t *out, uint8_t log_level)
#define XML_ATTR_GENERATION
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
#define PCMK__CIB_REQUEST_ERASE
gboolean validate_xml_verbose(xmlNode *xml_blob)
xmlNode * copy_xml(xmlNode *src_node)
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)
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_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
#define crm_trace(fmt, args...)
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.
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.
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
#define XML_ATTR_VALIDATION
#define pcmk_err_cib_modified
void free_xml(xmlNode *child)
#define cib_clear_file_flags(cibfile, flags_to_clear)
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.
void pcmk__output_free(pcmk__output_t *out)
#define PCMK__CIB_REQUEST_UPGRADE
#define PCMK__CIB_REQUEST_BUMP
xmlNode * cib_create_op(int call_id, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
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)
cib_t * cib_file_new(const char *cib_location)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define crm_err(fmt, args...)
#define PCMK__CIB_REQUEST_REPLACE
This structure contains everything that makes up a single output formatter.
int cib_perform_op(const char *op, int call_options, cib_op_t *fn, gboolean is_query, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, xmlNode *current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
#define XML_ATTR_GENERATION_ADMIN
IPC interface to Pacemaker daemons.
#define XML_CIB_TAG_STATUS
#define PCMK__CIB_REQUEST_MODIFY
int pcmk__real_path(const char *path, char **resolved_path)
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
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
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...)
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
#define PCMK__CIB_REQUEST_APPLY_PATCH
bool pcmk__ends_with_ext(const char *s, const char *match)
int pcmk__log_output_new(pcmk__output_t **out)
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
#define PCMK__CIB_REQUEST_DELETE