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