This source file includes following definitions.
- print_xml_output
- report_schema_unchanged
- main
- do_work
- do_init
- cibadmin_op_callback
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <stdio.h>
12 #include <crm/crm.h>
13 #include <crm/msg_xml.h>
14 #include <crm/common/xml.h>
15 #include <crm/common/ipc.h>
16 #include <crm/cib/internal.h>
17
18 #include <pacemaker-internal.h>
19
20 static int message_timeout_ms = 30;
21 static int command_options = 0;
22 static int request_id = 0;
23 static int bump_log_num = 0;
24
25 static char *host = NULL;
26 static const char *cib_user = NULL;
27 static const char *cib_action = NULL;
28 static const char *obj_type = NULL;
29
30 static cib_t *the_cib = NULL;
31 static GMainLoop *mainloop = NULL;
32 static gboolean force_flag = FALSE;
33 static crm_exit_t exit_code = CRM_EX_OK;
34
35 int do_init(void);
36 int do_work(xmlNode *input, int command_options, xmlNode **output);
37 void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
38 void *user_data);
39
40 static pcmk__cli_option_t long_options[] = {
41
42 {
43 "help", no_argument, NULL, '?',
44 "\tThis text", pcmk__option_default
45 },
46 {
47 "version", no_argument, NULL, '$',
48 "\tVersion information", pcmk__option_default
49 },
50 {
51 "verbose", no_argument, NULL, 'V',
52 "\tIncrease debug output\n", pcmk__option_default
53 },
54
55 {
56 "-spacer-", no_argument, NULL, '-',
57 "Commands:", pcmk__option_default
58 },
59 {
60 "upgrade", no_argument, NULL, 'u',
61 "\tUpgrade the configuration to the latest syntax", pcmk__option_default
62 },
63 {
64 "query", no_argument, NULL, 'Q',
65 "\tQuery the contents of the CIB", pcmk__option_default
66 },
67 {
68 "erase", no_argument, NULL, 'E',
69 "\tErase the contents of the whole CIB", pcmk__option_default
70 },
71 {
72 "bump", no_argument, NULL, 'B',
73 "\tIncrease the CIB's epoch value by 1", pcmk__option_default
74 },
75 {
76 "create", no_argument, NULL, 'C',
77 "\tCreate an object in the CIB (will fail if object already exists)",
78 pcmk__option_default
79 },
80 {
81 "modify", no_argument, NULL, 'M',
82 "\tFind object somewhere in CIB's XML tree and update it "
83 "(fails if object does not exist unless -c is also specified)",
84 pcmk__option_default
85 },
86 {
87 "patch", no_argument, NULL, 'P',
88 "\tSupply an update in the form of an XML diff (see crm_diff(8))",
89 pcmk__option_default
90 },
91 {
92 "replace", no_argument, NULL, 'R',
93 "\tRecursively replace an object in the CIB", pcmk__option_default
94 },
95 {
96 "delete", no_argument, NULL, 'D',
97 "\tDelete first object matching supplied criteria "
98 "(for example, <op id=\"rsc1_op1\" name=\"monitor\"/>)",
99 pcmk__option_default
100 },
101 {
102 "-spacer-", no_argument, NULL, '-',
103 "\n\tThe XML element name and all attributes must match "
104 "in order for the element to be deleted.\n",
105 pcmk__option_default
106 },
107 {
108 "delete-all", no_argument, NULL, 'd',
109 "When used with --xpath, remove all matching objects in the "
110 "configuration instead of just the first one",
111 pcmk__option_default
112 },
113 {
114 "empty", no_argument, NULL, 'a',
115 "\tOutput an empty CIB", pcmk__option_default
116 },
117 {
118 "md5-sum", no_argument, NULL, '5',
119 "\tCalculate the on-disk CIB digest", pcmk__option_default
120 },
121 {
122 "md5-sum-versioned", no_argument, NULL, '6',
123 "Calculate an on-the-wire versioned CIB digest", pcmk__option_default
124 },
125 {
126 "show-access", optional_argument, NULL, 'S',
127 "Whether to use syntax highlighting for ACLs "
128 "(with -Q/--query and -U/--user)",
129 pcmk__option_default
130 },
131 {
132 "-spacer-", no_argument, NULL, '-',
133 "\n\tThat amounts to one of \"color\" (default for terminal),"
134 " \"text\" (otherwise), \"namespace\", or \"auto\""
135 " (per former defaults).",
136 pcmk__option_default
137 },
138 {
139 "blank", no_argument, NULL, '-',
140 NULL, pcmk__option_hidden
141 },
142
143 {
144 "-spacer-", required_argument, NULL, '-',
145 "\nAdditional options:", pcmk__option_default
146 },
147 {
148 "force", no_argument, NULL, 'f',
149 NULL, pcmk__option_default
150 },
151 {
152 "timeout", required_argument, NULL, 't',
153 "Time (in seconds) to wait before declaring the operation failed",
154 pcmk__option_default
155 },
156 {
157 "user", required_argument, NULL, 'U',
158 "Run the command with permissions of the named user (valid only for "
159 "the root and " CRM_DAEMON_USER " accounts)",
160 pcmk__option_default
161 },
162 {
163 "sync-call", no_argument, NULL, 's',
164 "Wait for call to complete before returning", pcmk__option_default
165 },
166 {
167 "local", no_argument, NULL, 'l',
168 "\tCommand takes effect locally (should be used only for queries)",
169 pcmk__option_default
170 },
171 {
172 "allow-create", no_argument, NULL, 'c',
173 "(Advanced) Allow target of --modify/-M to be created "
174 "if it does not exist",
175 pcmk__option_default
176 },
177 {
178 "no-children", no_argument, NULL, 'n',
179 "(Advanced) When querying an object, do not include its children "
180 "in the result",
181 pcmk__option_default
182 },
183 {
184 "no-bcast", no_argument, NULL, 'b',
185 NULL, pcmk__option_hidden
186 },
187
188 {
189 "-spacer-", no_argument, NULL, '-',
190 "\nData:", pcmk__option_default
191 },
192 {
193 "xml-text", required_argument, NULL, 'X',
194 "Retrieve XML from the supplied string", pcmk__option_default
195 },
196 {
197 "xml-file", required_argument, NULL, 'x',
198 "Retrieve XML from the named file", pcmk__option_default
199 },
200 {
201 "xml-pipe", no_argument, NULL, 'p',
202 "Retrieve XML from stdin\n", pcmk__option_default
203 },
204
205 {
206 "scope", required_argument, NULL, 'o',
207 "Limit scope of operation to specific section of CIB",
208 pcmk__option_default
209 },
210 {
211 "-spacer-", no_argument, NULL, '-',
212 "\tValid values: configuration, nodes, resources, constraints, "
213 "crm_config, rsc_defaults, op_defaults, acls, fencing-topology, "
214 "tags, alerts",
215 pcmk__option_default
216 },
217
218 {
219 "xpath", required_argument, NULL, 'A',
220 "A valid XPath to use instead of --scope/-o", pcmk__option_default
221 },
222 {
223 "node-path", no_argument, NULL, 'e',
224 "When performing XPath queries, return path of any matches found",
225 pcmk__option_default
226 },
227 {
228 "-spacer-", no_argument, NULL, '-',
229 "\t(for example, \"/cib/configuration/resources/clone[@id='ms_RH1_SCS']"
230 "/primitive[@id='prm_RH1_SCS']\")",
231 pcmk__option_paragraph
232 },
233 {
234 "node", required_argument, NULL, 'N',
235 "(Advanced) Send command to the specified host", pcmk__option_default
236 },
237 {
238 "-spacer-", no_argument, NULL, '!',
239 NULL, pcmk__option_hidden
240 },
241 {
242 "-spacer-", no_argument, NULL, '-',
243 "\n\nExamples:\n", pcmk__option_default
244 },
245 {
246 "-spacer-", no_argument, NULL, '-',
247 "Query the configuration from the local node:", pcmk__option_paragraph
248 },
249 {
250 "-spacer-", no_argument, NULL, '-',
251 " cibadmin --query --local", pcmk__option_example
252 },
253
254 {
255 "-spacer-", no_argument, NULL, '-',
256 "Query just the cluster options configuration:", pcmk__option_paragraph
257 },
258 {
259 "-spacer-", no_argument, NULL, '-',
260 " cibadmin --query --scope crm_config", pcmk__option_example
261 },
262
263 {
264 "-spacer-", no_argument, NULL, '-',
265 "Query all 'target-role' settings:", pcmk__option_paragraph
266 },
267 {
268 "-spacer-", no_argument, NULL, '-',
269 " cibadmin --query --xpath \"//nvpair[@name='target-role']\"",
270 pcmk__option_example
271 },
272
273 {
274 "-spacer-", no_argument, NULL, '-',
275 "Remove all 'is-managed' settings:", pcmk__option_paragraph
276 },
277 {
278 "-spacer-", no_argument, NULL, '-',
279 " cibadmin --delete-all --xpath \"//nvpair[@name='is-managed']\"",
280 pcmk__option_example
281 },
282
283 {
284 "-spacer-", no_argument, NULL, '-',
285 "Remove the resource named 'old':", pcmk__option_paragraph
286 },
287 {
288 "-spacer-", no_argument, NULL, '-',
289 " cibadmin --delete --xml-text '<primitive id=\"old\"/>'",
290 pcmk__option_example
291 },
292 {
293 "-spacer-", no_argument, NULL, '-',
294 "Remove all resources from the configuration:", pcmk__option_paragraph
295 },
296 {
297 "-spacer-", no_argument, NULL, '-',
298 " cibadmin --replace --scope resources --xml-text '<resources/>'",
299 pcmk__option_example
300 },
301 {
302 "-spacer-", no_argument, NULL, '-',
303 "Replace complete configuration with contents of $HOME/pacemaker.xml:",
304 pcmk__option_paragraph
305 },
306 {
307 "-spacer-", no_argument, NULL, '-',
308 " cibadmin --replace --xml-file $HOME/pacemaker.xml",
309 pcmk__option_example
310 },
311 {
312 "-spacer-", no_argument, NULL, '-',
313 "Replace constraints section of configuration with contents of "
314 "$HOME/constraints.xml:",
315 pcmk__option_paragraph
316 },
317 {
318 "-spacer-", no_argument, NULL, '-',
319 " cibadmin --replace --scope constraints --xml-file "
320 "$HOME/constraints.xml",
321 pcmk__option_example
322 },
323 {
324 "-spacer-", no_argument, NULL, '-',
325 "Increase configuration version to prevent old configurations from "
326 "being loaded accidentally:",
327 pcmk__option_paragraph
328 },
329 {
330 "-spacer-", no_argument, NULL, '-',
331 " cibadmin --modify --xml-text '<cib admin_epoch=\"admin_epoch++\"/>'",
332 pcmk__option_example
333 },
334 {
335 "-spacer-", no_argument, NULL, '-',
336 "Edit the configuration with your favorite $EDITOR:",
337 pcmk__option_paragraph
338 },
339 {
340 "-spacer-", no_argument, NULL, '-',
341 " cibadmin --query > $HOME/local.xml", pcmk__option_example
342 },
343 {
344 "-spacer-", no_argument, NULL, '-',
345 " $EDITOR $HOME/local.xml", pcmk__option_example
346 },
347 {
348 "-spacer-", no_argument, NULL, '-',
349 " cibadmin --replace --xml-file $HOME/local.xml", pcmk__option_example
350 },
351 {
352 "-spacer-", no_argument, NULL, '-',
353 "Assuming terminal, render configuration in color (green for writable, blue for readable, red for denied) to visualize permissions for user tony:",
354 pcmk__option_paragraph
355 },
356 {
357 "-spacer-", no_argument, NULL, '-',
358 " cibadmin --show-access=color --query --user tony | less -r",
359 pcmk__option_example
360 },
361 {
362 "-spacer-", no_argument, NULL, '-',
363 "SEE ALSO:", pcmk__option_default
364 },
365 {
366 "-spacer-", no_argument, NULL, '-',
367 " crm(8), pcs(8), crm_shadow(8), crm_diff(8)", pcmk__option_default
368 },
369 {
370 "host", required_argument, NULL, 'h',
371 "deprecated", pcmk__option_hidden
372 },
373 { 0, 0, 0, 0 }
374 };
375
376 static void
377 print_xml_output(xmlNode * xml)
378 {
379 char *buffer;
380
381 if (!xml) {
382 return;
383 } else if (xml->type != XML_ELEMENT_NODE) {
384 return;
385 }
386
387 if (command_options & cib_xpath_address) {
388 const char *id = crm_element_value(xml, XML_ATTR_ID);
389
390 if (pcmk__str_eq((const char *)xml->name, "xpath-query", pcmk__str_casei)) {
391 xmlNode *child = NULL;
392
393 for (child = xml->children; child; child = child->next) {
394 print_xml_output(child);
395 }
396
397 } else if (id) {
398 printf("%s\n", id);
399 }
400
401 } else {
402 buffer = dump_xml_formatted(xml);
403 fprintf(stdout, "%s", crm_str(buffer));
404 free(buffer);
405 }
406 }
407
408
409 static void
410 report_schema_unchanged(void)
411 {
412 const char *err = pcmk_rc_str(pcmk_rc_schema_unchanged);
413
414 crm_info("Upgrade unnecessary: %s\n", err);
415 printf("Upgrade unnecessary: %s\n", err);
416 exit_code = CRM_EX_OK;
417 }
418
419 int
420 main(int argc, char **argv)
421 {
422 int argerr = 0;
423 int rc = pcmk_ok;
424 int flag;
425 const char *source = NULL;
426 const char *admin_input_xml = NULL;
427 const char *admin_input_file = NULL;
428 gboolean dangerous_cmd = FALSE;
429 gboolean admin_input_stdin = FALSE;
430 xmlNode *output = NULL;
431 xmlNode *input = NULL;
432 char *username = NULL;
433 const char *acl_cred = NULL;
434 enum acl_eval_how {
435 acl_eval_unused,
436 acl_eval_auto,
437 acl_eval_namespace,
438 acl_eval_text,
439 acl_eval_color,
440 } acl_eval_how = acl_eval_unused;
441
442 int option_index = 0;
443
444 pcmk__cli_init_logging("cibadmin", 0);
445 set_crm_log_level(LOG_CRIT);
446 pcmk__set_cli_options(NULL, "<command> [options]", long_options,
447 "query and edit the Pacemaker configuration");
448
449 if (argc < 2) {
450 pcmk__cli_help('?', CRM_EX_USAGE);
451 }
452
453 while (1) {
454 flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
455 if (flag == -1)
456 break;
457
458 switch (flag) {
459 case 't':
460 message_timeout_ms = atoi(optarg);
461 if (message_timeout_ms < 1) {
462 message_timeout_ms = 30;
463 }
464 break;
465 case 'A':
466 obj_type = optarg;
467 cib__set_call_options(command_options, crm_system_name,
468 cib_xpath);
469 break;
470 case 'e':
471 cib__set_call_options(command_options, crm_system_name,
472 cib_xpath_address);
473 break;
474 case 'u':
475 cib_action = CIB_OP_UPGRADE;
476 dangerous_cmd = TRUE;
477 break;
478 case 'E':
479 cib_action = CIB_OP_ERASE;
480 dangerous_cmd = TRUE;
481 break;
482 case 'S':
483 if (optarg != NULL) {
484 if (!strcmp(optarg, "auto")) {
485 acl_eval_how = acl_eval_auto;
486 } else if (!strcmp(optarg, "namespace")) {
487 acl_eval_how = acl_eval_namespace;
488 } else if (!strcmp(optarg, "text")) {
489 acl_eval_how = acl_eval_text;
490 } else if (!strcmp(optarg, "color")) {
491 acl_eval_how = acl_eval_color;
492 } else {
493 fprintf(stderr, "Unrecognized value for --show-access: \"%s\"\n",
494 optarg);
495 ++argerr;
496 }
497 } else {
498 acl_eval_how = acl_eval_auto;
499 }
500
501
502
503
504 command_options |= cib_sync_call;
505 break;
506 case 'Q':
507 cib_action = CIB_OP_QUERY;
508 break;
509 case 'P':
510 cib_action = CIB_OP_APPLY_DIFF;
511 break;
512 case 'U':
513 cib_user = optarg;
514 break;
515 case 'M':
516 cib_action = CIB_OP_MODIFY;
517 break;
518 case 'R':
519 cib_action = CIB_OP_REPLACE;
520 break;
521 case 'C':
522 cib_action = CIB_OP_CREATE;
523 break;
524 case 'D':
525 cib_action = CIB_OP_DELETE;
526 break;
527 case '5':
528 cib_action = "md5-sum";
529 break;
530 case '6':
531 cib_action = "md5-sum-versioned";
532 break;
533 case 'c':
534 cib__set_call_options(command_options, crm_system_name,
535 cib_can_create);
536 break;
537 case 'n':
538 cib__set_call_options(command_options, crm_system_name,
539 cib_no_children);
540 break;
541 case 'B':
542 cib_action = CIB_OP_BUMP;
543 crm_log_args(argc, argv);
544 break;
545 case 'V':
546 cib__set_call_options(command_options, crm_system_name,
547 cib_verbose);
548 bump_log_num++;
549 break;
550 case '?':
551 case '$':
552 case '!':
553 pcmk__cli_help(flag, CRM_EX_OK);
554 break;
555 case 'o':
556 crm_trace("Option %c => %s", flag, optarg);
557 obj_type = optarg;
558 break;
559 case 'X':
560 crm_trace("Option %c => %s", flag, optarg);
561 admin_input_xml = optarg;
562 crm_log_args(argc, argv);
563 break;
564 case 'x':
565 crm_trace("Option %c => %s", flag, optarg);
566 admin_input_file = optarg;
567 crm_log_args(argc, argv);
568 break;
569 case 'p':
570 admin_input_stdin = TRUE;
571 crm_log_args(argc, argv);
572 break;
573 case 'N':
574 case 'h':
575 pcmk__str_update(&host, optarg);
576 break;
577 case 'l':
578 cib__set_call_options(command_options, crm_system_name,
579 cib_scope_local);
580 break;
581 case 'd':
582 cib_action = CIB_OP_DELETE;
583 cib__set_call_options(command_options, crm_system_name,
584 cib_multiple);
585 dangerous_cmd = TRUE;
586 break;
587 case 'b':
588 dangerous_cmd = TRUE;
589 cib__set_call_options(command_options, crm_system_name,
590 cib_inhibit_bcast|cib_scope_local);
591 break;
592 case 's':
593 cib__set_call_options(command_options, crm_system_name,
594 cib_sync_call);
595 break;
596 case 'f':
597 force_flag = TRUE;
598 cib__set_call_options(command_options, crm_system_name,
599 cib_quorum_override);
600 crm_log_args(argc, argv);
601 break;
602 case 'a':
603 output = createEmptyCib(1);
604 if (optind < argc) {
605 crm_xml_add(output, XML_ATTR_VALIDATION, argv[optind]);
606 }
607 admin_input_xml = dump_xml_formatted(output);
608 fprintf(stdout, "%s\n", crm_str(admin_input_xml));
609 crm_exit(CRM_EX_OK);
610 break;
611 default:
612 printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
613 ++argerr;
614 break;
615 }
616 }
617
618 while (bump_log_num > 0) {
619 crm_bump_log_level(argc, argv);
620 bump_log_num--;
621 }
622
623 if (optind < argc) {
624 printf("non-option ARGV-elements: ");
625 while (optind < argc)
626 printf("%s ", argv[optind++]);
627 printf("\n");
628 pcmk__cli_help('?', CRM_EX_USAGE);
629 }
630
631 if (optind > argc || cib_action == NULL) {
632 ++argerr;
633 }
634
635 if (argerr) {
636 pcmk__cli_help('?', CRM_EX_USAGE);
637 }
638
639 if (dangerous_cmd && force_flag == FALSE) {
640 fprintf(stderr, "The supplied command is considered dangerous."
641 " To prevent accidental destruction of the cluster,"
642 " the --force flag is required in order to proceed.\n");
643 fflush(stderr);
644 crm_exit(CRM_EX_UNSAFE);
645 }
646
647 if (admin_input_file != NULL) {
648 input = filename2xml(admin_input_file);
649 source = admin_input_file;
650
651 } else if (admin_input_xml != NULL) {
652 source = "input string";
653 input = string2xml(admin_input_xml);
654
655 } else if (admin_input_stdin) {
656 source = "STDIN";
657 input = stdin2xml();
658
659 } else if (acl_eval_how != acl_eval_unused) {
660 username = pcmk__uid2username(geteuid());
661 if (pcmk_acl_required(username)) {
662 if (force_flag) {
663 fprintf(stderr, "The supplied command can provide skewed"
664 " result since it is run under user that also"
665 " gets guarded per ACLs on their own right."
666 " Continuing since --force flag was"
667 " provided.\n");
668
669 } else {
670 fprintf(stderr, "The supplied command can provide skewed"
671 " result since it is run under user that also"
672 " gets guarded per ACLs in their own right."
673 " To accept the risk of such a possible"
674 " distortion (without even knowing it at this"
675 " time), use the --force flag.\n");
676 crm_exit(CRM_EX_UNSAFE);
677 }
678
679 }
680 free(username);
681 username = NULL;
682
683 if (cib_user == NULL) {
684 fprintf(stderr, "The supplied command requires -U user specified.\n");
685 crm_exit(CRM_EX_USAGE);
686 }
687
688
689 acl_cred = cib_user;
690 cib_user = NULL;
691 }
692
693 if (input != NULL) {
694 crm_log_xml_debug(input, "[admin input]");
695
696 } else if (source) {
697 fprintf(stderr, "Couldn't parse input from %s.\n", source);
698 crm_exit(CRM_EX_CONFIG);
699 }
700
701 if (pcmk__str_eq(cib_action, "md5-sum", pcmk__str_casei)) {
702 char *digest = NULL;
703
704 if (input == NULL) {
705 fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
706 crm_exit(CRM_EX_USAGE);
707 }
708
709 digest = calculate_on_disk_digest(input);
710 fprintf(stderr, "Digest: ");
711 fprintf(stdout, "%s\n", crm_str(digest));
712 free(digest);
713 free_xml(input);
714 crm_exit(CRM_EX_OK);
715
716 } else if (pcmk__str_eq(cib_action, "md5-sum-versioned", pcmk__str_casei)) {
717 char *digest = NULL;
718 const char *version = NULL;
719
720 if (input == NULL) {
721 fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
722 crm_exit(CRM_EX_USAGE);
723 }
724
725 version = crm_element_value(input, XML_ATTR_CRM_VERSION);
726 digest = calculate_xml_versioned_digest(input, FALSE, TRUE, version);
727 fprintf(stderr, "Versioned (%s) digest: ", version);
728 fprintf(stdout, "%s\n", crm_str(digest));
729 free(digest);
730 free_xml(input);
731 crm_exit(CRM_EX_OK);
732 }
733
734 rc = do_init();
735 if (rc != pcmk_ok) {
736 crm_err("Init failed, could not perform requested operations");
737 fprintf(stderr, "Init failed, could not perform requested operations\n");
738 free_xml(input);
739 crm_exit(crm_errno2exit(rc));
740 }
741
742 rc = do_work(input, command_options, &output);
743 if (rc > 0) {
744
745
746
747 request_id = rc;
748
749 the_cib->cmds->register_callback(the_cib, request_id, message_timeout_ms, FALSE, NULL,
750 "cibadmin_op_callback", cibadmin_op_callback);
751
752 mainloop = g_main_loop_new(NULL, FALSE);
753
754 crm_trace("%s waiting for reply from the local CIB", crm_system_name);
755
756 crm_info("Starting mainloop");
757 g_main_loop_run(mainloop);
758
759 } else if ((rc == -pcmk_err_schema_unchanged)
760 && pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
761 report_schema_unchanged();
762
763 } else if (rc < 0) {
764 crm_err("Call failed: %s", pcmk_strerror(rc));
765 fprintf(stderr, "Call failed: %s\n", pcmk_strerror(rc));
766
767 if (rc == -pcmk_err_schema_validation) {
768 if (pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
769 xmlNode *obj = NULL;
770 int version = 0, rc = 0;
771
772 rc = the_cib->cmds->query(the_cib, NULL, &obj, command_options);
773 if (rc == pcmk_ok) {
774 update_validation(&obj, &version, 0, TRUE, FALSE);
775 }
776
777 } else if (output) {
778 validate_xml_verbose(output);
779 }
780 }
781 exit_code = crm_errno2exit(rc);
782 }
783
784 if (output != NULL && acl_eval_how != acl_eval_unused) {
785 xmlDoc *acl_evaled_doc;
786 rc = pcmk__acl_annotate_permissions(acl_cred, output->doc, &acl_evaled_doc);
787 if (rc == pcmk_rc_ok) {
788 enum pcmk__acl_render_how how;
789 xmlChar *rendered = NULL;
790 free_xml(output);
791 switch(acl_eval_how) {
792 case acl_eval_text:
793 how = pcmk__acl_render_text;
794 break;
795 case acl_eval_color:
796 how = pcmk__acl_render_color;
797 break;
798 case acl_eval_namespace:
799 how = pcmk__acl_render_namespace;
800 break;
801 default:
802 if ( isatty(STDOUT_FILENO)) {
803 how = pcmk__acl_render_color;
804 } else {
805 how = pcmk__acl_render_text;
806 }
807 break;
808 }
809
810 if (!pcmk__acl_evaled_render(acl_evaled_doc, how,
811 &rendered)) {
812 printf("%s\n", (char *) rendered);
813 free(rendered);
814 } else {
815 fprintf(stderr, "Could not render evaluated access\n");
816 crm_exit(CRM_EX_CONFIG);
817 }
818 output = NULL;
819 } else {
820 fprintf(stderr, "Could not evaluate access per request (%s, error: %s)\n", acl_cred, pcmk_rc_str(rc));
821 crm_exit(CRM_EX_CONFIG);
822 }
823 }
824
825 if (output != NULL) {
826 print_xml_output(output);
827 free_xml(output);
828 }
829
830 crm_trace("%s exiting normally", crm_system_name);
831
832 free_xml(input);
833 rc = cib__clean_up_connection(&the_cib);
834 if (exit_code == CRM_EX_OK) {
835 exit_code = pcmk_rc2exitc(rc);
836 }
837
838 free(host);
839 crm_exit(exit_code);
840 }
841
842 int
843 do_work(xmlNode * input, int call_options, xmlNode ** output)
844 {
845
846 the_cib->call_timeout = message_timeout_ms;
847 if (strcasecmp(CIB_OP_REPLACE, cib_action) == 0
848 && pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
849 xmlNode *status = pcmk_find_cib_element(input, XML_CIB_TAG_STATUS);
850
851 if (status == NULL) {
852 create_xml_node(input, XML_CIB_TAG_STATUS);
853 }
854 }
855
856 if (cib_action != NULL) {
857 crm_trace("Passing \"%s\" to variant_op...", cib_action);
858 return cib_internal_op(the_cib, cib_action, host, obj_type, input, output, call_options, cib_user);
859
860 } else {
861 crm_err("You must specify an operation");
862 }
863 return -EINVAL;
864 }
865
866 int
867 do_init(void)
868 {
869 int rc = pcmk_ok;
870
871 the_cib = cib_new();
872 rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
873 if (rc != pcmk_ok) {
874 crm_err("Could not connect to the CIB: %s", pcmk_strerror(rc));
875 fprintf(stderr, "Could not connect to the CIB: %s\n",
876 pcmk_strerror(rc));
877 }
878
879 return rc;
880 }
881
882 void
883 cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
884 {
885 exit_code = crm_errno2exit(rc);
886
887 if (rc == -pcmk_err_schema_unchanged) {
888 report_schema_unchanged();
889
890 } else if (rc != pcmk_ok) {
891 crm_warn("Call %s failed (%d): %s", cib_action, rc, pcmk_strerror(rc));
892 fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, pcmk_strerror(rc));
893 print_xml_output(output);
894
895 } else if (pcmk__str_eq(cib_action, CIB_OP_QUERY, pcmk__str_casei) && output == NULL) {
896 crm_err("Query returned no output");
897 crm_log_xml_err(msg, "no output");
898
899 } else if (output == NULL) {
900 crm_info("Call passed");
901
902 } else {
903 crm_info("Call passed");
904 print_xml_output(output);
905 }
906
907 if (call_id == request_id) {
908 g_main_loop_quit(mainloop);
909
910 } else {
911 crm_info("Message was not the response we were looking for (%d vs. %d)",
912 call_id, request_id);
913 }
914 }