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