root/cib/io.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_rename
  2. retrieveCib
  3. cib_archive_filter
  4. cib_archive_sort
  5. readCibXmlFile
  6. get_the_CIB
  7. uninitializeCib
  8. initializeCib
  9. activateCibXml
  10. cib_diskwrite_complete
  11. write_cib_contents

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 
  21 #include <stdio.h>
  22 #include <unistd.h>
  23 #include <string.h>
  24 #include <stdlib.h>
  25 #include <errno.h>
  26 #include <fcntl.h>
  27 #include <dirent.h>
  28 
  29 #include <sys/param.h>
  30 #include <sys/types.h>
  31 #include <sys/wait.h>
  32 #include <sys/stat.h>
  33 
  34 #include <crm/crm.h>
  35 
  36 #include <cibio.h>
  37 #include <crm/cib.h>
  38 #include <crm/common/util.h>
  39 #include <crm/msg_xml.h>
  40 #include <crm/common/xml.h>
  41 #include <crm/cib/internal.h>
  42 #include <crm/cluster.h>
  43 
  44 extern const char *cib_root;
  45 
  46 crm_trigger_t *cib_writer = NULL;
  47 gboolean initialized = FALSE;
  48 
  49 extern int cib_status;
  50 
  51 int write_cib_contents(gpointer p);
  52 
  53 static void
  54 cib_rename(const char *old)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56     int new_fd;
  57     char *new = crm_strdup_printf("%s/cib.auto.XXXXXX", cib_root);
  58 
  59     crm_err("Archiving unusable file %s as %s", old, new);
  60     umask(S_IWGRP | S_IWOTH | S_IROTH);
  61     if ((new_fd = mkstemp(new) < 0) || (rename(old, new) < 0)) {
  62         crm_perror(LOG_ERR, "Couldn't rename %s as %s", old, new);
  63         crm_err("Disabling disk writes and continuing");
  64         cib_writes_enabled = FALSE;
  65     }
  66     if (new_fd > 0) {
  67         close(new_fd);
  68     }
  69     free(new);
  70 }
  71 
  72 /*
  73  * It is the callers responsibility to free the output of this function
  74  */
  75 
  76 static xmlNode *
  77 retrieveCib(const char *filename, const char *sigfile)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79     xmlNode *root = NULL;
  80 
  81     crm_info("Reading cluster configuration file %s (digest: %s)",
  82              filename, sigfile);
  83     switch (cib_file_read_and_verify(filename, sigfile, &root)) {
  84         case -pcmk_err_cib_corrupt:
  85             crm_warn("Continuing but %s will NOT be used.", filename);
  86             break;
  87 
  88         case -pcmk_err_cib_modified:
  89             /* Archive the original files so the contents are not lost */
  90             crm_warn("Continuing but %s will NOT be used.", filename);
  91             cib_rename(filename);
  92             cib_rename(sigfile);
  93             break;
  94     }
  95     return root;
  96 }
  97 
  98 /*
  99  * for OSs without support for direntry->d_type, like Solaris
 100  */
 101 #ifndef DT_UNKNOWN
 102 # define DT_UNKNOWN     0
 103 # define DT_FIFO        1
 104 # define DT_CHR         2
 105 # define DT_DIR         4
 106 # define DT_BLK         6
 107 # define DT_REG         8
 108 # define DT_LNK         10
 109 # define DT_SOCK        12
 110 # define DT_WHT         14
 111 #endif /*DT_UNKNOWN*/
 112 
 113 static int cib_archive_filter(const struct dirent * a)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115     int rc = 0;
 116     /* Looking for regular files (d_type = 8) starting with 'cib-' and not ending in .sig */
 117     struct stat s;
 118     char *a_path = crm_strdup_printf("%s/%s", cib_root, a->d_name);
 119 
 120     if(stat(a_path, &s) != 0) {
 121         rc = errno;
 122         crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_strerror(rc), rc);
 123         rc = 0;
 124 
 125     } else if ((s.st_mode & S_IFREG) != S_IFREG) {
 126         unsigned char dtype;
 127 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
 128         dtype = a->d_type;
 129 #else
 130         switch (s.st_mode & S_IFMT) {
 131             case S_IFREG:  dtype = DT_REG;      break;
 132             case S_IFDIR:  dtype = DT_DIR;      break;
 133             case S_IFCHR:  dtype = DT_CHR;      break;
 134             case S_IFBLK:  dtype = DT_BLK;      break;
 135             case S_IFLNK:  dtype = DT_LNK;      break;
 136             case S_IFIFO:  dtype = DT_FIFO;     break;
 137             case S_IFSOCK: dtype = DT_SOCK;     break;
 138             default:       dtype = DT_UNKNOWN;  break;
 139         }
 140 #endif
 141          crm_trace("%s - wrong type (%d)", a->d_name, dtype);
 142 
 143     } else if(strstr(a->d_name, "cib-") != a->d_name) {
 144         crm_trace("%s - wrong prefix", a->d_name);
 145 
 146     } else if (crm_ends_with_ext(a->d_name, ".sig")) {
 147         crm_trace("%s - wrong suffix", a->d_name);
 148 
 149     } else {
 150         crm_debug("%s - candidate", a->d_name);
 151         rc = 1;
 152     }
 153 
 154     free(a_path);
 155     return rc;
 156 }
 157 
 158 static int cib_archive_sort(const struct dirent ** a, const struct dirent **b)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160     /* Order by creation date - most recently created file first */
 161     int rc = 0;
 162     struct stat buf;
 163 
 164     time_t a_age = 0;
 165     time_t b_age = 0;
 166 
 167     char *a_path = crm_strdup_printf("%s/%s", cib_root, a[0]->d_name);
 168     char *b_path = crm_strdup_printf("%s/%s", cib_root, b[0]->d_name);
 169 
 170     if(stat(a_path, &buf) == 0) {
 171         a_age = buf.st_ctime;
 172     }
 173     if(stat(b_path, &buf) == 0) {
 174         b_age = buf.st_ctime;
 175     }
 176 
 177     free(a_path);
 178     free(b_path);
 179 
 180     if(a_age > b_age) {
 181         rc = 1;
 182     } else if(a_age < b_age) {
 183         rc = -1;
 184     }
 185 
 186     crm_trace("%s (%lu) vs. %s (%lu) : %d",
 187         a[0]->d_name, (unsigned long)a_age,
 188         b[0]->d_name, (unsigned long)b_age, rc);
 189     return rc;
 190 }
 191 
 192 xmlNode *
 193 readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195     struct dirent **namelist = NULL;
 196 
 197     int lpc = 0;
 198     char *sigfile = NULL;
 199     char *filename = NULL;
 200     const char *name = NULL;
 201     const char *value = NULL;
 202     const char *validation = NULL;
 203     const char *use_valgrind = getenv("PCMK_valgrind_enabled");
 204 
 205     xmlNode *root = NULL;
 206     xmlNode *status = NULL;
 207 
 208     if (!crm_is_writable(dir, file, CRM_DAEMON_USER, NULL, FALSE)) {
 209         cib_status = -EACCES;
 210         return NULL;
 211     }
 212 
 213     filename = crm_concat(dir, file, '/');
 214     sigfile = crm_concat(filename, "sig", '.');
 215 
 216     cib_status = pcmk_ok;
 217     root = retrieveCib(filename, sigfile);
 218     free(filename);
 219     free(sigfile);
 220 
 221     if (root == NULL) {
 222         crm_warn("Primary configuration corrupt or unusable, trying backups in %s", cib_root);
 223         lpc = scandir(cib_root, &namelist, cib_archive_filter, cib_archive_sort);
 224         if (lpc < 0) {
 225             crm_perror(LOG_NOTICE, "scandir(%s) failed", cib_root);
 226         }
 227     }
 228 
 229     while (root == NULL && lpc > 1) {
 230         crm_debug("Testing %d candidates", lpc);
 231 
 232         lpc--;
 233 
 234         filename = crm_strdup_printf("%s/%s", cib_root, namelist[lpc]->d_name);
 235         sigfile = crm_concat(filename, "sig", '.');
 236 
 237         crm_info("Reading cluster configuration file %s (digest: %s)",
 238                  filename, sigfile);
 239         if (cib_file_read_and_verify(filename, sigfile, &root) < 0) {
 240             crm_warn("Continuing but %s will NOT be used.", filename);
 241         } else {
 242             crm_notice("Continuing with last valid configuration archive: %s", filename);
 243         }
 244 
 245         free(namelist[lpc]);
 246         free(filename);
 247         free(sigfile);
 248     }
 249     free(namelist);
 250 
 251     if (root == NULL) {
 252         root = createEmptyCib(0);
 253         crm_warn("Continuing with an empty configuration.");
 254     }
 255 
 256     if (cib_writes_enabled && use_valgrind) {
 257         if (crm_is_true(use_valgrind) || strstr(use_valgrind, "cib")) {
 258             cib_writes_enabled = FALSE;
 259             crm_err("*** Disabling disk writes to avoid confusing Valgrind ***");
 260         }
 261     }
 262 
 263     status = find_xml_node(root, XML_CIB_TAG_STATUS, FALSE);
 264     if (discard_status && status != NULL) {
 265         /* strip out the status section if there is one */
 266         free_xml(status);
 267         status = NULL;
 268     }
 269     if (status == NULL) {
 270         create_xml_node(root, XML_CIB_TAG_STATUS);
 271     }
 272 
 273     /* Do this before DTD validation happens */
 274 
 275     /* fill in some defaults */
 276     name = XML_ATTR_GENERATION_ADMIN;
 277     value = crm_element_value(root, name);
 278     if (value == NULL) {
 279         crm_warn("No value for %s was specified in the configuration.", name);
 280         crm_warn("The recommended course of action is to shutdown,"
 281                  " run crm_verify and fix any errors it reports.");
 282         crm_warn("We will default to zero and continue but may get"
 283                  " confused about which configuration to use if"
 284                  " multiple nodes are powered up at the same time.");
 285         crm_xml_add_int(root, name, 0);
 286     }
 287 
 288     name = XML_ATTR_GENERATION;
 289     value = crm_element_value(root, name);
 290     if (value == NULL) {
 291         crm_xml_add_int(root, name, 0);
 292     }
 293 
 294     name = XML_ATTR_NUMUPDATES;
 295     value = crm_element_value(root, name);
 296     if (value == NULL) {
 297         crm_xml_add_int(root, name, 0);
 298     }
 299 
 300     /* unset these and require the DC/CCM to update as needed */
 301     xml_remove_prop(root, XML_ATTR_DC_UUID);
 302 
 303     if (discard_status) {
 304         crm_log_xml_trace(root, "[on-disk]");
 305     }
 306 
 307     validation = crm_element_value(root, XML_ATTR_VALIDATION);
 308     if (validate_xml(root, NULL, TRUE) == FALSE) {
 309         crm_err("CIB does not validate with %s", crm_str(validation));
 310         cib_status = -pcmk_err_schema_validation;
 311 
 312     } else if (validation == NULL) {
 313         int version = 0;
 314 
 315         update_validation(&root, &version, 0, FALSE, FALSE);
 316         if (version > 0) {
 317             crm_notice("Enabling %s validation on"
 318                        " the existing (sane) configuration", get_schema_name(version));
 319         } else {
 320             crm_err("CIB does not validate with any known DTD or schema");
 321             cib_status = -pcmk_err_schema_validation;
 322         }
 323     }
 324 
 325     return root;
 326 }
 327 
 328 /*
 329  * The caller should never free the return value
 330  */
 331 xmlNode *
 332 get_the_CIB(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334     return the_cib;
 335 }
 336 
 337 gboolean
 338 uninitializeCib(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340     xmlNode *tmp_cib = the_cib;
 341 
 342     if (tmp_cib == NULL) {
 343         crm_debug("The CIB has already been deallocated.");
 344         return FALSE;
 345     }
 346 
 347     initialized = FALSE;
 348     the_cib = NULL;
 349 
 350     crm_debug("Deallocating the CIB.");
 351 
 352     free_xml(tmp_cib);
 353 
 354     crm_debug("The CIB has been deallocated.");
 355 
 356     return TRUE;
 357 }
 358 
 359 /*
 360  * This method will not free the old CIB pointer or the new one.
 361  * We rely on the caller to have saved a pointer to the old CIB
 362  *   and to free the old/bad one depending on what is appropriate.
 363  */
 364 gboolean
 365 initializeCib(xmlNode * new_cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367     if (new_cib == NULL) {
 368         return FALSE;
 369     }
 370 
 371     the_cib = new_cib;
 372     initialized = TRUE;
 373     return TRUE;
 374 }
 375 
 376 /*
 377  * This method will free the old CIB pointer on success and the new one
 378  * on failure.
 379  */
 380 int
 381 activateCibXml(xmlNode * new_cib, gboolean to_disk, const char *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 382 {
 383     xmlNode *saved_cib = the_cib;
 384 
 385     CRM_ASSERT(new_cib != saved_cib);
 386     if (initializeCib(new_cib) == FALSE) {
 387         free_xml(new_cib);
 388         crm_err("Ignoring invalid or NULL CIB");
 389 
 390         if (saved_cib != NULL) {
 391             crm_warn("Reverting to last known CIB");
 392             if (initializeCib(saved_cib) == FALSE) {
 393                 /* oh we are so dead  */
 394                 crm_crit("Couldn't re-initialize the old CIB!");
 395                 exit(1);
 396             }
 397 
 398         } else {
 399             crm_crit("Could not write out new CIB and no saved" " version to revert to");
 400         }
 401         return -ENODATA;
 402     }
 403 
 404     free_xml(saved_cib);
 405     if (cib_writes_enabled && cib_status == pcmk_ok && to_disk) {
 406         crm_debug("Triggering CIB write for %s op", op);
 407         mainloop_set_trigger(cib_writer);
 408     }
 409 
 410     return pcmk_ok;
 411 }
 412 
 413 static void
 414 cib_diskwrite_complete(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416     if (signo) {
 417         crm_notice("Disk write process terminated with signal %d (pid=%d, core=%d)", signo, pid,
 418                    core);
 419 
 420     } else  {
 421         do_crm_log(exitcode == 0 ? LOG_TRACE : LOG_ERR, "Disk write process exited (pid=%d, rc=%d)",
 422                    pid, exitcode);
 423     }
 424 
 425     if (exitcode != 0 && cib_writes_enabled) {
 426         crm_err("Disabling disk writes after write failure");
 427         cib_writes_enabled = FALSE;
 428     }
 429 
 430     mainloop_trigger_complete(cib_writer);
 431 }
 432 
 433 int
 434 write_cib_contents(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436     int exit_rc = pcmk_ok;
 437     xmlNode *cib_local = NULL;
 438 
 439     /* Make a copy of the CIB to write (possibly in a forked child) */
 440     if (p) {
 441         /* Synchronous write out */
 442         cib_local = copy_xml(p);
 443 
 444     } else {
 445         int pid = 0;
 446         int bb_state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
 447 
 448         /* Turn it off before the fork() to avoid:
 449          * - 2 processes writing to the same shared mem
 450          * - the child needing to disable it
 451          *   (which would close it from underneath the parent)
 452          * This way, the shared mem files are already closed
 453          */
 454         qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
 455 
 456         pid = fork();
 457         if (pid < 0) {
 458             crm_perror(LOG_ERR, "Disabling disk writes after fork failure");
 459             cib_writes_enabled = FALSE;
 460             return FALSE;
 461         }
 462 
 463         if (pid) {
 464             /* Parent */
 465             mainloop_child_add(pid, 0, "disk-writer", NULL, cib_diskwrite_complete);
 466             if (bb_state == QB_LOG_STATE_ENABLED) {
 467                 /* Re-enable now that it it safe */
 468                 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
 469             }
 470 
 471             return -1;          /* -1 means 'still work to do' */
 472         }
 473 
 474         /* A-synchronous write out after a fork() */
 475 
 476         /* In theory we can scribble on "the_cib" here and not affect the parent
 477          * But lets be safe anyway
 478          */
 479         cib_local = copy_xml(the_cib);
 480     }
 481 
 482     /* Write the CIB */
 483     exit_rc = cib_file_write_with_digest(cib_local, cib_root, "cib.xml");
 484 
 485     /* A nonzero exit code will cause further writes to be disabled */
 486     free_xml(cib_local);
 487     if (p == NULL) {
 488         /* Use _exit() because exit() could affect the parent adversely */
 489         _exit(exit_rc);
 490     }
 491     return exit_rc;
 492 }

/* [previous][next][first][last][top][bottom][index][help] */