This source file includes following definitions.
- cib_process_query
- cib_process_erase
- cib_process_upgrade
- cib_process_bump
- cib_update_counter
- cib_process_replace
- cib_process_delete
- cib_process_modify
- update_cib_object
- add_cib_object
- cib_process_create
- cib_process_diff
- cib_config_changed
- cib_process_xpath
- update_results
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 <stdlib.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <time.h>
27
28 #include <sys/param.h>
29 #include <sys/types.h>
30
31 #include <crm/crm.h>
32 #include <crm/cib/internal.h>
33 #include <crm/msg_xml.h>
34
35 #include <crm/common/xml.h>
36
37 int
38 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
39 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
40 {
41 xmlNode *obj_root = NULL;
42 int result = pcmk_ok;
43
44 crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
45
46 if (options & cib_xpath) {
47 return cib_process_xpath(op, options, section, req, input,
48 existing_cib, result_cib, answer);
49 }
50
51 CRM_CHECK(*answer == NULL, free_xml(*answer));
52 *answer = NULL;
53
54 if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
55 section = NULL;
56 }
57
58 obj_root = get_object_root(section, existing_cib);
59
60 if (obj_root == NULL) {
61 result = -ENXIO;
62
63 } else if (options & cib_no_children) {
64 const char *tag = TYPE(obj_root);
65 xmlNode *shallow = create_xml_node(*answer, tag);
66
67 copy_in_properties(shallow, obj_root);
68 *answer = shallow;
69
70 } else {
71 *answer = obj_root;
72 }
73
74 if (result == pcmk_ok && *answer == NULL) {
75 crm_err("Error creating query response");
76 result = -ENOMSG;
77 }
78
79 return result;
80 }
81
82 int
83 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
84 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
85 {
86 int result = pcmk_ok;
87
88 crm_trace("Processing \"%s\" event", op);
89 *answer = NULL;
90 free_xml(*result_cib);
91 *result_cib = createEmptyCib(0);
92
93 copy_in_properties(*result_cib, existing_cib);
94 cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
95
96 return result;
97 }
98
99 int
100 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
101 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
102 xmlNode ** answer)
103 {
104 int rc = 0;
105 int new_version = 0;
106 int current_version = 0;
107 int max_version = 0;
108 const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
109 const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
110
111 *answer = NULL;
112 crm_trace("Processing \"%s\" event with max=%s", op, max);
113
114 if (value != NULL) {
115 current_version = get_schema_version(value);
116 }
117
118 if (max) {
119 max_version = get_schema_version(max);
120 }
121
122 rc = update_validation(result_cib, &new_version, max_version, TRUE, TRUE);
123 if (new_version > current_version) {
124 cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
125 cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
126 cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
127 return pcmk_ok;
128 }
129
130 return rc;
131 }
132
133 int
134 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
135 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
136 {
137 int result = pcmk_ok;
138
139 crm_trace("Processing \"%s\" event for epoch=%s",
140 op, crm_str(crm_element_value(existing_cib, XML_ATTR_GENERATION)));
141
142 *answer = NULL;
143 cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
144
145 return result;
146 }
147
148 int
149 cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
150 {
151 char *new_value = NULL;
152 char *old_value = NULL;
153 int int_value = -1;
154
155 if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
156 old_value = crm_element_value_copy(xml_obj, field);
157 }
158 if (old_value != NULL) {
159 new_value = calloc(1, 128);
160 int_value = atoi(old_value);
161 sprintf(new_value, "%d", ++int_value);
162 } else {
163 new_value = strdup("1");
164 }
165
166 crm_trace("%s %d(%s)->%s", field, int_value, crm_str(old_value), crm_str(new_value));
167 crm_xml_add(xml_obj, field, new_value);
168
169 free(new_value);
170 free(old_value);
171
172 return pcmk_ok;
173 }
174
175 int
176 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
177 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
178 xmlNode ** answer)
179 {
180 const char *tag = NULL;
181 int result = pcmk_ok;
182
183 crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
184
185 if (options & cib_xpath) {
186 return cib_process_xpath(op, options, section, req, input,
187 existing_cib, result_cib, answer);
188 }
189
190 *answer = NULL;
191
192 if (input == NULL) {
193 return -EINVAL;
194 }
195
196 tag = crm_element_name(input);
197
198 if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
199 section = NULL;
200
201 } else if (safe_str_eq(tag, section)) {
202 section = NULL;
203 }
204
205 if (safe_str_eq(tag, XML_TAG_CIB)) {
206 int updates = 0;
207 int epoch = 0;
208 int admin_epoch = 0;
209
210 int replace_updates = 0;
211 int replace_epoch = 0;
212 int replace_admin_epoch = 0;
213
214 const char *reason = NULL;
215 const char *peer = crm_element_value(req, F_ORIG);
216 const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
217
218 if (digest) {
219 const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
220 char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
221 version ? version :
222 CRM_FEATURE_SET);
223
224 if (safe_str_neq(digest_verify, digest)) {
225 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
226 digest_verify, digest);
227 reason = "digest mismatch";
228
229 } else {
230 crm_info("Digest matched on replace from %s: %s", peer, digest);
231 }
232 free(digest_verify);
233
234 } else {
235 crm_trace("No digest to verify");
236 }
237
238 cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
239 cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
240
241 if (replace_admin_epoch < admin_epoch) {
242 reason = XML_ATTR_GENERATION_ADMIN;
243
244 } else if (replace_admin_epoch > admin_epoch) {
245
246
247 } else if (replace_epoch < epoch) {
248 reason = XML_ATTR_GENERATION;
249
250 } else if (replace_epoch > epoch) {
251
252
253 } else if (replace_updates < updates) {
254 reason = XML_ATTR_NUMUPDATES;
255 }
256
257 if (reason != NULL) {
258 crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
259 " current %s is greater than the replacement",
260 replace_admin_epoch, replace_epoch,
261 replace_updates, peer, admin_epoch, epoch, updates, reason);
262 result = -pcmk_err_old_data;
263 } else {
264 crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
265 admin_epoch, epoch, updates,
266 replace_admin_epoch, replace_epoch, replace_updates, peer);
267 }
268
269 free_xml(*result_cib);
270 *result_cib = copy_xml(input);
271
272 } else {
273 xmlNode *obj_root = NULL;
274 gboolean ok = TRUE;
275
276 obj_root = get_object_root(section, *result_cib);
277 ok = replace_xml_child(NULL, obj_root, input, FALSE);
278 if (ok == FALSE) {
279 crm_trace("No matching object to replace");
280 result = -ENXIO;
281 }
282 }
283
284 return result;
285 }
286
287 int
288 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
289 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
290 {
291 xmlNode *obj_root = NULL;
292
293 crm_trace("Processing \"%s\" event", op);
294
295 if (options & cib_xpath) {
296 return cib_process_xpath(op, options, section, req, input,
297 existing_cib, result_cib, answer);
298 }
299
300 if (input == NULL) {
301 crm_err("Cannot perform modification with no data");
302 return -EINVAL;
303 }
304
305 obj_root = get_object_root(section, *result_cib);
306 if(safe_str_eq(crm_element_name(input), section)) {
307 xmlNode *child = NULL;
308 for(child = __xml_first_child(input); child; child = __xml_next(child)) {
309 if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
310 crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
311 }
312 }
313
314 } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
315 crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
316 }
317
318 return pcmk_ok;
319 }
320
321 int
322 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
323 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
324 {
325 xmlNode *obj_root = NULL;
326
327 crm_trace("Processing \"%s\" event", op);
328
329 if (options & cib_xpath) {
330 return cib_process_xpath(op, options, section, req, input,
331 existing_cib, result_cib, answer);
332 }
333
334 if (input == NULL) {
335 crm_err("Cannot perform modification with no data");
336 return -EINVAL;
337 }
338
339 obj_root = get_object_root(section, *result_cib);
340 if (obj_root == NULL) {
341 xmlNode *tmp_section = NULL;
342 const char *path = get_object_parent(section);
343
344 if (path == NULL) {
345 return -EINVAL;
346 }
347
348 tmp_section = create_xml_node(NULL, section);
349 cib_process_xpath(CIB_OP_CREATE, 0, path, NULL, tmp_section, NULL, result_cib, answer);
350 free_xml(tmp_section);
351
352 obj_root = get_object_root(section, *result_cib);
353 }
354
355 CRM_CHECK(obj_root != NULL, return -EINVAL);
356
357 if (update_xml_child(obj_root, input) == FALSE) {
358 if (options & cib_can_create) {
359 add_node_copy(obj_root, input);
360 } else {
361 return -ENXIO;
362 }
363 }
364
365 if(options & cib_mixed_update) {
366 int max = 0, lpc;
367 xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
368
369 if (xpathObj) {
370 max = numXpathResults(xpathObj);
371 crm_log_xml_trace(*result_cib, "Mixed result");
372 }
373
374 for (lpc = 0; lpc < max; lpc++) {
375 xmlNode *match = getXpathResult(xpathObj, lpc);
376 xmlChar *match_path = xmlGetNodePath(match);
377
378 crm_debug("Destroying %s", match_path);
379 free(match_path);
380 free_xml(match);
381 }
382
383 freeXpathObject(xpathObj);
384 }
385 return pcmk_ok;
386 }
387
388 static int
389 update_cib_object(xmlNode * parent, xmlNode * update)
390 {
391 int result = pcmk_ok;
392 xmlNode *target = NULL;
393 xmlNode *a_child = NULL;
394 const char *replace = NULL;
395 const char *object_id = NULL;
396 const char *object_name = NULL;
397
398 CRM_CHECK(update != NULL, return -EINVAL);
399 CRM_CHECK(parent != NULL, return -EINVAL);
400
401 object_name = crm_element_name(update);
402 CRM_CHECK(object_name != NULL, return -EINVAL);
403
404 object_id = ID(update);
405 crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
406
407 if (object_id == NULL) {
408
409 target = find_xml_node(parent, object_name, FALSE);
410
411 } else {
412 target = find_entity(parent, object_name, object_id);
413 }
414
415 if (target == NULL) {
416 target = create_xml_node(parent, object_name);
417 }
418
419 crm_trace("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id));
420
421 replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
422 if (replace != NULL) {
423 xmlNode *remove = NULL;
424 int last = 0, lpc = 0, len = 0;
425
426 len = strlen(replace);
427 while (lpc <= len) {
428 if (replace[lpc] == ',' || replace[lpc] == 0) {
429 char *replace_item = NULL;
430
431 if (last == lpc) {
432
433 last = lpc + 1;
434 goto incr;
435 }
436
437 replace_item = calloc(1, lpc - last + 1);
438 memcpy(replace_item, replace + last, lpc - last);
439
440 remove = find_xml_node(target, replace_item, FALSE);
441 if (remove != NULL) {
442 crm_trace("Replacing node <%s> in <%s>",
443 replace_item, crm_element_name(target));
444 free_xml(remove);
445 remove = NULL;
446 }
447 free(replace_item);
448 last = lpc + 1;
449 }
450 incr:
451 lpc++;
452 }
453 xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
454 xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
455 }
456
457 copy_in_properties(target, update);
458
459 crm_trace("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id));
460
461 for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
462 int tmp_result = 0;
463
464 crm_trace("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
465
466 tmp_result = update_cib_object(target, a_child);
467
468
469 if (tmp_result != pcmk_ok) {
470 crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
471
472 if (result == pcmk_ok) {
473 result = tmp_result;
474 }
475 }
476 }
477
478 crm_trace("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id));
479
480 return result;
481 }
482
483 static int
484 add_cib_object(xmlNode * parent, xmlNode * new_obj)
485 {
486 int result = pcmk_ok;
487 const char *object_name = NULL;
488 const char *object_id = NULL;
489 xmlNode *equiv_node = NULL;
490
491 if (new_obj != NULL) {
492 object_name = crm_element_name(new_obj);
493 }
494 object_id = crm_element_value(new_obj, XML_ATTR_ID);
495
496 crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
497
498 if (new_obj == NULL || object_name == NULL) {
499 result = -EINVAL;
500
501 } else if (parent == NULL) {
502 result = -EINVAL;
503
504 } else if (object_id == NULL) {
505
506 equiv_node = find_xml_node(parent, object_name, FALSE);
507
508 } else {
509 equiv_node = find_entity(parent, object_name, object_id);
510 }
511
512 if (result != pcmk_ok) {
513 ;
514
515 } else if (equiv_node != NULL) {
516 result = -ENOTUNIQ;
517
518 } else {
519 result = update_cib_object(parent, new_obj);
520 }
521
522 return result;
523 }
524
525 int
526 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
527 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
528 {
529 xmlNode *failed = NULL;
530 int result = pcmk_ok;
531 xmlNode *update_section = NULL;
532
533 crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
534 if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
535 section = NULL;
536
537 } else if (safe_str_eq(XML_TAG_CIB, section)) {
538 section = NULL;
539
540 } else if (safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
541 section = NULL;
542 }
543
544 CRM_CHECK(strcasecmp(CIB_OP_CREATE, op) == 0, return -EINVAL);
545
546 if (input == NULL) {
547 crm_err("Cannot perform modification with no data");
548 return -EINVAL;
549 }
550
551 if (section == NULL) {
552 return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
553 answer);
554 }
555
556 failed = create_xml_node(NULL, XML_TAG_FAILED);
557
558 update_section = get_object_root(section, *result_cib);
559 if (safe_str_eq(crm_element_name(input), section)) {
560 xmlNode *a_child = NULL;
561
562 for (a_child = __xml_first_child(input); a_child != NULL; a_child = __xml_next(a_child)) {
563 result = add_cib_object(update_section, a_child);
564 if (update_results(failed, a_child, op, result)) {
565 break;
566 }
567 }
568
569 } else {
570 result = add_cib_object(update_section, input);
571 update_results(failed, input, op, result);
572 }
573
574 if (xml_has_children(failed)) {
575 CRM_CHECK(result != pcmk_ok, result = -EINVAL);
576 }
577
578 if (result != pcmk_ok) {
579 crm_log_xml_err(failed, "CIB Update failures");
580 *answer = failed;
581
582 } else {
583 free_xml(failed);
584 }
585
586 return result;
587 }
588
589 int
590 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
591 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
592 {
593 const char *originator = NULL;
594
595 if (req != NULL) {
596 originator = crm_element_value(req, F_ORIG);
597 }
598
599 crm_trace("Processing \"%s\" event from %s %s",
600 op, originator, is_set(options, cib_force_diff)?"(global update)":"");
601
602 free_xml(*result_cib);
603 *result_cib = copy_xml(existing_cib);
604 return xml_apply_patchset(*result_cib, input, TRUE);
605 }
606
607 gboolean
608 cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
609 {
610 int lpc = 0, max = 0;
611 gboolean config_changes = FALSE;
612 xmlXPathObject *xpathObj = NULL;
613 int format = 1;
614
615 CRM_ASSERT(diff != NULL);
616
617 if (*diff == NULL && last != NULL && next != NULL) {
618 *diff = diff_xml_object(last, next, FALSE);
619 }
620
621 if (*diff == NULL) {
622 goto done;
623 }
624
625 crm_element_value_int(*diff, "format", &format);
626
627 CRM_LOG_ASSERT(format == 1);
628
629 xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
630 if (numXpathResults(xpathObj) > 0) {
631 config_changes = TRUE;
632 goto done;
633 }
634 freeXpathObject(xpathObj);
635
636
637
638
639
640
641 xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
642 max = numXpathResults(xpathObj);
643
644 for (lpc = 0; lpc < max; lpc++) {
645 xmlNode *top = getXpathResult(xpathObj, lpc);
646
647 if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
648 config_changes = TRUE;
649 goto done;
650 }
651 if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
652 config_changes = TRUE;
653 goto done;
654 }
655
656 if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
657 config_changes = TRUE;
658 goto done;
659 }
660 if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
661 config_changes = TRUE;
662 goto done;
663 }
664 if (crm_element_value(top, "remote-clear-port") != NULL) {
665 config_changes = TRUE;
666 goto done;
667 }
668 if (crm_element_value(top, "remote-tls-port") != NULL) {
669 config_changes = TRUE;
670 goto done;
671 }
672 }
673
674 done:
675 freeXpathObject(xpathObj);
676 return config_changes;
677 }
678
679 int
680 cib_process_xpath(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
681 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
682 {
683 int lpc = 0;
684 int max = 0;
685 int rc = pcmk_ok;
686 gboolean is_query = safe_str_eq(op, CIB_OP_QUERY);
687
688 xmlXPathObjectPtr xpathObj = NULL;
689
690 crm_trace("Processing \"%s\" event", op);
691
692 if (is_query) {
693 xpathObj = xpath_search(existing_cib, section);
694 } else {
695 xpathObj = xpath_search(*result_cib, section);
696 }
697
698 max = numXpathResults(xpathObj);
699
700 if (max < 1 && safe_str_eq(op, CIB_OP_DELETE)) {
701 crm_debug("%s was already removed", section);
702
703 } else if (max < 1) {
704 crm_debug("%s: %s does not exist", op, section);
705 rc = -ENXIO;
706
707 } else if (is_query) {
708 if (max > 1) {
709 *answer = create_xml_node(NULL, "xpath-query");
710 }
711 }
712
713 if (safe_str_eq(op, CIB_OP_DELETE) && (options & cib_multiple)) {
714 dedupXpathResults(xpathObj);
715 }
716
717 for (lpc = 0; lpc < max; lpc++) {
718 xmlChar *path = NULL;
719 xmlNode *match = getXpathResult(xpathObj, lpc);
720
721 if (match == NULL) {
722 continue;
723 }
724
725 path = xmlGetNodePath(match);
726 crm_debug("Processing %s op for %s with %s", op, section, path);
727 free(path);
728
729 if (safe_str_eq(op, CIB_OP_DELETE)) {
730 if (match == *result_cib) {
731
732 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
733 rc = -EINVAL;
734 break;
735 }
736
737 free_xml(match);
738 if ((options & cib_multiple) == 0) {
739 break;
740 }
741
742 } else if (safe_str_eq(op, CIB_OP_MODIFY)) {
743 if (update_xml_child(match, input) == FALSE) {
744 rc = -ENXIO;
745 } else if ((options & cib_multiple) == 0) {
746 break;
747 }
748
749 } else if (safe_str_eq(op, CIB_OP_CREATE)) {
750 add_node_copy(match, input);
751 break;
752
753 } else if (safe_str_eq(op, CIB_OP_QUERY)) {
754
755 if (options & cib_no_children) {
756 const char *tag = TYPE(match);
757 xmlNode *shallow = create_xml_node(*answer, tag);
758
759 copy_in_properties(shallow, match);
760
761 if (*answer == NULL) {
762 *answer = shallow;
763 }
764
765 } else if (options & cib_xpath_address) {
766
767 int path_len = 0;
768 char *path = NULL;
769 xmlNode *parent = match;
770
771 while (parent && parent->type == XML_ELEMENT_NODE) {
772 int extra = 1;
773 char *new_path = NULL;
774 const char *id = crm_element_value(parent, XML_ATTR_ID);
775
776 extra += strlen((const char *)parent->name);
777 if (id) {
778 extra += 8;
779 extra += strlen(id);
780 }
781
782 path_len += extra;
783 new_path = malloc(path_len + 1);
784 if(new_path == NULL) {
785 break;
786
787 } else if (id) {
788 snprintf(new_path, path_len + 1, "/%s[@id='%s']%s", parent->name, id,
789 path ? path : "");
790 } else {
791 snprintf(new_path, path_len + 1, "/%s%s", parent->name, path ? path : "");
792 }
793 free(path);
794 path = new_path;
795 parent = parent->parent;
796 }
797 crm_trace("Got: %s", path);
798
799 if (*answer == NULL) {
800 *answer = create_xml_node(NULL, "xpath-query");
801 }
802 parent = create_xml_node(*answer, "xpath-query-path");
803 crm_xml_add(parent, XML_ATTR_ID, path);
804 free(path);
805
806 } else if (*answer) {
807 add_node_copy(*answer, match);
808
809 } else {
810 *answer = match;
811 }
812
813 } else if (safe_str_eq(op, CIB_OP_REPLACE)) {
814 xmlNode *parent = match->parent;
815
816 free_xml(match);
817 if (input != NULL) {
818 add_node_copy(parent, input);
819 }
820
821 if ((options & cib_multiple) == 0) {
822 break;
823 }
824 }
825 }
826
827 freeXpathObject(xpathObj);
828 return rc;
829 }
830
831
832 gboolean
833 update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
834 {
835 xmlNode *xml_node = NULL;
836 gboolean was_error = FALSE;
837 const char *error_msg = NULL;
838
839 if (return_code != pcmk_ok) {
840 error_msg = pcmk_strerror(return_code);
841
842 was_error = TRUE;
843 xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
844 add_node_copy(xml_node, target);
845
846 crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
847 crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
848 crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
849 crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
850
851 crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
852 }
853
854 return was_error;
855 }