22 #include <sys/types.h>    37 typedef struct cib_file_opaque_s {
    42 #define cib_set_file_flags(cibfile, flags_to_set) do {                  \    43         (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__,       \    44                                               LOG_TRACE, "CIB file",    \    51 #define cib_clear_file_flags(cibfile, flags_to_clear) do {              \    52         (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__,     \    53                                                 LOG_TRACE, "CIB file",  \    61                         xmlNode * 
data, xmlNode ** output_data, 
int call_options);
    64                                  xmlNode * 
data, xmlNode ** output_data, 
int call_options,
    65                                  const char *user_name);
    72 cib_file_inputfd(
cib_t * cib)
    74     return -EPROTONOSUPPORT;
    78 cib_file_set_connection_dnotify(
cib_t * cib, 
void (*dnotify) (gpointer user_data))
    80     return -EPROTONOSUPPORT;
    84 cib_file_register_notification(
cib_t * cib, 
const char *callback, 
int enabled)
    86     return -EPROTONOSUPPORT;
    99 cib_file_verify_digest(xmlNode *root, 
const char *sigfile)
   101     gboolean passed = FALSE;
   107             if (expected == NULL) {
   108                 crm_err(
"On-disk digest at %s is empty", sigfile);
   113             crm_warn(
"No on-disk digest present at %s", sigfile);
   116             crm_err(
"Could not read on-disk digest from %s: %s",
   145     char *local_sigfile = NULL;
   146     xmlNode *local_root = NULL;
   154     s_res = stat(filename, &buf);
   156         crm_perror(LOG_WARNING, 
"Could not verify cluster configuration file %s", filename);
   158     } 
else if (buf.st_size == 0) {
   159         crm_warn(
"Cluster configuration file %s is corrupt (size is zero)", filename);
   165     if (local_root == NULL) {
   166         crm_warn(
"Cluster configuration file %s is corrupt (unparseable as XML)", filename);
   171     if (sigfile == NULL) {
   176     if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
   191 #define CIB_SERIES "cib"   192 #define CIB_SERIES_MAX 100   193 #define CIB_SERIES_BZIP FALSE    197 #define CIB_LIVE_NAME CIB_SERIES ".xml"   208 cib_file_is_live(
const char *filename)
   210     gboolean same = FALSE;
   212     if (filename != NULL) {
   214         char *real_filename = NULL;
   217             char *real_livename = NULL;
   221                 same = !strcmp(real_filename, real_livename);
   234 static uid_t cib_file_owner = 0;
   235 static uid_t cib_file_group = 0;
   236 static gboolean cib_do_chown = FALSE;
   248 cib_file_backup(
const char *cib_dirname, 
const char *cib_filename)
   269     unlink(backup_digest);
   272     if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
   273         crm_perror(LOG_ERR, 
"Could not archive %s by linking to %s",
   274                    cib_path, backup_path);
   278     } 
else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
   279         crm_perror(LOG_ERR, 
"Could not archive %s by linking to %s",
   280                    cib_digest, backup_digest);
   290             if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
   291                     && (errno != ENOENT)) {
   292                 crm_perror(LOG_ERR, 
"Could not set owner of %s", backup_path);
   295             if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
   296                     && (errno != ENOENT)) {
   297                 crm_perror(LOG_ERR, 
"Could not set owner of %s", backup_digest);
   301                                               cib_file_owner, cib_file_group);
   303                 crm_err(
"Could not set owner of sequence file in %s: %s",
   309         crm_info(
"Archived previous version as %s", backup_path);
   331 cib_file_prepare_xml(xmlNode *root)
   333     xmlNode *cib_status_root = NULL;
   343     if (cib_status_root != NULL) {
   363                            const char *cib_filename)
   382     CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
   383                && (tmp_cib != NULL) && (tmp_digest != NULL));
   386     crm_trace(
"Reading cluster configuration file %s", cib_path);
   389         crm_err(
"%s was manually modified while the cluster was active!",
   396     if (cib_file_backup(cib_dirname, cib_filename) < 0) {
   402     umask(S_IWGRP | S_IWOTH | S_IROTH);
   403     cib_file_prepare_xml(cib_root);
   406     fd = mkstemp(tmp_cib);
   408         crm_perror(LOG_ERR, 
"Couldn't open temporary file %s for writing CIB",
   415     if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
   416         crm_perror(LOG_ERR, 
"Couldn't protect temporary file %s for writing CIB",
   421     if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
   422         crm_perror(LOG_ERR, 
"Couldn't protect temporary file %s for writing CIB",
   430         crm_err(
"Changes couldn't be written to %s", tmp_cib);
   438     crm_info(
"Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
   439              (admin_epoch ? admin_epoch : 
"0"), (epoch ? epoch : 
"0"), digest);
   442     fd = mkstemp(tmp_digest);
   444         crm_perror(LOG_ERR, 
"Could not create temporary file for CIB digest");
   448     if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
   449         crm_perror(LOG_ERR, 
"Couldn't protect temporary file %s for writing CIB",
   457         crm_err(
"Could not write digest to %s: %s",
   464     crm_debug(
"Wrote digest %s to disk", digest);
   467     crm_info(
"Reading cluster configuration file %s (digest: %s)",
   468              tmp_cib, tmp_digest);
   474     if (rename(tmp_cib, cib_path) < 0) {
   475         crm_perror(LOG_ERR, 
"Couldn't rename %s as %s", tmp_cib, cib_path);
   478     if (rename(tmp_digest, digest_path) < 0) {
   479         crm_perror(LOG_ERR, 
"Couldn't rename %s as %s", tmp_digest,
   506     if (
private == NULL) {
   514     if (cib_location == NULL) {
   515         cib_location = getenv(
"CIB_file");
   518     if (cib_file_is_live(cib_location)) {
   520         crm_trace(
"File %s detected as live CIB", cib_location);
   522     private->filename = strdup(cib_location);
   537 static xmlNode *in_mem_cib = NULL;
   554 load_file_cib(
const char *filename)
   557     xmlNode *root = NULL;
   560     if (strcmp(filename, 
"-") && (stat(filename, &buf) < 0)) {
   579         crm_err(
"CIB does not validate against %s", schema);
   595     if (private->filename == NULL) {
   598         rc = load_file_cib(private->filename);
   602         crm_debug(
"Opened connection to local file '%s' for %s",
   603                   private->filename, 
name);
   608         crm_info(
"Connection to local file '%s' for %s failed: %s\n",
   623 cib_file_write_live(
char *path)
   625     uid_t uid = geteuid();
   626     struct passwd *daemon_pwent;
   627     char *sep = strrchr(path, 
'/');
   628     const char *cib_dirname, *cib_filename;
   634     if (daemon_pwent == NULL) {
   643     if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
   644         crm_perror(LOG_ERR, 
"Must be root or %s to modify live CIB",
   656     } 
else if (sep == path) { 
   658         cib_filename = path + 1;
   662         cib_filename = sep + 1;
   667         cib_file_owner = daemon_pwent->pw_uid;
   668         cib_file_group = daemon_pwent->pw_gid;
   680         cib_do_chown = FALSE;
   684     if ((sep != NULL) && (*sep == 
'\0')) {
   710     crm_debug(
"Disconnecting from the CIB manager");
   719             if (cib_file_write_live(private->filename) < 0) {
   727             if (
write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
   733             crm_info(
"Wrote CIB to %s", private->filename);
   736             crm_err(
"Could not write CIB to %s", private->filename);
   758         free(private->filename);
   764         fprintf(stderr, 
"Couldn't sign off: %d\n", 
rc);
   770 struct cib_func_entry {
   777 static struct cib_func_entry cib_file_ops[] = {
   792                     xmlNode * 
data, xmlNode ** output_data, 
int call_options)
   800                              xmlNode * 
data, xmlNode ** output_data, 
int call_options,
   801                              const char *user_name)
   804     char *effective_user = NULL;
   805     gboolean query = FALSE;
   806     gboolean changed = FALSE;
   807     xmlNode *request = NULL;
   808     xmlNode *output = NULL;
   809     xmlNode *cib_diff = NULL;
   810     xmlNode *result_cib = NULL;
   813     static int max_msg_types = 
PCMK__NELEM(cib_file_ops);
   816     crm_info(
"Handling %s operation for %s as %s",
   817              (op? op : 
"invalid"), (section? section : 
"entire CIB"),
   818              (user_name? user_name : 
"default user"));
   827     if (output_data != NULL) {
   835     for (lpc = 0; lpc < max_msg_types; lpc++) {
   837             fn = &(cib_file_ops[lpc].fn);
   838             query = cib_file_ops[lpc].read_only;
   844         return -EPROTONOSUPPORT;
   859                         section, request, 
data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
   870     } 
else if (query == FALSE) {
   873         in_mem_cib = result_cib;
   883     if (output_data && output) {
   884         if(output == in_mem_cib) {
   887             *output_data = output;
   890     } 
else if(output != in_mem_cib) {
   894     free(effective_user);
 
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
 
#define pcmk_err_schema_validation
 
const char * pcmk_strerror(int rc)
 
#define XML_ATTR_NUMUPDATES
 
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
 
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)
 
int(* signoff)(cib_t *cib)
 
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
 
int pcmk__write_sync(int fd, const char *contents)
 
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)
 
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. 
 
#define CRM_LOG_ASSERT(expr)
 
int(* inputfd)(cib_t *cib)
 
enum crm_ais_msg_types type
 
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
 
char * pcmk__series_filename(const char *directory, const char *series, int sequence, bool bzip)
 
#define XML_ATTR_GENERATION
 
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)
 
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 CIB_OP_APPLY_DIFF
 
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
 
int pcmk__real_path(const char *path, char **resolved_path)
 
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute. 
 
int cib_file_signoff(cib_t *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)
 
Wrappers for and extensions to libxml2. 
 
xmlNode * create_xml_node(xmlNode *parent, const char *name)
 
#define XML_ATTR_VALIDATION
 
int pcmk__file_contents(const char *filename, char **contents)
 
#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__write_series_sequence(const char *directory, const char *series, unsigned int sequence, int max)
 
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)
 
#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...)
 
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
 
int pcmk__chown_series_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
 
void pcmk__sync_directory(const char *name)
 
IPC interface to Pacemaker daemons. 
 
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)
 
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
 
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor. 
 
#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)
 
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)