29 #include <sys/types.h>
38 #define cib_flag_dirty 0x00001
39 #define cib_flag_live 0x00002
41 typedef struct cib_file_opaque_s {
48 xmlNode *
data, xmlNode ** output_data,
int call_options);
51 xmlNode *
data, xmlNode ** output_data,
int call_options,
52 const char *user_name);
59 cib_file_inputfd(
cib_t * cib)
61 return -EPROTONOSUPPORT;
65 cib_file_set_connection_dnotify(
cib_t * cib,
void (*dnotify) (gpointer user_data))
67 return -EPROTONOSUPPORT;
71 cib_file_register_notification(
cib_t * cib,
const char *callback,
int enabled)
73 return -EPROTONOSUPPORT;
86 cib_file_verify_digest(xmlNode *root,
const char *sigfile)
88 gboolean passed = FALSE;
91 if (expected == NULL) {
94 crm_err(
"On-disk digest at %s is empty", sigfile);
97 crm_warn(
"No on-disk digest present at %s", sigfile);
100 crm_perror(LOG_ERR,
"Could not read on-disk digest from %s", sigfile);
129 char *local_sigfile = NULL;
130 xmlNode *local_root = NULL;
138 s_res = stat(filename, &buf);
140 crm_perror(LOG_WARNING,
"Could not verify cluster configuration file %s", filename);
142 }
else if (buf.st_size == 0) {
143 crm_warn(
"Cluster configuration file %s is corrupt (size is zero)", filename);
149 if (local_root == NULL) {
150 crm_warn(
"Cluster configuration file %s is corrupt (unparseable as XML)", filename);
155 if (sigfile == NULL) {
156 sigfile = local_sigfile =
crm_concat(filename,
"sig",
'.');
160 if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
175 #define CIB_SERIES "cib"
176 #define CIB_SERIES_MAX 100
177 #define CIB_SERIES_BZIP FALSE
181 #define CIB_LIVE_NAME CIB_SERIES ".xml"
192 cib_file_is_live(
const char *filename)
194 if (filename != NULL) {
198 if (real_filename != NULL) {
199 const char *livenames[] = {
207 for (i = 0; i <
DIMOF(livenames); ++i) {
209 if (real_livename && !strcmp(real_filename, real_livename)) {
225 static uid_t cib_file_owner = 0;
226 static uid_t cib_file_group = 0;
227 static gboolean cib_do_chown = FALSE;
239 cib_file_backup(
const char *cib_dirname,
const char *cib_filename)
242 char *cib_path =
crm_concat(cib_dirname, cib_filename,
'/');
243 char *cib_digest =
crm_concat(cib_path,
"sig",
'.');
249 char *backup_digest =
crm_concat(backup_path,
"sig",
'.');
251 CRM_ASSERT((cib_path != NULL) && (cib_digest != NULL)
252 && (backup_path != NULL) && (backup_digest != NULL));
256 unlink(backup_digest);
259 if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
260 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
261 cib_path, backup_path);
265 }
else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
266 crm_perror(LOG_ERR,
"Could not archive %s by linking to %s",
267 cib_digest, backup_digest);
274 if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
275 && (errno != ENOENT)) {
276 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_path);
279 if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
280 && (errno != ENOENT)) {
281 crm_perror(LOG_ERR,
"Could not set owner of %s", backup_digest);
285 cib_file_group) < 0) {
287 "Could not set owner of %s last sequence file",
293 crm_info(
"Archived previous version as %s", backup_path);
315 cib_file_prepare_xml(xmlNode *root)
317 xmlNode *cib_status_root = NULL;
327 if (cib_status_root != NULL) {
347 const char *cib_filename)
359 char *cib_path =
crm_concat(cib_dirname, cib_filename,
'/');
360 char *digest_path =
crm_concat(cib_path,
"sig",
'.');
366 CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
367 && (tmp_cib != NULL) && (tmp_digest != NULL));
370 crm_trace(
"Reading cluster configuration file %s", cib_path);
372 if ((rc !=
pcmk_ok) && (rc != -ENOENT)) {
373 crm_err(
"%s was manually modified while the cluster was active!",
380 if (cib_file_backup(cib_dirname, cib_filename) < 0) {
386 umask(S_IWGRP | S_IWOTH | S_IROTH);
387 cib_file_prepare_xml(cib_root);
390 fd = mkstemp(tmp_cib);
392 crm_perror(LOG_ERR,
"Couldn't open temporary file %s for writing CIB",
399 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
400 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
405 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
406 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
414 crm_err(
"Changes couldn't be written to %s", tmp_cib);
422 crm_info(
"Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
423 (admin_epoch ? admin_epoch :
"0"), (epoch ? epoch :
"0"), digest);
426 fd = mkstemp(tmp_digest);
428 crm_perror(LOG_ERR,
"Could not create temporary file for CIB digest");
432 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
433 crm_perror(LOG_ERR,
"Couldn't protect temporary file %s for writing CIB",
440 crm_perror(LOG_ERR,
"Could not write digest to file %s", tmp_digest);
446 crm_debug(
"Wrote digest %s to disk", digest);
449 crm_info(
"Reading cluster configuration file %s (digest: %s)",
450 tmp_cib, tmp_digest);
456 if (rename(tmp_cib, cib_path) < 0) {
457 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_cib, cib_path);
460 if (rename(tmp_digest, digest_path) < 0) {
461 crm_perror(LOG_ERR,
"Couldn't rename %s as %s", tmp_digest,
483 CRM_ASSERT((cib != NULL) && (
private != NULL));
488 if (cib_location == NULL) {
489 cib_location = getenv(
"CIB_file");
492 if (cib_file_is_live(cib_location)) {
494 crm_trace(
"File %s detected as live CIB", cib_location);
496 private->filename = strdup(cib_location);
511 static xmlNode *in_mem_cib = NULL;
528 load_file_cib(
const char *filename)
531 xmlNode *root = NULL;
532 const char *ignore_dtd = NULL;
535 if (stat(filename, &buf) < 0) {
553 crm_err(
"CIB does not validate against %s", ignore_dtd);
569 if (private->filename == NULL) {
572 rc = load_file_cib(private->filename);
576 crm_debug(
"%s: Opened connection to local file '%s'", name, private->filename);
581 fprintf(stderr,
"%s: Connection to local file '%s' failed: %s\n",
597 cib_file_write_live(
char *path)
599 uid_t uid = geteuid();
600 struct passwd *daemon_pwent;
601 char *sep = strrchr(path,
'/');
602 const char *cib_dirname, *cib_filename;
608 if (daemon_pwent == NULL) {
617 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
618 crm_perror(LOG_ERR,
"Must be root or %s to modify live CIB",
630 }
else if (sep == path) {
632 cib_filename = path + 1;
636 cib_filename = sep + 1;
641 cib_file_owner = daemon_pwent->pw_uid;
642 cib_file_group = daemon_pwent->pw_gid;
654 cib_do_chown = FALSE;
658 if ((sep != NULL) && (*sep ==
'\0')) {
684 crm_debug(
"Signing out of the CIB Service");
693 if (cib_file_write_live(private->filename) < 0) {
701 if (
write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
707 crm_info(
"Wrote CIB to %s", private->filename);
710 crm_err(
"Could not write CIB to %s", private->filename);
732 free(private->filename);
738 fprintf(stderr,
"Couldn't sign off: %d\n", rc);
744 struct cib_func_entry {
751 static struct cib_func_entry cib_file_ops[] = {
766 xmlNode *
data, xmlNode ** output_data,
int call_options)
774 xmlNode *
data, xmlNode ** output_data,
int call_options,
775 const char *user_name)
778 char *effective_user = NULL;
779 gboolean query = FALSE;
780 gboolean changed = FALSE;
781 xmlNode *request = NULL;
782 xmlNode *output = NULL;
783 xmlNode *cib_diff = NULL;
784 xmlNode *result_cib = NULL;
787 static int max_msg_types =
DIMOF(cib_file_ops);
797 if (output_data != NULL) {
805 for (lpc = 0; lpc < max_msg_types; lpc++) {
807 fn = &(cib_file_ops[lpc].fn);
808 query = cib_file_ops[lpc].read_only;
814 return -EPROTONOSUPPORT;
818 request =
cib_create_op(cib->
call_id,
"dummy-token", op, host, section, data, call_options, user_name);
823 crm_trace(
"Performing %s operation as %s", op, user_name);
832 section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
843 }
else if (query == FALSE) {
846 in_mem_cib = result_cib;
856 if (output_data && output) {
857 if(output == in_mem_cib) {
860 *output_data = output;
863 }
else if(output != in_mem_cib) {
867 free(effective_user);
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
char * crm_compat_realpath(const char *path)
#define XML_ATTR_NUMUPDATES
#define CRM_LEGACY_CONFIG_DIR
int get_last_sequence(const char *directory, const char *series)
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_strerror(int rc)
int cib_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
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_file_perform_op_delegate(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options, const char *user_name)
int cib_process_bump(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int(* inputfd)(cib_t *cib)
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
gboolean crm_digest_verify(xmlNode *input, const char *expected)
#define CRM_LOG_ASSERT(expr)
#define clear_bit(word, bit)
xmlNode * filename2xml(const char *filename)
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
struct cib_file_opaque_s cib_file_opaque_t
char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
#define XML_ATTR_GENERATION
char * crm_read_contents(const char *filename)
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
gboolean validate_xml_verbose(xmlNode *xml_blob)
xmlNode * cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
int cib_file_perform_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options)
xmlNode * copy_xml(xmlNode *src_node)
cib_t * cib_new_variant(void)
#define crm_warn(fmt, args...)
#define set_bit(word, bit)
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 CIB_OP_APPLY_DIFF
int cib_file_signoff(cib_t *cib)
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
#define pcmk_err_schema_validation
#define crm_trace(fmt, args...)
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
#define pcmk_err_cib_save
Wrappers for and extensions to libxml2.
#define pcmk_err_cib_backup
xmlNode * create_xml_node(xmlNode *parent, const char *name)
const char * crm_element_value(xmlNode *data, const char *name)
#define XML_ATTR_VALIDATION
void free_xml(xmlNode *child)
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
gboolean crm_ends_with_ext(const char *s, const char *match)
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
cib_t * cib_file_new(const char *filename)
void write_last_sequence(const char *directory, const char *series, int sequence, int max)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
int cib_process_query(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
#define crm_perror(level, fmt, args...)
Log a system error message.
#define crm_err(fmt, args...)
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)
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
int crm_write_sync(int fd, const char *contents)
#define XML_ATTR_GENERATION_ADMIN
#define pcmk_err_cib_modified
int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Wrappers for and extensions to libqb IPC.
int cib_file_free(cib_t *cib)
#define XML_CIB_TAG_STATUS
int cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
int(* signoff)(cib_t *cib)
void crm_sync_directory(const char *name)
char * crm_concat(const char *prefix, const char *suffix, char join)
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
#define safe_str_eq(a, b)
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#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...)
const char * crm_xml_add_last_written(xmlNode *xml_node)
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
enum crm_ais_msg_types type