root/tools/cibadmin.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_xml_output
  2. report_schema_unchanged
  3. main
  4. do_work
  5. do_init
  6. cibadmin_op_callback

   1 /*
   2  * Copyright 2004-2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   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     // long option, argument type, storage, short option, description, flags
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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", pcmk__s(buffer, "<null>\n"));
 404         free(buffer);
 405     }
 406 }
 407 
 408 // Upgrade requested but already at latest schema
 409 static void
 410 report_schema_unchanged(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 = PCMK__CIB_REQUEST_UPGRADE;
 476                 dangerous_cmd = TRUE;
 477                 break;
 478             case 'E':
 479                 cib_action = PCMK__CIB_REQUEST_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                 /* XXX this is a workaround until we unify happy paths for
 501                        both a/sync handling; the respective extra code is
 502                        only in sync path now, but does it matter at all for
 503                        query-like request wrt. what blackbox users observe? */
 504                 command_options |= cib_sync_call;
 505                 break;
 506             case 'Q':
 507                 cib_action = PCMK__CIB_REQUEST_QUERY;
 508                 break;
 509             case 'P':
 510                 cib_action = PCMK__CIB_REQUEST_APPLY_PATCH;
 511                 break;
 512             case 'U':
 513                 cib_user = optarg;
 514                 break;
 515             case 'M':
 516                 cib_action = PCMK__CIB_REQUEST_MODIFY;
 517                 break;
 518             case 'R':
 519                 cib_action = PCMK__CIB_REQUEST_REPLACE;
 520                 break;
 521             case 'C':
 522                 cib_action = PCMK__CIB_REQUEST_CREATE;
 523                 break;
 524             case 'D':
 525                 cib_action = PCMK__CIB_REQUEST_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 = PCMK__CIB_REQUEST_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 = PCMK__CIB_REQUEST_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", pcmk__s(admin_input_xml, "<null>\n"));
 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         /* we already stopped/warned ACL-controlled users about consequences */
 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", pcmk__s(digest, "<null>"));
 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", pcmk__s(digest, "<null>"));
 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(pcmk_rc2exitc(pcmk_legacy2rc(rc)));
 740     }
 741 
 742     rc = do_work(input, command_options, &output);
 743     if (rc > 0) {
 744         /* wait for the reply by creating a mainloop and running it until
 745          * the callbacks are invoked...
 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, PCMK__CIB_REQUEST_UPGRADE,
 761                                pcmk__str_none)) {
 762         report_schema_unchanged();
 763 
 764     } else if (rc < 0) {
 765         rc = pcmk_legacy2rc(rc);
 766         crm_err("Call failed: %s", pcmk_rc_str(rc));
 767         fprintf(stderr, "Call failed: %s\n", pcmk_rc_str(rc));
 768 
 769         if (rc == pcmk_rc_schema_validation) {
 770             if (pcmk__str_eq(cib_action, PCMK__CIB_REQUEST_UPGRADE,
 771                              pcmk__str_none)) {
 772                 xmlNode *obj = NULL;
 773                 int version = 0;
 774 
 775                 if (the_cib->cmds->query(the_cib, NULL, &obj,
 776                                          command_options) == pcmk_ok) {
 777                     update_validation(&obj, &version, 0, TRUE, FALSE);
 778                 }
 779 
 780             } else if (output) {
 781                 validate_xml_verbose(output);
 782             }
 783         }
 784         exit_code = pcmk_rc2exitc(rc);
 785     }
 786 
 787     if (output != NULL && acl_eval_how != acl_eval_unused) {
 788         xmlDoc *acl_evaled_doc;
 789         rc = pcmk__acl_annotate_permissions(acl_cred, output->doc, &acl_evaled_doc);
 790         if (rc == pcmk_rc_ok) {
 791             enum pcmk__acl_render_how how;
 792             xmlChar *rendered = NULL;
 793             free_xml(output);
 794             switch(acl_eval_how) {
 795                 case acl_eval_text:
 796                     how = pcmk__acl_render_text;
 797                     break;
 798                 case acl_eval_color:
 799                     how = pcmk__acl_render_color;
 800                     break;
 801                 case acl_eval_namespace:
 802                     how = pcmk__acl_render_namespace;
 803                     break;
 804                 default:
 805                     if (/*acl_eval_auto*/ isatty(STDOUT_FILENO)) {
 806                         how = pcmk__acl_render_color;
 807                     } else {
 808                         how = pcmk__acl_render_text;
 809                     }
 810                     break;
 811             }
 812 
 813             if (!pcmk__acl_evaled_render(acl_evaled_doc, how,
 814                                             &rendered)) {
 815                 printf("%s\n", (char *) rendered);
 816                 free(rendered);
 817             } else {
 818                 fprintf(stderr, "Could not render evaluated access\n");
 819                 crm_exit(CRM_EX_CONFIG);
 820             }
 821             output = NULL;
 822         } else {
 823             fprintf(stderr, "Could not evaluate access per request (%s, error: %s)\n", acl_cred, pcmk_rc_str(rc));
 824             crm_exit(CRM_EX_CONFIG);
 825         }
 826     }
 827 
 828     if (output != NULL) {
 829         print_xml_output(output);
 830         free_xml(output);
 831     }
 832 
 833     crm_trace("%s exiting normally", crm_system_name);
 834 
 835     free_xml(input);
 836     rc = cib__clean_up_connection(&the_cib);
 837     if (exit_code == CRM_EX_OK) {
 838         exit_code = pcmk_rc2exitc(rc);
 839     }
 840 
 841     free(host);
 842     crm_exit(exit_code);
 843 }
 844 
 845 int
 846 do_work(xmlNode * input, int call_options, xmlNode ** output)
     /* [previous][next][first][last][top][bottom][index][help] */
 847 {
 848     /* construct the request */
 849     the_cib->call_timeout = message_timeout_ms;
 850     if ((strcmp(cib_action, PCMK__CIB_REQUEST_REPLACE) == 0)
 851         && pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
 852         xmlNode *status = pcmk_find_cib_element(input, XML_CIB_TAG_STATUS);
 853 
 854         if (status == NULL) {
 855             create_xml_node(input, XML_CIB_TAG_STATUS);
 856         }
 857     }
 858 
 859     if (cib_action != NULL) {
 860         crm_trace("Passing \"%s\" to variant_op...", cib_action);
 861         return cib_internal_op(the_cib, cib_action, host, obj_type, input, output, call_options, cib_user);
 862 
 863     } else {
 864         crm_err("You must specify an operation");
 865     }
 866     return -EINVAL;
 867 }
 868 
 869 int
 870 do_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 871 {
 872     int rc = pcmk_ok;
 873 
 874     the_cib = cib_new();
 875     rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
 876     if (rc != pcmk_ok) {
 877         crm_err("Could not connect to the CIB: %s", pcmk_strerror(rc));
 878         fprintf(stderr, "Could not connect to the CIB: %s\n",
 879                 pcmk_strerror(rc));
 880     }
 881 
 882     return rc;
 883 }
 884 
 885 void
 886 cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 887 {
 888     rc = pcmk_legacy2rc(rc);
 889     exit_code = pcmk_rc2exitc(rc);
 890 
 891     if (rc == pcmk_rc_schema_unchanged) {
 892         report_schema_unchanged();
 893 
 894     } else if (rc != pcmk_rc_ok) {
 895         crm_warn("Call %s failed: %s " CRM_XS " rc=%d",
 896                  cib_action, pcmk_rc_str(rc), rc);
 897         fprintf(stderr, "Call %s failed: %s\n", cib_action, pcmk_rc_str(rc));
 898         print_xml_output(output);
 899 
 900     } else if (pcmk__str_eq(cib_action, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)
 901                && (output == NULL)) {
 902         crm_err("Query returned no output");
 903         crm_log_xml_err(msg, "no output");
 904 
 905     } else if (output == NULL) {
 906         crm_info("Call passed");
 907 
 908     } else {
 909         crm_info("Call passed");
 910         print_xml_output(output);
 911     }
 912 
 913     if (call_id == request_id) {
 914         g_main_loop_quit(mainloop);
 915 
 916     } else {
 917         crm_info("Message was not the response we were looking for (%d vs. %d)",
 918                  call_id, request_id);
 919     }
 920 }

/* [previous][next][first][last][top][bottom][index][help] */