This source file includes following definitions.
- cib__get_operation
- cib_process_query
- update_counter
- cib_process_erase
- cib_process_upgrade
- cib_process_bump
- cib_process_replace
- delete_child
- cib_process_delete
- cib_process_modify
- add_cib_object
- update_results
- cib_process_create
- cib_process_diff
- 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 <glib.h>
23 #include <libxml/tree.h>
24 #include <libxml/xpath.h>
25
26 #include <crm/crm.h>
27 #include <crm/cib/internal.h>
28
29 #include <crm/common/xml.h>
30 #include <crm/common/xml_internal.h>
31
32
33 static GHashTable *operation_table = NULL;
34
35 static const cib__operation_t cib_ops[] = {
36 {
37 PCMK__CIB_REQUEST_ABS_DELETE, cib__op_abs_delete,
38 cib__op_attr_modifies|cib__op_attr_privileged
39 },
40 {
41 PCMK__CIB_REQUEST_APPLY_PATCH, cib__op_apply_patch,
42 cib__op_attr_modifies
43 |cib__op_attr_privileged
44 |cib__op_attr_transaction
45 },
46 {
47 PCMK__CIB_REQUEST_BUMP, cib__op_bump,
48 cib__op_attr_modifies
49 |cib__op_attr_privileged
50 |cib__op_attr_transaction
51 },
52 {
53 PCMK__CIB_REQUEST_COMMIT_TRANSACT, cib__op_commit_transact,
54 cib__op_attr_modifies
55 |cib__op_attr_privileged
56 |cib__op_attr_replaces
57 |cib__op_attr_writes_through
58 },
59 {
60 PCMK__CIB_REQUEST_CREATE, cib__op_create,
61 cib__op_attr_modifies
62 |cib__op_attr_privileged
63 |cib__op_attr_transaction
64 },
65 {
66 PCMK__CIB_REQUEST_DELETE, cib__op_delete,
67 cib__op_attr_modifies
68 |cib__op_attr_privileged
69 |cib__op_attr_transaction
70 },
71 {
72 PCMK__CIB_REQUEST_ERASE, cib__op_erase,
73 cib__op_attr_modifies
74 |cib__op_attr_privileged
75 |cib__op_attr_replaces
76 |cib__op_attr_transaction
77 },
78 {
79 PCMK__CIB_REQUEST_IS_PRIMARY, cib__op_is_primary,
80 cib__op_attr_privileged
81 },
82 {
83 PCMK__CIB_REQUEST_MODIFY, cib__op_modify,
84 cib__op_attr_modifies
85 |cib__op_attr_privileged
86 |cib__op_attr_transaction
87 },
88 {
89 PCMK__CIB_REQUEST_NOOP, cib__op_noop, cib__op_attr_none
90 },
91 {
92 CRM_OP_PING, cib__op_ping, cib__op_attr_none
93 },
94 {
95
96 PCMK__CIB_REQUEST_PRIMARY, cib__op_primary,
97 cib__op_attr_modifies|cib__op_attr_privileged|cib__op_attr_local
98 },
99 {
100 PCMK__CIB_REQUEST_QUERY, cib__op_query, cib__op_attr_none
101 },
102 {
103 PCMK__CIB_REQUEST_REPLACE, cib__op_replace,
104 cib__op_attr_modifies
105 |cib__op_attr_privileged
106 |cib__op_attr_replaces
107 |cib__op_attr_writes_through
108 |cib__op_attr_transaction
109 },
110 {
111 PCMK__CIB_REQUEST_SECONDARY, cib__op_secondary,
112 cib__op_attr_privileged|cib__op_attr_local
113 },
114 {
115 PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_privileged
116 },
117 {
118 PCMK__CIB_REQUEST_SYNC_TO_ALL, cib__op_sync_all, cib__op_attr_privileged
119 },
120 {
121 PCMK__CIB_REQUEST_SYNC_TO_ONE, cib__op_sync_one, cib__op_attr_privileged
122 },
123 {
124 PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade,
125 cib__op_attr_modifies
126 |cib__op_attr_privileged
127 |cib__op_attr_writes_through
128 |cib__op_attr_transaction
129 },
130 {
131 PCMK__CIB_REQUEST_SCHEMAS, cib__op_schemas, cib__op_attr_local
132 }
133 };
134
135
136
137
138
139
140
141
142
143
144 int
145 cib__get_operation(const char *op, const cib__operation_t **operation)
146 {
147 pcmk__assert((op != NULL) && (operation != NULL));
148
149 if (operation_table == NULL) {
150 operation_table = pcmk__strkey_table(NULL, NULL);
151
152 for (int lpc = 0; lpc < PCMK__NELEM(cib_ops); lpc++) {
153 const cib__operation_t *oper = &(cib_ops[lpc]);
154
155 g_hash_table_insert(operation_table, (gpointer) oper->name,
156 (gpointer) oper);
157 }
158 }
159
160 *operation = g_hash_table_lookup(operation_table, op);
161 if (*operation == NULL) {
162 crm_err("Operation %s is invalid", op);
163 return EINVAL;
164 }
165 return pcmk_rc_ok;
166 }
167
168 int
169 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
170 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
171 {
172 xmlNode *obj_root = NULL;
173 int result = pcmk_ok;
174
175 crm_trace("Processing %s for %s section",
176 op, pcmk__s(section, "unspecified"));
177
178 if (options & cib_xpath) {
179 return cib_process_xpath(op, options, section, req, input,
180 existing_cib, result_cib, answer);
181 }
182
183 CRM_CHECK(*answer == NULL, pcmk__xml_free(*answer));
184 *answer = NULL;
185
186 if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
187 section = NULL;
188 }
189
190 obj_root = pcmk_find_cib_element(existing_cib, section);
191
192 if (obj_root == NULL) {
193 result = -ENXIO;
194
195 } else if (options & cib_no_children) {
196 xmlNode *shallow = pcmk__xe_create(*answer,
197 (const char *) obj_root->name);
198
199 pcmk__xe_copy_attrs(shallow, obj_root, pcmk__xaf_none);
200 *answer = shallow;
201
202 } else {
203 *answer = obj_root;
204 }
205
206 if (result == pcmk_ok && *answer == NULL) {
207 crm_err("Error creating query response");
208 result = -ENOMSG;
209 }
210
211 return result;
212 }
213
214 static int
215 update_counter(xmlNode *xml_obj, const char *field, bool reset)
216 {
217 char *new_value = NULL;
218 char *old_value = NULL;
219 int int_value = -1;
220
221 if (!reset && crm_element_value(xml_obj, field) != NULL) {
222 old_value = crm_element_value_copy(xml_obj, field);
223 }
224 if (old_value != NULL) {
225 int_value = atoi(old_value);
226 new_value = pcmk__itoa(++int_value);
227 } else {
228 new_value = pcmk__str_copy("1");
229 }
230
231 crm_trace("Update %s from %s to %s",
232 field, pcmk__s(old_value, "unset"), new_value);
233 crm_xml_add(xml_obj, field, new_value);
234
235 free(new_value);
236 free(old_value);
237
238 return pcmk_ok;
239 }
240
241 int
242 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
243 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
244 {
245 int result = pcmk_ok;
246
247 crm_trace("Processing \"%s\" event", op);
248
249 if (*result_cib != existing_cib) {
250 pcmk__xml_free(*result_cib);
251 }
252 *result_cib = createEmptyCib(0);
253 pcmk__xe_copy_attrs(*result_cib, existing_cib, pcmk__xaf_none);
254 update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
255 *answer = NULL;
256
257 return result;
258 }
259
260 int
261 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
262 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
263 xmlNode ** answer)
264 {
265 int rc = 0;
266 const char *max_schema = crm_element_value(req, PCMK__XA_CIB_SCHEMA_MAX);
267 const char *original_schema = NULL;
268 const char *new_schema = NULL;
269
270 *answer = NULL;
271 crm_trace("Processing \"%s\" event with max=%s", op, max_schema);
272
273 original_schema = crm_element_value(existing_cib, PCMK_XA_VALIDATE_WITH);
274 rc = pcmk__update_schema(result_cib, max_schema, true,
275 !pcmk_is_set(options, cib_verbose));
276 rc = pcmk_rc2legacy(rc);
277 new_schema = crm_element_value(*result_cib, PCMK_XA_VALIDATE_WITH);
278
279 if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) {
280 update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
281 update_counter(*result_cib, PCMK_XA_EPOCH, true);
282 update_counter(*result_cib, PCMK_XA_NUM_UPDATES, true);
283 return pcmk_ok;
284 }
285
286 return rc;
287 }
288
289 int
290 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
291 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
292 {
293 int result = pcmk_ok;
294
295 crm_trace("Processing %s for epoch='%s'", op,
296 pcmk__s(crm_element_value(existing_cib, PCMK_XA_EPOCH), ""));
297
298 *answer = NULL;
299 update_counter(*result_cib, PCMK_XA_EPOCH, false);
300
301 return result;
302 }
303
304 int
305 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
306 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
307 xmlNode ** answer)
308 {
309 int result = pcmk_ok;
310
311 crm_trace("Processing %s for %s section",
312 op, pcmk__s(section, "unspecified"));
313
314 if (options & cib_xpath) {
315 return cib_process_xpath(op, options, section, req, input,
316 existing_cib, result_cib, answer);
317 }
318
319 *answer = NULL;
320
321 if (input == NULL) {
322 return -EINVAL;
323 }
324
325 if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
326 section = NULL;
327
328 } else if (pcmk__xe_is(input, section)) {
329 section = NULL;
330 }
331
332 if (pcmk__xe_is(input, PCMK_XE_CIB)) {
333 int updates = 0;
334 int epoch = 0;
335 int admin_epoch = 0;
336
337 int replace_updates = 0;
338 int replace_epoch = 0;
339 int replace_admin_epoch = 0;
340
341 const char *reason = NULL;
342 const char *peer = crm_element_value(req, PCMK__XA_SRC);
343 const char *digest = crm_element_value(req, PCMK__XA_DIGEST);
344
345 if (digest) {
346 char *digest_verify = pcmk__digest_xml(input, true);
347
348 if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
349 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
350 digest_verify, digest);
351 reason = "digest mismatch";
352
353 } else {
354 crm_info("Digest matched on replace from %s: %s", peer, digest);
355 }
356 free(digest_verify);
357
358 } else {
359 crm_trace("No digest to verify");
360 }
361
362 cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
363 cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
364
365 if (replace_admin_epoch < admin_epoch) {
366 reason = PCMK_XA_ADMIN_EPOCH;
367
368 } else if (replace_admin_epoch > admin_epoch) {
369
370
371 } else if (replace_epoch < epoch) {
372 reason = PCMK_XA_EPOCH;
373
374 } else if (replace_epoch > epoch) {
375
376
377 } else if (replace_updates < updates) {
378 reason = PCMK_XA_NUM_UPDATES;
379 }
380
381 if (reason != NULL) {
382 crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
383 " current %s is greater than the replacement",
384 replace_admin_epoch, replace_epoch,
385 replace_updates, peer, admin_epoch, epoch, updates, reason);
386 result = -pcmk_err_old_data;
387 } else {
388 crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
389 admin_epoch, epoch, updates,
390 replace_admin_epoch, replace_epoch, replace_updates, peer);
391 }
392
393 if (*result_cib != existing_cib) {
394 pcmk__xml_free(*result_cib);
395 }
396 *result_cib = pcmk__xml_copy(NULL, input);
397
398 } else {
399 xmlNode *obj_root = NULL;
400
401 obj_root = pcmk_find_cib_element(*result_cib, section);
402 result = pcmk__xe_replace_match(obj_root, input);
403 result = pcmk_rc2legacy(result);
404 if (result != pcmk_ok) {
405 crm_trace("No matching object to replace");
406 }
407 }
408
409 return result;
410 }
411
412 static int
413 delete_child(xmlNode *child, void *userdata)
414 {
415 xmlNode *obj_root = userdata;
416
417 if (pcmk__xe_delete_match(obj_root, child) != pcmk_rc_ok) {
418 crm_trace("No matching object to delete: %s=%s",
419 child->name, pcmk__xe_id(child));
420 }
421
422 return pcmk_rc_ok;
423 }
424
425 int
426 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
427 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
428 {
429 xmlNode *obj_root = NULL;
430
431 crm_trace("Processing \"%s\" event", op);
432
433 if (options & cib_xpath) {
434 return cib_process_xpath(op, options, section, req, input,
435 existing_cib, result_cib, answer);
436 }
437
438 if (input == NULL) {
439 crm_err("Cannot perform modification with no data");
440 return -EINVAL;
441 }
442
443 obj_root = pcmk_find_cib_element(*result_cib, section);
444 if (pcmk__xe_is(input, section)) {
445 pcmk__xe_foreach_child(input, NULL, delete_child, obj_root);
446 } else {
447 delete_child(input, obj_root);
448 }
449
450 return pcmk_ok;
451 }
452
453 int
454 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
455 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
456 {
457 xmlNode *obj_root = NULL;
458 uint32_t flags = pcmk__xaf_none;
459
460 crm_trace("Processing \"%s\" event", op);
461
462 if (options & cib_xpath) {
463 return cib_process_xpath(op, options, section, req, input,
464 existing_cib, result_cib, answer);
465 }
466
467 if (input == NULL) {
468 crm_err("Cannot perform modification with no data");
469 return -EINVAL;
470 }
471
472 obj_root = pcmk_find_cib_element(*result_cib, section);
473 if (obj_root == NULL) {
474 xmlNode *tmp_section = NULL;
475 const char *path = pcmk_cib_parent_name_for(section);
476
477 if (path == NULL) {
478 return -EINVAL;
479 }
480
481 tmp_section = pcmk__xe_create(NULL, section);
482 cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
483 NULL, result_cib, answer);
484 pcmk__xml_free(tmp_section);
485
486 obj_root = pcmk_find_cib_element(*result_cib, section);
487 }
488
489 CRM_CHECK(obj_root != NULL, return -EINVAL);
490
491 if (pcmk_is_set(options, cib_score_update)) {
492 flags |= pcmk__xaf_score_update;
493 }
494
495 if (pcmk__xe_update_match(obj_root, input, flags) != pcmk_rc_ok) {
496 if (options & cib_can_create) {
497 pcmk__xml_copy(obj_root, input);
498 } else {
499 return -ENXIO;
500 }
501 }
502
503 return pcmk_ok;
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
512 if ((parent == NULL) || (new_obj == NULL)) {
513 return -EINVAL;
514 }
515
516 object_name = (const char *) new_obj->name;
517 if (object_name == NULL) {
518 return -EINVAL;
519 }
520
521 object_id = pcmk__xe_id(new_obj);
522 if (pcmk__xe_first_child(parent, object_name,
523 ((object_id != NULL)? PCMK_XA_ID : NULL),
524 object_id)) {
525 return -EEXIST;
526 }
527
528 if (object_id != NULL) {
529 crm_trace("Processing creation of <%s " PCMK_XA_ID "='%s'>",
530 object_name, object_id);
531 } else {
532 crm_trace("Processing creation of <%s>", object_name);
533 }
534
535
536
537
538
539
540
541
542
543 pcmk__xml_tree_foreach(new_obj, pcmk__xe_remove_attr_cb,
544 (void *) PCMK__XA_REPLACE);
545
546 pcmk__xml_copy(parent, new_obj);
547 return pcmk_ok;
548 }
549
550 static bool
551 update_results(xmlNode *failed, xmlNode *target, const char *operation,
552 int return_code)
553 {
554 xmlNode *xml_node = NULL;
555 bool was_error = false;
556 const char *error_msg = NULL;
557
558 if (return_code != pcmk_ok) {
559 error_msg = pcmk_strerror(return_code);
560
561 was_error = true;
562 xml_node = pcmk__xe_create(failed, PCMK__XE_FAILED_UPDATE);
563 pcmk__xml_copy(xml_node, target);
564
565 crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(target));
566 crm_xml_add(xml_node, PCMK_XA_OBJECT_TYPE, (const char *) target->name);
567 crm_xml_add(xml_node, PCMK_XA_OPERATION, operation);
568 crm_xml_add(xml_node, PCMK_XA_REASON, error_msg);
569
570 crm_warn("Action %s failed: %s (cde=%d)",
571 operation, error_msg, return_code);
572 }
573
574 return was_error;
575 }
576
577 int
578 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
579 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
580 {
581 xmlNode *failed = NULL;
582 int result = pcmk_ok;
583 xmlNode *update_section = NULL;
584
585 crm_trace("Processing %s for %s section",
586 op, pcmk__s(section, "unspecified"));
587 if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
588 section = NULL;
589
590 } else if (pcmk__str_eq(section, PCMK_XE_CIB, pcmk__str_casei)) {
591 section = NULL;
592
593 } else if (pcmk__xe_is(input, PCMK_XE_CIB)) {
594 section = NULL;
595 }
596
597 CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
598
599 if (input == NULL) {
600 crm_err("Cannot perform modification with no data");
601 return -EINVAL;
602 }
603
604 if (section == NULL) {
605 return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
606 answer);
607 }
608
609
610 failed = pcmk__xe_create(NULL, PCMK__XE_FAILED);
611
612 update_section = pcmk_find_cib_element(*result_cib, section);
613 if (pcmk__xe_is(input, section)) {
614 xmlNode *a_child = NULL;
615
616 for (a_child = pcmk__xml_first_child(input); a_child != NULL;
617 a_child = pcmk__xml_next(a_child)) {
618 result = add_cib_object(update_section, a_child);
619 if (update_results(failed, a_child, op, result)) {
620 break;
621 }
622 }
623
624 } else {
625 result = add_cib_object(update_section, input);
626 update_results(failed, input, op, result);
627 }
628
629 if ((result == pcmk_ok) && (failed->children != NULL)) {
630 result = -EINVAL;
631 }
632
633 if (result != pcmk_ok) {
634 crm_log_xml_err(failed, "CIB Update failures");
635 *answer = failed;
636
637 } else {
638 pcmk__xml_free(failed);
639 }
640
641 return result;
642 }
643
644 int
645 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
646 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
647 {
648 const char *originator = NULL;
649
650 if (req != NULL) {
651 originator = crm_element_value(req, PCMK__XA_SRC);
652 }
653
654 crm_trace("Processing \"%s\" event from %s%s",
655 op, originator,
656 (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
657
658 if (*result_cib != existing_cib) {
659 pcmk__xml_free(*result_cib);
660 }
661 *result_cib = pcmk__xml_copy(NULL, existing_cib);
662
663 return xml_apply_patchset(*result_cib, input, TRUE);
664 }
665
666 int
667 cib_process_xpath(const char *op, int options, const char *section,
668 const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
669 xmlNode **result_cib, xmlNode **answer)
670 {
671 int num_results = 0;
672 int rc = pcmk_ok;
673 bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
674 bool delete_multiple = pcmk_is_set(options, cib_multiple)
675 && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE,
676 pcmk__str_none);
677 xmlXPathObject *xpathObj = NULL;
678
679 crm_trace("Processing \"%s\" event", op);
680
681 if (is_query) {
682 xpathObj = pcmk__xpath_search(existing_cib->doc, section);
683 } else {
684 xpathObj = pcmk__xpath_search((*result_cib)->doc, section);
685 }
686
687 num_results = pcmk__xpath_num_results(xpathObj);
688 if (num_results == 0) {
689 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
690 crm_debug("%s was already removed", section);
691
692 } else {
693 crm_debug("%s: %s does not exist", op, section);
694 rc = -ENXIO;
695 }
696 goto done;
697 }
698
699 if (is_query && (num_results > 1)) {
700 *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
701 }
702
703 for (int i = 0; i < num_results; i++) {
704 xmlNode *match = NULL;
705 xmlChar *path = NULL;
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723 if (delete_multiple) {
724 match = pcmk__xpath_result(xpathObj, num_results - 1 - i);
725 } else {
726 match = pcmk__xpath_result(xpathObj, i);
727 }
728
729 if (match == NULL) {
730 continue;
731 }
732
733 path = xmlGetNodePath(match);
734 crm_debug("Processing %s op for %s with %s", op, section, path);
735 free(path);
736
737 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
738 if (match == *result_cib) {
739
740 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
741 rc = -EINVAL;
742 break;
743 }
744
745 pcmk__xml_free(match);
746 if ((options & cib_multiple) == 0) {
747 break;
748 }
749
750 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
751 uint32_t flags = pcmk__xaf_none;
752
753 if (pcmk_is_set(options, cib_score_update)) {
754 flags |= pcmk__xaf_score_update;
755 }
756
757 if (pcmk__xe_update_match(match, input, flags) != pcmk_rc_ok) {
758 rc = -ENXIO;
759 } else if ((options & cib_multiple) == 0) {
760 break;
761 }
762
763 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
764 pcmk__xml_copy(match, input);
765 break;
766
767 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
768
769 if (options & cib_no_children) {
770 xmlNode *shallow = pcmk__xe_create(*answer,
771 (const char *) match->name);
772
773 pcmk__xe_copy_attrs(shallow, match, pcmk__xaf_none);
774
775 if (*answer == NULL) {
776 *answer = shallow;
777 }
778
779 } else if (options & cib_xpath_address) {
780 char *path = NULL;
781 xmlNode *parent = match;
782
783 while (parent && parent->type == XML_ELEMENT_NODE) {
784 const char *id = crm_element_value(parent, PCMK_XA_ID);
785 char *new_path = NULL;
786
787 if (id) {
788 new_path = crm_strdup_printf("/%s[@" PCMK_XA_ID "='%s']"
789 "%s",
790 parent->name, id,
791 pcmk__s(path, ""));
792 } else {
793 new_path = crm_strdup_printf("/%s%s", parent->name,
794 pcmk__s(path, ""));
795 }
796 free(path);
797 path = new_path;
798 parent = parent->parent;
799 }
800 crm_trace("Got: %s", path);
801
802 if (*answer == NULL) {
803 *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
804 }
805 parent = pcmk__xe_create(*answer, PCMK__XE_XPATH_QUERY_PATH);
806 crm_xml_add(parent, PCMK_XA_ID, path);
807 free(path);
808
809 } else if (*answer) {
810 pcmk__xml_copy(*answer, match);
811
812 } else {
813 *answer = match;
814 }
815
816 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
817 pcmk__str_none)) {
818 xmlNode *parent = match->parent;
819
820 pcmk__xml_free(match);
821 pcmk__xml_copy(parent, input);
822
823 if ((options & cib_multiple) == 0) {
824 break;
825 }
826 }
827 }
828
829 done:
830 xmlXPathFreeObject(xpathObj);
831 return rc;
832 }