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