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/common/xml.h>
33 #include <crm/cib/internal.h>
34 #include <crm/cluster.h>
35
36 #include <pacemaker-based.h>
37
38 crm_trigger_t *cib_writer = NULL;
39
40 int write_cib_contents(gpointer p);
41
42 static void
43 cib_rename(const char *old)
44 {
45 int new_fd;
46 char *new = crm_strdup_printf("%s/cib.auto.XXXXXX", cib_root);
47
48 umask(S_IWGRP | S_IWOTH | S_IROTH);
49 new_fd = mkstemp(new);
50
51 if ((new_fd < 0) || (rename(old, new) < 0)) {
52 crm_err("Couldn't archive unusable file %s (disabling disk writes and continuing)",
53 old);
54 cib_writes_enabled = FALSE;
55 } else {
56 crm_err("Archived unusable file %s as %s", old, new);
57 }
58
59 if (new_fd > 0) {
60 close(new_fd);
61 }
62 free(new);
63 }
64
65
66
67
68
69 static xmlNode *
70 retrieveCib(const char *filename, const char *sigfile)
71 {
72 xmlNode *root = NULL;
73 int rc = cib_file_read_and_verify(filename, sigfile, &root);
74
75 if (rc == pcmk_ok) {
76 crm_info("Loaded CIB from %s (with digest %s)", filename, sigfile);
77 } else {
78 crm_warn("Continuing but NOT using CIB from %s (with digest %s): %s",
79 filename, sigfile, pcmk_strerror(rc));
80 if (rc == -pcmk_err_cib_modified) {
81
82 cib_rename(filename);
83 cib_rename(sigfile);
84 }
85 }
86 return root;
87 }
88
89 static int cib_archive_filter(const struct dirent * a)
90 {
91 int rc = 0;
92
93 struct stat s;
94 char *a_path = crm_strdup_printf("%s/%s", cib_root, a->d_name);
95
96 if(stat(a_path, &s) != 0) {
97 rc = errno;
98 crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_rc_str(rc), rc);
99 rc = 0;
100
101 } else if (!S_ISREG(s.st_mode)) {
102 crm_trace("%s - wrong type (%#o)",
103 a->d_name, (unsigned int) (s.st_mode & S_IFMT));
104
105 } else if(strstr(a->d_name, "cib-") != a->d_name) {
106 crm_trace("%s - wrong prefix", a->d_name);
107
108 } else if (pcmk__ends_with_ext(a->d_name, ".sig")) {
109 crm_trace("%s - wrong suffix", a->d_name);
110
111 } else {
112 crm_debug("%s - candidate", a->d_name);
113 rc = 1;
114 }
115
116 free(a_path);
117 return rc;
118 }
119
120 static int cib_archive_sort(const struct dirent ** a, const struct dirent **b)
121 {
122
123 int rc = 0;
124 struct stat buf;
125
126 time_t a_age = 0;
127 time_t b_age = 0;
128
129 char *a_path = crm_strdup_printf("%s/%s", cib_root, a[0]->d_name);
130 char *b_path = crm_strdup_printf("%s/%s", cib_root, b[0]->d_name);
131
132 if(stat(a_path, &buf) == 0) {
133 a_age = buf.st_ctime;
134 }
135 if(stat(b_path, &buf) == 0) {
136 b_age = buf.st_ctime;
137 }
138
139 free(a_path);
140 free(b_path);
141
142 if(a_age > b_age) {
143 rc = 1;
144 } else if(a_age < b_age) {
145 rc = -1;
146 }
147
148 crm_trace("%s (%lu) vs. %s (%lu) : %d",
149 a[0]->d_name, (unsigned long)a_age,
150 b[0]->d_name, (unsigned long)b_age, rc);
151 return rc;
152 }
153
154 xmlNode *
155 readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
156 {
157 struct dirent **namelist = NULL;
158
159 int lpc = 0;
160 char *sigfile = NULL;
161 char *sigfilepath = NULL;
162 char *filename = NULL;
163 const char *name = NULL;
164 const char *value = NULL;
165 const char *use_valgrind = pcmk__env_option(PCMK__ENV_VALGRIND_ENABLED);
166
167 xmlNode *root = NULL;
168 xmlNode *status = NULL;
169
170 sigfile = crm_strdup_printf("%s.sig", file);
171 if (pcmk__daemon_can_write(dir, file) == FALSE
172 || pcmk__daemon_can_write(dir, sigfile) == FALSE) {
173 cib_status = -EACCES;
174 return NULL;
175 }
176
177 filename = crm_strdup_printf("%s/%s", dir, file);
178 sigfilepath = crm_strdup_printf("%s/%s", dir, sigfile);
179 free(sigfile);
180
181 cib_status = pcmk_ok;
182 root = retrieveCib(filename, sigfilepath);
183 free(filename);
184 free(sigfilepath);
185
186 if (root == NULL) {
187 lpc = scandir(cib_root, &namelist, cib_archive_filter, cib_archive_sort);
188 if (lpc < 0) {
189 crm_err("Could not check for CIB backups in %s: %s",
190 cib_root, pcmk_rc_str(errno));
191 }
192 }
193
194 while (root == NULL && lpc > 1) {
195 int rc = pcmk_ok;
196
197 lpc--;
198
199 filename = crm_strdup_printf("%s/%s", cib_root, namelist[lpc]->d_name);
200 sigfile = crm_strdup_printf("%s.sig", filename);
201
202 rc = cib_file_read_and_verify(filename, sigfile, &root);
203 if (rc == pcmk_ok) {
204 crm_notice("Loaded CIB from last valid backup %s (with digest %s)",
205 filename, sigfile);
206 } else {
207 crm_warn("Not using next most recent CIB backup from %s "
208 "(with digest %s): %s",
209 filename, sigfile, pcmk_strerror(rc));
210 }
211
212 free(namelist[lpc]);
213 free(filename);
214 free(sigfile);
215 }
216 free(namelist);
217
218 if (root == NULL) {
219 root = createEmptyCib(0);
220 crm_warn("Continuing with an empty configuration");
221 }
222
223 if (cib_writes_enabled && (use_valgrind != NULL)
224 && (crm_is_true(use_valgrind)
225 || (strstr(use_valgrind, PCMK__SERVER_BASED) != NULL))) {
226
227 cib_writes_enabled = FALSE;
228 crm_err("*** Disabling disk writes to avoid confusing Valgrind ***");
229 }
230
231 status = pcmk__xe_first_child(root, PCMK_XE_STATUS, NULL, NULL);
232 if (discard_status && status != NULL) {
233
234 pcmk__xml_free(status);
235 status = NULL;
236 }
237 if (status == NULL) {
238 pcmk__xe_create(root, PCMK_XE_STATUS);
239 }
240
241
242
243
244 value = crm_element_value(root, PCMK_XA_ADMIN_EPOCH);
245 if (value == NULL) {
246 crm_warn("Defaulting missing " PCMK_XA_ADMIN_EPOCH " to 0, but "
247 "cluster may get confused about which node's configuration "
248 "is most recent");
249 crm_xml_add_int(root, PCMK_XA_ADMIN_EPOCH, 0);
250 }
251
252 name = PCMK_XA_EPOCH;
253 value = crm_element_value(root, name);
254 if (value == NULL) {
255 crm_xml_add_int(root, name, 0);
256 }
257
258 name = PCMK_XA_NUM_UPDATES;
259 value = crm_element_value(root, name);
260 if (value == NULL) {
261 crm_xml_add_int(root, name, 0);
262 }
263
264
265 pcmk__xe_remove_attr(root, PCMK_XA_DC_UUID);
266
267 if (discard_status) {
268 crm_log_xml_trace(root, "[on-disk]");
269 }
270
271 if (!pcmk__configured_schema_validates(root)) {
272 cib_status = -pcmk_err_schema_validation;
273 }
274 return root;
275 }
276
277 gboolean
278 uninitializeCib(void)
279 {
280 xmlNode *tmp_cib = the_cib;
281
282 if (tmp_cib == NULL) {
283 return FALSE;
284 }
285 the_cib = NULL;
286 pcmk__xml_free(tmp_cib);
287 return TRUE;
288 }
289
290
291
292
293
294 int
295 activateCibXml(xmlNode * new_cib, gboolean to_disk, const char *op)
296 {
297 if (new_cib) {
298 xmlNode *saved_cib = the_cib;
299
300 pcmk__assert(new_cib != saved_cib);
301 the_cib = new_cib;
302 pcmk__xml_free(saved_cib);
303 if (cib_writes_enabled && cib_status == pcmk_ok && to_disk) {
304 crm_debug("Triggering CIB write for %s op", op);
305 mainloop_set_trigger(cib_writer);
306 }
307 return pcmk_ok;
308 }
309
310 crm_err("Ignoring invalid CIB");
311 if (the_cib) {
312 crm_warn("Reverting to last known CIB");
313 } else {
314 crm_crit("Could not write out new CIB and no saved version to revert to");
315 }
316 return -ENODATA;
317 }
318
319 static void
320 cib_diskwrite_complete(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
321 {
322 const char *errmsg = "Could not write CIB to disk";
323
324 if ((exitcode != 0) && cib_writes_enabled) {
325 cib_writes_enabled = FALSE;
326 errmsg = "Disabling CIB disk writes after failure";
327 }
328
329 if ((signo == 0) && (exitcode == 0)) {
330 crm_trace("Disk write [%d] succeeded", (int) pid);
331
332 } else if (signo == 0) {
333 crm_err("%s: process %d exited %d", errmsg, (int) pid, exitcode);
334
335 } else {
336 crm_err("%s: process %d terminated with signal %d (%s)%s",
337 errmsg, (int) pid, signo, strsignal(signo),
338 (core? " and dumped core" : ""));
339 }
340
341 mainloop_trigger_complete(cib_writer);
342 }
343
344 int
345 write_cib_contents(gpointer p)
346 {
347 int exit_rc = pcmk_ok;
348 xmlNode *cib_local = NULL;
349
350
351 if (p) {
352
353 cib_local = pcmk__xml_copy(NULL, p);
354
355 } else {
356 int pid = 0;
357 int bb_state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
358
359
360
361
362
363
364
365 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
366
367 pid = fork();
368 if (pid < 0) {
369 crm_err("Disabling disk writes after fork failure: %s", pcmk_rc_str(errno));
370 cib_writes_enabled = FALSE;
371 return FALSE;
372 }
373
374 if (pid) {
375
376 mainloop_child_add(pid, 0, "disk-writer", NULL, cib_diskwrite_complete);
377 if (bb_state == QB_LOG_STATE_ENABLED) {
378
379 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
380 }
381
382 return -1;
383 }
384
385
386
387
388
389
390 cib_local = pcmk__xml_copy(NULL, the_cib);
391 }
392
393
394 exit_rc = cib_file_write_with_digest(cib_local, cib_root, "cib.xml");
395
396
397 pcmk__xml_free(cib_local);
398 if (p == NULL) {
399 crm_exit_t exit_code = CRM_EX_OK;
400
401 switch (exit_rc) {
402 case pcmk_ok:
403 exit_code = CRM_EX_OK;
404 break;
405 case pcmk_err_cib_modified:
406 exit_code = CRM_EX_DIGEST;
407 break;
408 case pcmk_err_cib_backup:
409 case pcmk_err_cib_save:
410 exit_code = CRM_EX_CANTCREAT;
411 break;
412 default:
413 exit_code = CRM_EX_ERROR;
414 break;
415 }
416
417
418 pcmk_common_cleanup();
419 _exit(exit_code);
420 }
421 return exit_rc;
422 }