This source file includes following definitions.
- cib_rename
- retrieveCib
- cib_archive_filter
- cib_archive_sort
- readCibXmlFile
- uninitializeCib
- activateCibXml
- cib_diskwrite_complete
- write_cib_contents
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <dirent.h>
19
20 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <sys/stat.h>
24
25 #include <crm/crm.h>
26
27 #include <crm/cib.h>
28 #include <crm/common/util.h>
29 #include <crm/msg_xml.h>
30 #include <crm/common/xml.h>
31 #include <crm/cib/internal.h>
32 #include <crm/cluster.h>
33
34 #include <pacemaker-based.h>
35
36 crm_trigger_t *cib_writer = NULL;
37
38 int write_cib_contents(gpointer p);
39
40 static void
41 cib_rename(const char *old)
42 {
43 int new_fd;
44 char *new = crm_strdup_printf("%s/cib.auto.XXXXXX", cib_root);
45
46 umask(S_IWGRP | S_IWOTH | S_IROTH);
47 new_fd = mkstemp(new);
48 crm_err("Archiving unusable file %s as %s", old, new);
49 if ((new_fd < 0) || (rename(old, new) < 0)) {
50 crm_perror(LOG_ERR, "Couldn't rename %s as %s", old, new);
51 crm_err("Disabling disk writes and continuing");
52 cib_writes_enabled = FALSE;
53 }
54 if (new_fd > 0) {
55 close(new_fd);
56 }
57 free(new);
58 }
59
60
61
62
63
64 static xmlNode *
65 retrieveCib(const char *filename, const char *sigfile)
66 {
67 xmlNode *root = NULL;
68
69 crm_info("Reading cluster configuration file %s (digest: %s)",
70 filename, sigfile);
71 switch (cib_file_read_and_verify(filename, sigfile, &root)) {
72 case -pcmk_err_cib_corrupt:
73 crm_warn("Continuing but %s will NOT be used.", filename);
74 break;
75
76 case -pcmk_err_cib_modified:
77
78 crm_warn("Continuing but %s will NOT be used.", filename);
79 cib_rename(filename);
80 cib_rename(sigfile);
81 break;
82 }
83 return root;
84 }
85
86
87
88
89 #ifndef DT_UNKNOWN
90 # define DT_UNKNOWN 0
91 # define DT_FIFO 1
92 # define DT_CHR 2
93 # define DT_DIR 4
94 # define DT_BLK 6
95 # define DT_REG 8
96 # define DT_LNK 10
97 # define DT_SOCK 12
98 # define DT_WHT 14
99 #endif
100
101 static int cib_archive_filter(const struct dirent * a)
102 {
103 int rc = 0;
104
105 struct stat s;
106 char *a_path = crm_strdup_printf("%s/%s", cib_root, a->d_name);
107
108 if(stat(a_path, &s) != 0) {
109 rc = errno;
110 crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_strerror(rc), rc);
111 rc = 0;
112
113 } else if ((s.st_mode & S_IFREG) != S_IFREG) {
114 unsigned char dtype;
115 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
116 dtype = a->d_type;
117 #else
118 switch (s.st_mode & S_IFMT) {
119 case S_IFREG: dtype = DT_REG; break;
120 case S_IFDIR: dtype = DT_DIR; break;
121 case S_IFCHR: dtype = DT_CHR; break;
122 case S_IFBLK: dtype = DT_BLK; break;
123 case S_IFLNK: dtype = DT_LNK; break;
124 case S_IFIFO: dtype = DT_FIFO; break;
125 case S_IFSOCK: dtype = DT_SOCK; break;
126 default: dtype = DT_UNKNOWN; break;
127 }
128 #endif
129 crm_trace("%s - wrong type (%d)", a->d_name, dtype);
130
131 } else if(strstr(a->d_name, "cib-") != a->d_name) {
132 crm_trace("%s - wrong prefix", a->d_name);
133
134 } else if (pcmk__ends_with_ext(a->d_name, ".sig")) {
135 crm_trace("%s - wrong suffix", a->d_name);
136
137 } else {
138 crm_debug("%s - candidate", a->d_name);
139 rc = 1;
140 }
141
142 free(a_path);
143 return rc;
144 }
145
146 static int cib_archive_sort(const struct dirent ** a, const struct dirent **b)
147 {
148
149 int rc = 0;
150 struct stat buf;
151
152 time_t a_age = 0;
153 time_t b_age = 0;
154
155 char *a_path = crm_strdup_printf("%s/%s", cib_root, a[0]->d_name);
156 char *b_path = crm_strdup_printf("%s/%s", cib_root, b[0]->d_name);
157
158 if(stat(a_path, &buf) == 0) {
159 a_age = buf.st_ctime;
160 }
161 if(stat(b_path, &buf) == 0) {
162 b_age = buf.st_ctime;
163 }
164
165 free(a_path);
166 free(b_path);
167
168 if(a_age > b_age) {
169 rc = 1;
170 } else if(a_age < b_age) {
171 rc = -1;
172 }
173
174 crm_trace("%s (%lu) vs. %s (%lu) : %d",
175 a[0]->d_name, (unsigned long)a_age,
176 b[0]->d_name, (unsigned long)b_age, rc);
177 return rc;
178 }
179
180 xmlNode *
181 readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
182 {
183 struct dirent **namelist = NULL;
184
185 int lpc = 0;
186 char *sigfile = NULL;
187 char *sigfilepath = NULL;
188 char *filename = NULL;
189 const char *name = NULL;
190 const char *value = NULL;
191 const char *validation = NULL;
192 const char *use_valgrind = getenv("PCMK_valgrind_enabled");
193
194 xmlNode *root = NULL;
195 xmlNode *status = NULL;
196
197 sigfile = crm_strdup_printf("%s.sig", file);
198 if (pcmk__daemon_can_write(dir, file) == FALSE
199 || pcmk__daemon_can_write(dir, sigfile) == FALSE) {
200 cib_status = -EACCES;
201 return NULL;
202 }
203
204 filename = crm_strdup_printf("%s/%s", dir, file);
205 sigfilepath = crm_strdup_printf("%s/%s", dir, sigfile);
206 free(sigfile);
207
208 cib_status = pcmk_ok;
209 root = retrieveCib(filename, sigfilepath);
210 free(filename);
211 free(sigfilepath);
212
213 if (root == NULL) {
214 crm_warn("Primary configuration corrupt or unusable, trying backups in %s", cib_root);
215 lpc = scandir(cib_root, &namelist, cib_archive_filter, cib_archive_sort);
216 if (lpc < 0) {
217 crm_perror(LOG_NOTICE, "scandir(%s) failed", cib_root);
218 }
219 }
220
221 while (root == NULL && lpc > 1) {
222 crm_debug("Testing %d candidates", lpc);
223
224 lpc--;
225
226 filename = crm_strdup_printf("%s/%s", cib_root, namelist[lpc]->d_name);
227 sigfile = crm_strdup_printf("%s.sig", filename);
228
229 crm_info("Reading cluster configuration file %s (digest: %s)",
230 filename, sigfile);
231 if (cib_file_read_and_verify(filename, sigfile, &root) < 0) {
232 crm_warn("Continuing but %s will NOT be used.", filename);
233 } else {
234 crm_notice("Continuing with last valid configuration archive: %s", filename);
235 }
236
237 free(namelist[lpc]);
238 free(filename);
239 free(sigfile);
240 }
241 free(namelist);
242
243 if (root == NULL) {
244 root = createEmptyCib(0);
245 crm_warn("Continuing with an empty configuration.");
246 }
247
248 if (cib_writes_enabled && use_valgrind &&
249 (crm_is_true(use_valgrind) || strstr(use_valgrind, "pacemaker-based"))) {
250
251 cib_writes_enabled = FALSE;
252 crm_err("*** Disabling disk writes to avoid confusing Valgrind ***");
253 }
254
255 status = find_xml_node(root, XML_CIB_TAG_STATUS, FALSE);
256 if (discard_status && status != NULL) {
257
258 free_xml(status);
259 status = NULL;
260 }
261 if (status == NULL) {
262 create_xml_node(root, XML_CIB_TAG_STATUS);
263 }
264
265
266
267
268 name = XML_ATTR_GENERATION_ADMIN;
269 value = crm_element_value(root, name);
270 if (value == NULL) {
271 crm_warn("No value for %s was specified in the configuration.", name);
272 crm_warn("The recommended course of action is to shutdown,"
273 " run crm_verify and fix any errors it reports.");
274 crm_warn("We will default to zero and continue but may get"
275 " confused about which configuration to use if"
276 " multiple nodes are powered up at the same time.");
277 crm_xml_add_int(root, name, 0);
278 }
279
280 name = XML_ATTR_GENERATION;
281 value = crm_element_value(root, name);
282 if (value == NULL) {
283 crm_xml_add_int(root, name, 0);
284 }
285
286 name = XML_ATTR_NUMUPDATES;
287 value = crm_element_value(root, name);
288 if (value == NULL) {
289 crm_xml_add_int(root, name, 0);
290 }
291
292
293 xml_remove_prop(root, XML_ATTR_DC_UUID);
294
295 if (discard_status) {
296 crm_log_xml_trace(root, "[on-disk]");
297 }
298
299 validation = crm_element_value(root, XML_ATTR_VALIDATION);
300 if (validate_xml(root, NULL, TRUE) == FALSE) {
301 crm_err("CIB does not validate with %s",
302 pcmk__s(validation, "no schema specified"));
303 cib_status = -pcmk_err_schema_validation;
304
305 } else if (validation == NULL) {
306 int version = 0;
307
308 update_validation(&root, &version, 0, FALSE, FALSE);
309 if (version > 0) {
310 crm_notice("Enabling %s validation on"
311 " the existing (sane) configuration", get_schema_name(version));
312 } else {
313 crm_err("CIB does not validate with any known schema");
314 cib_status = -pcmk_err_schema_validation;
315 }
316 }
317
318 return root;
319 }
320
321 gboolean
322 uninitializeCib(void)
323 {
324 xmlNode *tmp_cib = the_cib;
325
326 if (tmp_cib == NULL) {
327 crm_debug("The CIB has already been deallocated.");
328 return FALSE;
329 }
330
331 the_cib = NULL;
332
333 crm_debug("Deallocating the CIB.");
334
335 free_xml(tmp_cib);
336
337 crm_debug("The CIB has been deallocated.");
338
339 return TRUE;
340 }
341
342
343
344
345
346 int
347 activateCibXml(xmlNode * new_cib, gboolean to_disk, const char *op)
348 {
349 if (new_cib) {
350 xmlNode *saved_cib = the_cib;
351
352 CRM_ASSERT(new_cib != saved_cib);
353 the_cib = new_cib;
354 free_xml(saved_cib);
355 if (cib_writes_enabled && cib_status == pcmk_ok && to_disk) {
356 crm_debug("Triggering CIB write for %s op", op);
357 mainloop_set_trigger(cib_writer);
358 }
359 return pcmk_ok;
360 }
361
362 crm_err("Ignoring invalid CIB");
363 if (the_cib) {
364 crm_warn("Reverting to last known CIB");
365 } else {
366 crm_crit("Could not write out new CIB and no saved version to revert to");
367 }
368 return -ENODATA;
369 }
370
371 static void
372 cib_diskwrite_complete(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
373 {
374 const char *errmsg = "Could not write CIB to disk";
375
376 if ((exitcode != 0) && cib_writes_enabled) {
377 cib_writes_enabled = FALSE;
378 errmsg = "Disabling CIB disk writes after failure";
379 }
380
381 if ((signo == 0) && (exitcode == 0)) {
382 crm_trace("Disk write [%d] succeeded", (int) pid);
383
384 } else if (signo == 0) {
385 crm_err("%s: process %d exited %d", errmsg, (int) pid, exitcode);
386
387 } else {
388 crm_err("%s: process %d terminated with signal %d (%s)%s",
389 errmsg, (int) pid, signo, strsignal(signo),
390 (core? " and dumped core" : ""));
391 }
392
393 mainloop_trigger_complete(cib_writer);
394 }
395
396 int
397 write_cib_contents(gpointer p)
398 {
399 int exit_rc = pcmk_ok;
400 xmlNode *cib_local = NULL;
401
402
403 if (p) {
404
405 cib_local = copy_xml(p);
406
407 } else {
408 int pid = 0;
409 int bb_state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
410
411
412
413
414
415
416
417 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
418
419 pid = fork();
420 if (pid < 0) {
421 crm_perror(LOG_ERR, "Disabling disk writes after fork failure");
422 cib_writes_enabled = FALSE;
423 return FALSE;
424 }
425
426 if (pid) {
427
428 mainloop_child_add(pid, 0, "disk-writer", NULL, cib_diskwrite_complete);
429 if (bb_state == QB_LOG_STATE_ENABLED) {
430
431 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
432 }
433
434 return -1;
435 }
436
437
438
439
440
441
442 cib_local = copy_xml(the_cib);
443 }
444
445
446 exit_rc = cib_file_write_with_digest(cib_local, cib_root, "cib.xml");
447
448
449 free_xml(cib_local);
450 if (p == NULL) {
451 crm_exit_t exit_code = CRM_EX_OK;
452
453 switch (exit_rc) {
454 case pcmk_ok:
455 exit_code = CRM_EX_OK;
456 break;
457 case pcmk_err_cib_modified:
458 exit_code = CRM_EX_DIGEST;
459 break;
460 case pcmk_err_cib_backup:
461 case pcmk_err_cib_save:
462 exit_code = CRM_EX_CANTCREAT;
463 break;
464 default:
465 exit_code = CRM_EX_ERROR;
466 break;
467 }
468
469
470 _exit(exit_code);
471 }
472 return exit_rc;
473 }