This source file includes following definitions.
- cib_rename
- retrieveCib
- cib_archive_filter
- cib_archive_sort
- readCibXmlFile
- get_the_CIB
- uninitializeCib
- initializeCib
- activateCibXml
- cib_diskwrite_complete
- write_cib_contents
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
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
74
75
76 static xmlNode *
77 retrieveCib(const char *filename, const char *sigfile)
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
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
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
112
113 static int cib_archive_filter(const struct dirent * a)
114 {
115 int rc = 0;
116
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)
159 {
160
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)
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
266 free_xml(status);
267 status = NULL;
268 }
269 if (status == NULL) {
270 create_xml_node(root, XML_CIB_TAG_STATUS);
271 }
272
273
274
275
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
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
330
331 xmlNode *
332 get_the_CIB(void)
333 {
334 return the_cib;
335 }
336
337 gboolean
338 uninitializeCib(void)
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
361
362
363
364 gboolean
365 initializeCib(xmlNode * new_cib)
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
378
379
380 int
381 activateCibXml(xmlNode * new_cib, gboolean to_disk, const char *op)
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
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)
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)
435 {
436 int exit_rc = pcmk_ok;
437 xmlNode *cib_local = NULL;
438
439
440 if (p) {
441
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
449
450
451
452
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
465 mainloop_child_add(pid, 0, "disk-writer", NULL, cib_diskwrite_complete);
466 if (bb_state == QB_LOG_STATE_ENABLED) {
467
468 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
469 }
470
471 return -1;
472 }
473
474
475
476
477
478
479 cib_local = copy_xml(the_cib);
480 }
481
482
483 exit_rc = cib_file_write_with_digest(cib_local, cib_root, "cib.xml");
484
485
486 free_xml(cib_local);
487 if (p == NULL) {
488
489 _exit(exit_rc);
490 }
491 return exit_rc;
492 }