root/daemons/fenced/pacemaker-fenced.c

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

DEFINITIONS

This source file includes following definitions.
  1. st_ipc_accept
  2. st_ipc_dispatch
  3. st_ipc_closed
  4. st_ipc_destroy
  5. stonith_peer_callback
  6. stonith_peer_ais_callback
  7. stonith_peer_cs_destroy
  8. do_local_reply
  9. get_stonith_flag
  10. stonith_notify_client
  11. do_stonith_async_timeout_update
  12. fenced_send_notification
  13. send_config_notification
  14. fenced_send_device_notification
  15. fenced_send_level_notification
  16. topology_remove_helper
  17. remove_cib_device
  18. remove_topology_level
  19. add_topology_level
  20. remove_fencing_topology
  21. register_fencing_topology
  22. fencing_topology_init
  23. our_node_allowed_for
  24. watchdog_device_update
  25. update_stonith_watchdog_timeout_ms
  26. cib_device_update
  27. cib_devices_update
  28. update_cib_stonith_devices_v2
  29. update_cib_stonith_devices_v1
  30. update_cib_stonith_devices
  31. node_has_attr
  32. node_does_watchdog_fencing
  33. update_fencing_topology
  34. update_cib_cache_cb
  35. init_cib_cache_cb
  36. stonith_shutdown
  37. cib_connection_destroy
  38. stonith_cleanup
  39. stand_alone_cpg_cb
  40. setup_cib
  41. st_peer_update_callback
  42. fencer_metadata
  43. build_arg_context
  44. main

   1 /*
   2  * Copyright 2009-2023 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 
  12 #include <sys/param.h>
  13 #include <stdio.h>
  14 #include <sys/types.h>
  15 #include <sys/stat.h>
  16 #include <unistd.h>
  17 #include <sys/utsname.h>
  18 
  19 #include <stdlib.h>
  20 #include <errno.h>
  21 #include <fcntl.h>
  22 #include <inttypes.h>  // PRIu32, PRIx32
  23 
  24 #include <crm/crm.h>
  25 #include <crm/msg_xml.h>
  26 #include <crm/common/cmdline_internal.h>
  27 #include <crm/common/ipc.h>
  28 #include <crm/common/ipc_internal.h>
  29 #include <crm/common/output_internal.h>
  30 #include <crm/cluster/internal.h>
  31 
  32 #include <crm/stonith-ng.h>
  33 #include <crm/fencing/internal.h>
  34 #include <crm/common/xml.h>
  35 #include <crm/common/xml_internal.h>
  36 
  37 #include <crm/common/mainloop.h>
  38 
  39 #include <crm/cib/internal.h>
  40 #include <crm/pengine/status.h>
  41 #include <pacemaker-internal.h>
  42 
  43 #include <pacemaker-fenced.h>
  44 
  45 #define SUMMARY "daemon for executing fencing devices in a Pacemaker cluster"
  46 
  47 char *stonith_our_uname = NULL;
  48 long stonith_watchdog_timeout_ms = 0;
  49 GList *stonith_watchdog_targets = NULL;
  50 
  51 static GMainLoop *mainloop = NULL;
  52 
  53 gboolean stand_alone = FALSE;
  54 static gboolean stonith_shutdown_flag = FALSE;
  55 
  56 static qb_ipcs_service_t *ipcs = NULL;
  57 static xmlNode *local_cib = NULL;
  58 static pe_working_set_t *fenced_data_set = NULL;
  59 static const unsigned long long data_set_flags = pe_flag_quick_location
  60                                                  | pe_flag_no_compat
  61                                                  | pe_flag_no_counts;
  62 
  63 static cib_t *cib_api = NULL;
  64 
  65 static pcmk__output_t *logger_out = NULL;
  66 static pcmk__output_t *out = NULL;
  67 
  68 pcmk__supported_format_t formats[] = {
  69     PCMK__SUPPORTED_FORMAT_NONE,
  70     PCMK__SUPPORTED_FORMAT_TEXT,
  71     PCMK__SUPPORTED_FORMAT_XML,
  72     { NULL, NULL, NULL }
  73 };
  74 
  75 static struct {
  76     bool no_cib_connect;
  77     gchar **log_files;
  78 } options;
  79 
  80 static crm_exit_t exit_code = CRM_EX_OK;
  81 
  82 static void stonith_shutdown(int nsig);
  83 static void stonith_cleanup(void);
  84 
  85 static int32_t
  86 st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88     if (stonith_shutdown_flag) {
  89         crm_info("Ignoring new client [%d] during shutdown",
  90                  pcmk__client_pid(c));
  91         return -EPERM;
  92     }
  93 
  94     if (pcmk__new_client(c, uid, gid) == NULL) {
  95         return -EIO;
  96     }
  97     return 0;
  98 }
  99 
 100 /* Exit code means? */
 101 static int32_t
 102 st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104     uint32_t id = 0;
 105     uint32_t flags = 0;
 106     int call_options = 0;
 107     xmlNode *request = NULL;
 108     pcmk__client_t *c = pcmk__find_client(qbc);
 109     const char *op = NULL;
 110 
 111     if (c == NULL) {
 112         crm_info("Invalid client: %p", qbc);
 113         return 0;
 114     }
 115 
 116     request = pcmk__client_data2xml(c, data, &id, &flags);
 117     if (request == NULL) {
 118         pcmk__ipc_send_ack(c, id, flags, "nack", NULL, CRM_EX_PROTOCOL);
 119         return 0;
 120     }
 121 
 122 
 123     op = crm_element_value(request, F_CRM_TASK);
 124     if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) {
 125         crm_xml_add(request, F_TYPE, T_STONITH_NG);
 126         crm_xml_add(request, F_STONITH_OPERATION, op);
 127         crm_xml_add(request, F_STONITH_CLIENTID, c->id);
 128         crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
 129         crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
 130 
 131         send_cluster_message(NULL, crm_msg_stonith_ng, request, FALSE);
 132         free_xml(request);
 133         return 0;
 134     }
 135 
 136     if (c->name == NULL) {
 137         const char *value = crm_element_value(request, F_STONITH_CLIENTNAME);
 138 
 139         if (value == NULL) {
 140             value = "unknown";
 141         }
 142         c->name = crm_strdup_printf("%s.%u", value, c->pid);
 143     }
 144 
 145     crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
 146     crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32
 147               " from client %s", flags, call_options, id, pcmk__client_name(c));
 148 
 149     if (pcmk_is_set(call_options, st_opt_sync_call)) {
 150         CRM_ASSERT(flags & crm_ipc_client_response);
 151         CRM_LOG_ASSERT(c->request_id == 0);     /* This means the client has two synchronous events in-flight */
 152         c->request_id = id;     /* Reply only to the last one */
 153     }
 154 
 155     crm_xml_add(request, F_STONITH_CLIENTID, c->id);
 156     crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
 157     crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
 158 
 159     crm_log_xml_trace(request, "ipc-received");
 160     stonith_command(c, id, flags, request, NULL);
 161 
 162     free_xml(request);
 163     return 0;
 164 }
 165 
 166 /* Error code means? */
 167 static int32_t
 168 st_ipc_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170     pcmk__client_t *client = pcmk__find_client(c);
 171 
 172     if (client == NULL) {
 173         return 0;
 174     }
 175 
 176     crm_trace("Connection %p closed", c);
 177     pcmk__free_client(client);
 178 
 179     /* 0 means: yes, go ahead and destroy the connection */
 180     return 0;
 181 }
 182 
 183 static void
 184 st_ipc_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     crm_trace("Connection %p destroyed", c);
 187     st_ipc_closed(c);
 188 }
 189 
 190 static void
 191 stonith_peer_callback(xmlNode * msg, void *private_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193     const char *remote_peer = crm_element_value(msg, F_ORIG);
 194     const char *op = crm_element_value(msg, F_STONITH_OPERATION);
 195 
 196     if (pcmk__str_eq(op, "poke", pcmk__str_none)) {
 197         return;
 198     }
 199 
 200     crm_log_xml_trace(msg, "Peer[inbound]");
 201     stonith_command(NULL, 0, 0, msg, remote_peer);
 202 }
 203 
 204 #if SUPPORT_COROSYNC
 205 static void
 206 stonith_peer_ais_callback(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 207                           const struct cpg_name *groupName,
 208                           uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 209 {
 210     uint32_t kind = 0;
 211     xmlNode *xml = NULL;
 212     const char *from = NULL;
 213     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 214 
 215     if(data == NULL) {
 216         return;
 217     }
 218     if (kind == crm_class_cluster) {
 219         xml = string2xml(data);
 220         if (xml == NULL) {
 221             crm_err("Invalid XML: '%.120s'", data);
 222             free(data);
 223             return;
 224         }
 225         crm_xml_add(xml, F_ORIG, from);
 226         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
 227         stonith_peer_callback(xml, NULL);
 228     }
 229 
 230     free_xml(xml);
 231     free(data);
 232     return;
 233 }
 234 
 235 static void
 236 stonith_peer_cs_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238     crm_crit("Lost connection to cluster layer, shutting down");
 239     stonith_shutdown(0);
 240 }
 241 #endif
 242 
 243 void
 244 do_local_reply(xmlNode *notify_src, pcmk__client_t *client, int call_options)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246     /* send callback to originating child */
 247     int local_rc = pcmk_rc_ok;
 248     int rid = 0;
 249     uint32_t ipc_flags = crm_ipc_server_event;
 250 
 251     if (pcmk_is_set(call_options, st_opt_sync_call)) {
 252         CRM_LOG_ASSERT(client->request_id);
 253         rid = client->request_id;
 254         client->request_id = 0;
 255         ipc_flags = crm_ipc_flags_none;
 256     }
 257 
 258     local_rc = pcmk__ipc_send_xml(client, rid, notify_src, ipc_flags);
 259     if (local_rc == pcmk_rc_ok) {
 260         crm_trace("Sent response %d to client %s",
 261                   rid, pcmk__client_name(client));
 262     } else {
 263         crm_warn("%synchronous reply to client %s failed: %s",
 264                  (pcmk_is_set(call_options, st_opt_sync_call)? "S" : "As"),
 265                  pcmk__client_name(client), pcmk_rc_str(local_rc));
 266     }
 267 }
 268 
 269 uint64_t
 270 get_stonith_flag(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272     if (pcmk__str_eq(name, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
 273         return st_callback_notify_fence;
 274 
 275     } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_ADD, pcmk__str_casei)) {
 276         return st_callback_device_add;
 277 
 278     } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_DEL, pcmk__str_casei)) {
 279         return st_callback_device_del;
 280 
 281     } else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY, pcmk__str_casei)) {
 282         return st_callback_notify_history;
 283 
 284     } else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY_SYNCED, pcmk__str_casei)) {
 285         return st_callback_notify_history_synced;
 286 
 287     }
 288     return st_callback_unknown;
 289 }
 290 
 291 static void
 292 stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294 
 295     xmlNode *update_msg = user_data;
 296     pcmk__client_t *client = value;
 297     const char *type = NULL;
 298 
 299     CRM_CHECK(client != NULL, return);
 300     CRM_CHECK(update_msg != NULL, return);
 301 
 302     type = crm_element_value(update_msg, F_SUBTYPE);
 303     CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
 304 
 305     if (client->ipcs == NULL) {
 306         crm_trace("Skipping client with NULL channel");
 307         return;
 308     }
 309 
 310     if (pcmk_is_set(client->flags, get_stonith_flag(type))) {
 311         int rc = pcmk__ipc_send_xml(client, 0, update_msg,
 312                                     crm_ipc_server_event);
 313 
 314         if (rc != pcmk_rc_ok) {
 315             crm_warn("%s notification of client %s failed: %s "
 316                      CRM_XS " id=%.8s rc=%d", type, pcmk__client_name(client),
 317                      pcmk_rc_str(rc), client->id, rc);
 318         } else {
 319             crm_trace("Sent %s notification to client %s",
 320                       type, pcmk__client_name(client));
 321         }
 322     }
 323 }
 324 
 325 void
 326 do_stonith_async_timeout_update(const char *client_id, const char *call_id, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 327 {
 328     pcmk__client_t *client = NULL;
 329     xmlNode *notify_data = NULL;
 330 
 331     if (!timeout || !call_id || !client_id) {
 332         return;
 333     }
 334 
 335     client = pcmk__find_client_by_id(client_id);
 336     if (!client) {
 337         return;
 338     }
 339 
 340     notify_data = create_xml_node(NULL, T_STONITH_TIMEOUT_VALUE);
 341     crm_xml_add(notify_data, F_TYPE, T_STONITH_TIMEOUT_VALUE);
 342     crm_xml_add(notify_data, F_STONITH_CALLID, call_id);
 343     crm_xml_add_int(notify_data, F_STONITH_TIMEOUT, timeout);
 344 
 345     crm_trace("timeout update is %d for client %s and call id %s", timeout, client_id, call_id);
 346 
 347     if (client) {
 348         pcmk__ipc_send_xml(client, 0, notify_data, crm_ipc_server_event);
 349     }
 350 
 351     free_xml(notify_data);
 352 }
 353 
 354 /*!
 355  * \internal
 356  * \brief Notify relevant IPC clients of a fencing operation result
 357  *
 358  * \param[in] type     Notification type
 359  * \param[in] result   Result of fencing operation (assume success if NULL)
 360  * \param[in] data     If not NULL, add to notification as call data
 361  */
 362 void
 363 fenced_send_notification(const char *type, const pcmk__action_result_t *result,
     /* [previous][next][first][last][top][bottom][index][help] */
 364                          xmlNode *data)
 365 {
 366     /* TODO: Standardize the contents of data */
 367     xmlNode *update_msg = create_xml_node(NULL, "notify");
 368 
 369     CRM_LOG_ASSERT(type != NULL);
 370 
 371     crm_xml_add(update_msg, F_TYPE, T_STONITH_NOTIFY);
 372     crm_xml_add(update_msg, F_SUBTYPE, type);
 373     crm_xml_add(update_msg, F_STONITH_OPERATION, type);
 374     stonith__xe_set_result(update_msg, result);
 375 
 376     if (data != NULL) {
 377         add_message_xml(update_msg, F_STONITH_CALLDATA, data);
 378     }
 379 
 380     crm_trace("Notifying clients");
 381     pcmk__foreach_ipc_client(stonith_notify_client, update_msg);
 382     free_xml(update_msg);
 383     crm_trace("Notify complete");
 384 }
 385 
 386 /*!
 387  * \internal
 388  * \brief Send notifications for a configuration change to subscribed clients
 389  *
 390  * \param[in] op      Notification type (STONITH_OP_DEVICE_ADD,
 391  *                    STONITH_OP_DEVICE_DEL, STONITH_OP_LEVEL_ADD, or
 392  *                    STONITH_OP_LEVEL_DEL)
 393  * \param[in] result  Operation result
 394  * \param[in] desc    Description of what changed
 395  * \param[in] active  Current number of devices or topologies in use
 396  */
 397 static void
 398 send_config_notification(const char *op, const pcmk__action_result_t *result,
     /* [previous][next][first][last][top][bottom][index][help] */
 399                          const char *desc, int active)
 400 {
 401     xmlNode *notify_data = create_xml_node(NULL, op);
 402 
 403     CRM_CHECK(notify_data != NULL, return);
 404 
 405     crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
 406     crm_xml_add_int(notify_data, F_STONITH_ACTIVE, active);
 407 
 408     fenced_send_notification(op, result, notify_data);
 409     free_xml(notify_data);
 410 }
 411 
 412 /*!
 413  * \internal
 414  * \brief Send notifications for a device change to subscribed clients
 415  *
 416  * \param[in] op      Notification type (STONITH_OP_DEVICE_ADD or
 417  *                    STONITH_OP_DEVICE_DEL)
 418  * \param[in] result  Operation result
 419  * \param[in] desc    ID of device that changed
 420  */
 421 void
 422 fenced_send_device_notification(const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 423                                 const pcmk__action_result_t *result,
 424                                 const char *desc)
 425 {
 426     send_config_notification(op, result, desc, g_hash_table_size(device_list));
 427 }
 428 
 429 /*!
 430  * \internal
 431  * \brief Send notifications for a topology level change to subscribed clients
 432  *
 433  * \param[in] op      Notification type (STONITH_OP_LEVEL_ADD or
 434  *                    STONITH_OP_LEVEL_DEL)
 435  * \param[in] result  Operation result
 436  * \param[in] desc    String representation of level (<target>[<level_index>])
 437  */
 438 void
 439 fenced_send_level_notification(const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 440                                const pcmk__action_result_t *result,
 441                                const char *desc)
 442 {
 443     send_config_notification(op, result, desc, g_hash_table_size(topology));
 444 }
 445 
 446 static void
 447 topology_remove_helper(const char *node, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449     char *desc = NULL;
 450     pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
 451     xmlNode *data = create_xml_node(NULL, XML_TAG_FENCING_LEVEL);
 452 
 453     crm_xml_add(data, F_STONITH_ORIGIN, __func__);
 454     crm_xml_add_int(data, XML_ATTR_STONITH_INDEX, level);
 455     crm_xml_add(data, XML_ATTR_STONITH_TARGET, node);
 456 
 457     fenced_unregister_level(data, &desc, &result);
 458     fenced_send_level_notification(STONITH_OP_LEVEL_DEL, &result, desc);
 459     pcmk__reset_result(&result);
 460     free_xml(data);
 461     free(desc);
 462 }
 463 
 464 static void
 465 remove_cib_device(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 466 {
 467     int max = numXpathResults(xpathObj), lpc = 0;
 468 
 469     for (lpc = 0; lpc < max; lpc++) {
 470         const char *rsc_id = NULL;
 471         const char *standard = NULL;
 472         xmlNode *match = getXpathResult(xpathObj, lpc);
 473 
 474         CRM_LOG_ASSERT(match != NULL);
 475         if(match != NULL) {
 476             standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
 477         }
 478 
 479         if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 480             continue;
 481         }
 482 
 483         rsc_id = crm_element_value(match, XML_ATTR_ID);
 484 
 485         stonith_device_remove(rsc_id, true);
 486     }
 487 }
 488 
 489 static void
 490 remove_topology_level(xmlNode *match)
     /* [previous][next][first][last][top][bottom][index][help] */
 491 {
 492     int index = 0;
 493     char *key = NULL;
 494 
 495     CRM_CHECK(match != NULL, return);
 496 
 497     key = stonith_level_key(match, fenced_target_by_unknown);
 498     crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
 499     topology_remove_helper(key, index);
 500     free(key);
 501 }
 502 
 503 static void
 504 add_topology_level(xmlNode *match)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506     char *desc = NULL;
 507     pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
 508 
 509     CRM_CHECK(match != NULL, return);
 510 
 511     fenced_register_level(match, &desc, &result);
 512     fenced_send_level_notification(STONITH_OP_LEVEL_ADD, &result, desc);
 513     pcmk__reset_result(&result);
 514     free(desc);
 515 }
 516 
 517 static void
 518 remove_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 519 {
 520     int max = numXpathResults(xpathObj), lpc = 0;
 521 
 522     for (lpc = 0; lpc < max; lpc++) {
 523         xmlNode *match = getXpathResult(xpathObj, lpc);
 524 
 525         CRM_LOG_ASSERT(match != NULL);
 526         if (match && crm_element_value(match, XML_DIFF_MARKER)) {
 527             /* Deletion */
 528             int index = 0;
 529             char *target = stonith_level_key(match, fenced_target_by_unknown);
 530 
 531             crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
 532             if (target == NULL) {
 533                 crm_err("Invalid fencing target in element %s", ID(match));
 534 
 535             } else if (index <= 0) {
 536                 crm_err("Invalid level for %s in element %s", target, ID(match));
 537 
 538             } else {
 539                 topology_remove_helper(target, index);
 540             }
 541             /* } else { Deal with modifications during the 'addition' stage */
 542         }
 543     }
 544 }
 545 
 546 static void
 547 register_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 548 {
 549     int max = numXpathResults(xpathObj), lpc = 0;
 550 
 551     for (lpc = 0; lpc < max; lpc++) {
 552         xmlNode *match = getXpathResult(xpathObj, lpc);
 553 
 554         remove_topology_level(match);
 555         add_topology_level(match);
 556     }
 557 }
 558 
 559 /* Fencing
 560 <diff crm_feature_set="3.0.6">
 561   <diff-removed>
 562     <fencing-topology>
 563       <fencing-level id="f-p1.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="removed:top"/>
 564       <fencing-level id="f-p1.2" target="pcmk-1" index="2" devices="power" __crm_diff_marker__="removed:top"/>
 565       <fencing-level devices="disk,network" id="f-p2.1"/>
 566     </fencing-topology>
 567   </diff-removed>
 568   <diff-added>
 569     <fencing-topology>
 570       <fencing-level id="f-p.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="added:top"/>
 571       <fencing-level id="f-p2.1" target="pcmk-2" index="1" devices="disk,something"/>
 572       <fencing-level id="f-p3.1" target="pcmk-2" index="2" devices="power" __crm_diff_marker__="added:top"/>
 573     </fencing-topology>
 574   </diff-added>
 575 </diff>
 576 */
 577 
 578 static void
 579 fencing_topology_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 580 {
 581     xmlXPathObjectPtr xpathObj = NULL;
 582     const char *xpath = "//" XML_TAG_FENCING_LEVEL;
 583 
 584     crm_trace("Full topology refresh");
 585     free_topology_list();
 586     init_topology_list();
 587 
 588     /* Grab everything */
 589     xpathObj = xpath_search(local_cib, xpath);
 590     register_fencing_topology(xpathObj);
 591 
 592     freeXpathObject(xpathObj);
 593 }
 594 
 595 #define rsc_name(x) x->clone_name?x->clone_name:x->id
 596 
 597 /*!
 598  * \internal
 599  * \brief Check whether our uname is in a resource's allowed node list
 600  *
 601  * \param[in] rsc  Resource to check
 602  *
 603  * \return Pointer to node object if found, NULL otherwise
 604  */
 605 static pe_node_t *
 606 our_node_allowed_for(const pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 607 {
 608     GHashTableIter iter;
 609     pe_node_t *node = NULL;
 610 
 611     if (rsc && stonith_our_uname) {
 612         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 613         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 614             if (node && strcmp(node->details->uname, stonith_our_uname) == 0) {
 615                 break;
 616             }
 617             node = NULL;
 618         }
 619     }
 620     return node;
 621 }
 622 
 623 static void
 624 watchdog_device_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 625 {
 626     if (stonith_watchdog_timeout_ms > 0) {
 627         if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
 628             !stonith_watchdog_targets) {
 629             /* getting here watchdog-fencing enabled, no device there yet
 630                and reason isn't stonith_watchdog_targets preventing that
 631              */
 632             int rc;
 633             xmlNode *xml;
 634 
 635             xml = create_device_registration_xml(
 636                     STONITH_WATCHDOG_ID,
 637                     st_namespace_internal,
 638                     STONITH_WATCHDOG_AGENT,
 639                     NULL, /* stonith_device_register will add our
 640                              own name as PCMK_STONITH_HOST_LIST param
 641                              so we can skip that here
 642                            */
 643                     NULL);
 644             rc = stonith_device_register(xml, TRUE);
 645             free_xml(xml);
 646             if (rc != pcmk_ok) {
 647                 rc = pcmk_legacy2rc(rc);
 648                 exit_code = CRM_EX_FATAL;
 649                 crm_crit("Cannot register watchdog pseudo fence agent: %s",
 650                          pcmk_rc_str(rc));
 651                 stonith_shutdown(0);
 652             }
 653         }
 654 
 655     } else if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) != NULL) {
 656         /* be silent if no device - todo parameter to stonith_device_remove */
 657         stonith_device_remove(STONITH_WATCHDOG_ID, true);
 658     }
 659 }
 660 
 661 static void
 662 update_stonith_watchdog_timeout_ms(xmlNode *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 663 {
 664     long timeout_ms = 0;
 665     xmlNode *stonith_watchdog_xml = NULL;
 666     const char *value = NULL;
 667 
 668     stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']",
 669                                             cib, LOG_NEVER);
 670     if (stonith_watchdog_xml) {
 671         value = crm_element_value(stonith_watchdog_xml, XML_NVPAIR_ATTR_VALUE);
 672     }
 673     if (value) {
 674         timeout_ms = crm_get_msec(value);
 675     }
 676 
 677     if (timeout_ms < 0) {
 678         timeout_ms = pcmk__auto_watchdog_timeout();
 679     }
 680 
 681     stonith_watchdog_timeout_ms = timeout_ms;
 682 }
 683 
 684 /*!
 685  * \internal
 686  * \brief If a resource or any of its children are STONITH devices, update their
 687  *        definitions given a cluster working set.
 688  *
 689  * \param[in,out] rsc       Resource to check
 690  * \param[in,out] data_set  Cluster working set with device information
 691  */
 692 static void
 693 cib_device_update(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 694 {
 695     pe_node_t *node = NULL;
 696     const char *value = NULL;
 697     const char *rclass = NULL;
 698     pe_node_t *parent = NULL;
 699 
 700     /* If this is a complex resource, check children rather than this resource itself. */
 701     if(rsc->children) {
 702         GList *gIter = NULL;
 703         for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 704             cib_device_update(gIter->data, data_set);
 705             if(pe_rsc_is_clone(rsc)) {
 706                 crm_trace("Only processing one copy of the clone %s", rsc->id);
 707                 break;
 708             }
 709         }
 710         return;
 711     }
 712 
 713     /* We only care about STONITH resources. */
 714     rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 715     if (!pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 716         return;
 717     }
 718 
 719     /* If this STONITH resource is disabled, remove it. */
 720     if (pe__resource_is_disabled(rsc)) {
 721         crm_info("Device %s has been disabled", rsc->id);
 722         return;
 723     }
 724 
 725     /* if watchdog-fencing is disabled handle any watchdog-fence
 726        resource as if it was disabled
 727      */
 728     if ((stonith_watchdog_timeout_ms <= 0) &&
 729         pcmk__str_eq(rsc->id, STONITH_WATCHDOG_ID, pcmk__str_none)) {
 730         crm_info("Watchdog-fencing disabled thus handling "
 731                  "device %s as disabled", rsc->id);
 732         return;
 733     }
 734 
 735     /* Check whether our node is allowed for this resource (and its parent if in a group) */
 736     node = our_node_allowed_for(rsc);
 737     if (rsc->parent && (rsc->parent->variant == pe_group)) {
 738         parent = our_node_allowed_for(rsc->parent);
 739     }
 740 
 741     if(node == NULL) {
 742         /* Our node is disallowed, so remove the device */
 743         GHashTableIter iter;
 744 
 745         crm_info("Device %s has been disabled on %s: unknown", rsc->id, stonith_our_uname);
 746         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 747         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 748             crm_trace("Available: %s = %d", pe__node_name(node), node->weight);
 749         }
 750 
 751         return;
 752 
 753     } else if(node->weight < 0 || (parent && parent->weight < 0)) {
 754         /* Our node (or its group) is disallowed by score, so remove the device */
 755         int score = (node->weight < 0)? node->weight : parent->weight;
 756 
 757         crm_info("Device %s has been disabled on %s: score=%s",
 758                  rsc->id, stonith_our_uname, pcmk_readable_score(score));
 759         return;
 760 
 761     } else {
 762         /* Our node is allowed, so update the device information */
 763         int rc;
 764         xmlNode *data;
 765         GHashTable *rsc_params = NULL;
 766         GHashTableIter gIter;
 767         stonith_key_value_t *params = NULL;
 768 
 769         const char *name = NULL;
 770         const char *agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE);
 771         const char *rsc_provides = NULL;
 772 
 773         crm_debug("Device %s is allowed on %s: score=%d", rsc->id, stonith_our_uname, node->weight);
 774         rsc_params = pe_rsc_params(rsc, node, data_set);
 775         get_meta_attributes(rsc->meta, rsc, node, data_set);
 776 
 777         rsc_provides = g_hash_table_lookup(rsc->meta, PCMK_STONITH_PROVIDES);
 778 
 779         g_hash_table_iter_init(&gIter, rsc_params);
 780         while (g_hash_table_iter_next(&gIter, (gpointer *) & name, (gpointer *) & value)) {
 781             if (!name || !value) {
 782                 continue;
 783             }
 784             params = stonith_key_value_add(params, name, value);
 785             crm_trace(" %s=%s", name, value);
 786         }
 787 
 788         data = create_device_registration_xml(rsc_name(rsc), st_namespace_any,
 789                                               agent, params, rsc_provides);
 790         stonith_key_value_freeall(params, 1, 1);
 791         rc = stonith_device_register(data, TRUE);
 792         CRM_ASSERT(rc == pcmk_ok);
 793         free_xml(data);
 794     }
 795 }
 796 
 797 /*!
 798  * \internal
 799  * \brief Update all STONITH device definitions based on current CIB
 800  */
 801 static void
 802 cib_devices_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 803 {
 804     GHashTableIter iter;
 805     stonith_device_t *device = NULL;
 806 
 807     crm_info("Updating devices to version %s.%s.%s",
 808              crm_element_value(local_cib, XML_ATTR_GENERATION_ADMIN),
 809              crm_element_value(local_cib, XML_ATTR_GENERATION),
 810              crm_element_value(local_cib, XML_ATTR_NUMUPDATES));
 811 
 812     if (fenced_data_set->now != NULL) {
 813         crm_time_free(fenced_data_set->now);
 814         fenced_data_set->now = NULL;
 815     }
 816     fenced_data_set->localhost = stonith_our_uname;
 817     pcmk__schedule_actions(local_cib, data_set_flags, fenced_data_set);
 818 
 819     g_hash_table_iter_init(&iter, device_list);
 820     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 821         if (device->cib_registered) {
 822             device->dirty = TRUE;
 823         }
 824     }
 825 
 826     /* have list repopulated if cib has a watchdog-fencing-resource
 827        TODO: keep a cached list for queries happening while we are refreshing
 828      */
 829     g_list_free_full(stonith_watchdog_targets, free);
 830     stonith_watchdog_targets = NULL;
 831     g_list_foreach(fenced_data_set->resources, (GFunc) cib_device_update, fenced_data_set);
 832 
 833     g_hash_table_iter_init(&iter, device_list);
 834     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 835         if (device->dirty) {
 836             g_hash_table_iter_remove(&iter);
 837         }
 838     }
 839 
 840     fenced_data_set->input = NULL; // Wasn't a copy, so don't let API free it
 841     pe_reset_working_set(fenced_data_set);
 842 }
 843 
 844 static void
 845 update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 846 {
 847     xmlNode *change = NULL;
 848     char *reason = NULL;
 849     bool needs_update = FALSE;
 850     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 851 
 852     for (change = pcmk__xml_first_child(patchset); change != NULL;
 853          change = pcmk__xml_next(change)) {
 854         const char *op = crm_element_value(change, XML_DIFF_OP);
 855         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
 856         const char *shortpath = NULL;
 857 
 858         if ((op == NULL) ||
 859             (strcmp(op, "move") == 0) ||
 860             strstr(xpath, "/"XML_CIB_TAG_STATUS)) {
 861             continue;
 862         } else if (pcmk__str_eq(op, "delete", pcmk__str_casei) && strstr(xpath, "/"XML_CIB_TAG_RESOURCE)) {
 863             const char *rsc_id = NULL;
 864             char *search = NULL;
 865             char *mutable = NULL;
 866 
 867             if (strstr(xpath, XML_TAG_ATTR_SETS) ||
 868                 strstr(xpath, XML_TAG_META_SETS)) {
 869                 needs_update = TRUE;
 870                 pcmk__str_update(&reason,
 871                                  "(meta) attribute deleted from resource");
 872                 break;
 873             }
 874             pcmk__str_update(&mutable, xpath);
 875             rsc_id = strstr(mutable, "primitive[@" XML_ATTR_ID "=\'");
 876             if (rsc_id != NULL) {
 877                 rsc_id += strlen("primitive[@" XML_ATTR_ID "=\'");
 878                 search = strchr(rsc_id, '\'');
 879             }
 880             if (search != NULL) {
 881                 *search = 0;
 882                 stonith_device_remove(rsc_id, true);
 883                 /* watchdog_device_update called afterwards
 884                    to fall back to implicit definition if needed */
 885             } else {
 886                 crm_warn("Ignoring malformed CIB update (resource deletion)");
 887             }
 888             free(mutable);
 889 
 890         } else if (strstr(xpath, "/"XML_CIB_TAG_RESOURCES) ||
 891                    strstr(xpath, "/"XML_CIB_TAG_CONSTRAINTS) ||
 892                    strstr(xpath, "/"XML_CIB_TAG_RSCCONFIG)) {
 893             shortpath = strrchr(xpath, '/'); CRM_ASSERT(shortpath);
 894             reason = crm_strdup_printf("%s %s", op, shortpath+1);
 895             needs_update = TRUE;
 896             break;
 897         }
 898     }
 899 
 900     if(needs_update) {
 901         crm_info("Updating device list from CIB: %s", reason);
 902         cib_devices_update();
 903     } else {
 904         crm_trace("No updates for device list found in CIB");
 905     }
 906     free(reason);
 907 }
 908 
 909 
 910 static void
 911 update_cib_stonith_devices_v1(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 912 {
 913     const char *reason = "none";
 914     gboolean needs_update = FALSE;
 915     xmlXPathObjectPtr xpath_obj = NULL;
 916 
 917     /* process new constraints */
 918     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_CONS_TAG_RSC_LOCATION);
 919     if (numXpathResults(xpath_obj) > 0) {
 920         int max = numXpathResults(xpath_obj), lpc = 0;
 921 
 922         /* Safest and simplest to always recompute */
 923         needs_update = TRUE;
 924         reason = "new location constraint";
 925 
 926         for (lpc = 0; lpc < max; lpc++) {
 927             xmlNode *match = getXpathResult(xpath_obj, lpc);
 928 
 929             crm_log_xml_trace(match, "new constraint");
 930         }
 931     }
 932     freeXpathObject(xpath_obj);
 933 
 934     /* process deletions */
 935     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_RESOURCE);
 936     if (numXpathResults(xpath_obj) > 0) {
 937         remove_cib_device(xpath_obj);
 938     }
 939     freeXpathObject(xpath_obj);
 940 
 941     /* process additions */
 942     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_RESOURCE);
 943     if (numXpathResults(xpath_obj) > 0) {
 944         int max = numXpathResults(xpath_obj), lpc = 0;
 945 
 946         for (lpc = 0; lpc < max; lpc++) {
 947             const char *rsc_id = NULL;
 948             const char *standard = NULL;
 949             xmlNode *match = getXpathResult(xpath_obj, lpc);
 950 
 951             rsc_id = crm_element_value(match, XML_ATTR_ID);
 952             standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
 953 
 954             if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 955                 continue;
 956             }
 957 
 958             crm_trace("Fencing resource %s was added or modified", rsc_id);
 959             reason = "new resource";
 960             needs_update = TRUE;
 961         }
 962     }
 963     freeXpathObject(xpath_obj);
 964 
 965     if(needs_update) {
 966         crm_info("Updating device list from CIB: %s", reason);
 967         cib_devices_update();
 968     }
 969 }
 970 
 971 static void
 972 update_cib_stonith_devices(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 973 {
 974     int format = 1;
 975     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 976 
 977     CRM_ASSERT(patchset);
 978     crm_element_value_int(patchset, "format", &format);
 979     switch(format) {
 980         case 1:
 981             update_cib_stonith_devices_v1(event, msg);
 982             break;
 983         case 2:
 984             update_cib_stonith_devices_v2(event, msg);
 985             break;
 986         default:
 987             crm_warn("Unknown patch format: %d", format);
 988     }
 989 }
 990 
 991 /*!
 992  * \internal
 993  * \brief Check whether a node has a specific attribute name/value
 994  *
 995  * \param[in] node    Name of node to check
 996  * \param[in] name    Name of an attribute to look for
 997  * \param[in] value   The value the named attribute needs to be set to in order to be considered a match
 998  *
 999  * \return TRUE if the locally cached CIB has the specified node attribute
1000  */
1001 gboolean
1002 node_has_attr(const char *node, const char *name, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1003 {
1004     GString *xpath = NULL;
1005     xmlNode *match;
1006 
1007     CRM_CHECK((local_cib != NULL) && (node != NULL) && (name != NULL)
1008               && (value != NULL), return FALSE);
1009 
1010     /* Search for the node's attributes in the CIB. While the schema allows
1011      * multiple sets of instance attributes, and allows instance attributes to
1012      * use id-ref to reference values elsewhere, that is intended for resources,
1013      * so we ignore that here.
1014      */
1015     xpath = g_string_sized_new(256);
1016     pcmk__g_strcat(xpath,
1017                    "//" XML_CIB_TAG_NODES "/" XML_CIB_TAG_NODE
1018                    "[@" XML_ATTR_UNAME "='", node, "']/" XML_TAG_ATTR_SETS
1019                    "/" XML_CIB_TAG_NVPAIR
1020                    "[@" XML_NVPAIR_ATTR_NAME "='", name, "' "
1021                    "and @" XML_NVPAIR_ATTR_VALUE "='", value, "']", NULL);
1022 
1023     match = get_xpath_object((const char *) xpath->str, local_cib, LOG_NEVER);
1024 
1025     g_string_free(xpath, TRUE);
1026     return (match != NULL);
1027 }
1028 
1029 /*!
1030  * \internal
1031  * \brief Check whether a node does watchdog-fencing
1032  *
1033  * \param[in] node    Name of node to check
1034  *
1035  * \return TRUE if node found in stonith_watchdog_targets
1036  *         or stonith_watchdog_targets is empty indicating
1037  *         all nodes are doing watchdog-fencing
1038  */
1039 gboolean
1040 node_does_watchdog_fencing(const char *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1041 {
1042     return ((stonith_watchdog_targets == NULL) ||
1043             pcmk__str_in_list(node, stonith_watchdog_targets, pcmk__str_casei));
1044 }
1045 
1046 
1047 static void
1048 update_fencing_topology(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1049 {
1050     int format = 1;
1051     const char *xpath;
1052     xmlXPathObjectPtr xpathObj = NULL;
1053     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
1054 
1055     CRM_ASSERT(patchset);
1056     crm_element_value_int(patchset, "format", &format);
1057 
1058     if(format == 1) {
1059         /* Process deletions (only) */
1060         xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_FENCING_LEVEL;
1061         xpathObj = xpath_search(msg, xpath);
1062 
1063         remove_fencing_topology(xpathObj);
1064         freeXpathObject(xpathObj);
1065 
1066         /* Process additions and changes */
1067         xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_TAG_FENCING_LEVEL;
1068         xpathObj = xpath_search(msg, xpath);
1069 
1070         register_fencing_topology(xpathObj);
1071         freeXpathObject(xpathObj);
1072 
1073     } else if(format == 2) {
1074         xmlNode *change = NULL;
1075         int add[] = { 0, 0, 0 };
1076         int del[] = { 0, 0, 0 };
1077 
1078         xml_patch_versions(patchset, add, del);
1079 
1080         for (change = pcmk__xml_first_child(patchset); change != NULL;
1081              change = pcmk__xml_next(change)) {
1082             const char *op = crm_element_value(change, XML_DIFF_OP);
1083             const char *xpath = crm_element_value(change, XML_DIFF_PATH);
1084 
1085             if(op == NULL) {
1086                 continue;
1087 
1088             } else if(strstr(xpath, "/" XML_TAG_FENCING_LEVEL) != NULL) {
1089                 /* Change to a specific entry */
1090 
1091                 crm_trace("Handling %s operation %d.%d.%d for %s", op, add[0], add[1], add[2], xpath);
1092                 if(strcmp(op, "move") == 0) {
1093                     continue;
1094 
1095                 } else if(strcmp(op, "create") == 0) {
1096                     add_topology_level(change->children);
1097 
1098                 } else if(strcmp(op, "modify") == 0) {
1099                     xmlNode *match = first_named_child(change, XML_DIFF_RESULT);
1100 
1101                     if(match) {
1102                         remove_topology_level(match->children);
1103                         add_topology_level(match->children);
1104                     }
1105 
1106                 } else if(strcmp(op, "delete") == 0) {
1107                     /* Nuclear option, all we have is the path and an id... not enough to remove a specific entry */
1108                     crm_info("Re-initializing fencing topology after %s operation %d.%d.%d for %s",
1109                              op, add[0], add[1], add[2], xpath);
1110                     fencing_topology_init();
1111                     return;
1112                 }
1113 
1114             } else if (strstr(xpath, "/" XML_TAG_FENCING_TOPOLOGY) != NULL) {
1115                 /* Change to the topology in general */
1116                 crm_info("Re-initializing fencing topology after top-level %s operation  %d.%d.%d for %s",
1117                          op, add[0], add[1], add[2], xpath);
1118                 fencing_topology_init();
1119                 return;
1120 
1121             } else if (strstr(xpath, "/" XML_CIB_TAG_CONFIGURATION)) {
1122                 /* Changes to the whole config section, possibly including the topology as a whild */
1123                 if(first_named_child(change, XML_TAG_FENCING_TOPOLOGY) == NULL) {
1124                     crm_trace("Nothing for us in %s operation %d.%d.%d for %s.",
1125                               op, add[0], add[1], add[2], xpath);
1126 
1127                 } else if(strcmp(op, "delete") == 0 || strcmp(op, "create") == 0) {
1128                     crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s.",
1129                              op, add[0], add[1], add[2], xpath);
1130                     fencing_topology_init();
1131                     return;
1132                 }
1133 
1134             } else {
1135                 crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
1136                           op, add[0], add[1], add[2], xpath);
1137             }
1138         }
1139 
1140     } else {
1141         crm_warn("Unknown patch format: %d", format);
1142     }
1143 }
1144 static bool have_cib_devices = FALSE;
1145 
1146 static void
1147 update_cib_cache_cb(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1148 {
1149     int rc = pcmk_ok;
1150     long timeout_ms_saved = stonith_watchdog_timeout_ms;
1151     bool need_full_refresh = false;
1152 
1153     if(!have_cib_devices) {
1154         crm_trace("Skipping updates until we get a full dump");
1155         return;
1156 
1157     } else if(msg == NULL) {
1158         crm_trace("Missing %s update", event);
1159         return;
1160     }
1161 
1162     /* Maintain a local copy of the CIB so that we have full access
1163      * to device definitions, location constraints, and node attributes
1164      */
1165     if (local_cib != NULL) {
1166         int rc = pcmk_ok;
1167         xmlNode *patchset = NULL;
1168 
1169         crm_element_value_int(msg, F_CIB_RC, &rc);
1170         if (rc != pcmk_ok) {
1171             return;
1172         }
1173 
1174         patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
1175         pcmk__output_set_log_level(logger_out, LOG_TRACE);
1176         out->message(out, "xml-patchset", patchset);
1177         rc = xml_apply_patchset(local_cib, patchset, TRUE);
1178         switch (rc) {
1179             case pcmk_ok:
1180             case -pcmk_err_old_data:
1181                 break;
1182             case -pcmk_err_diff_resync:
1183             case -pcmk_err_diff_failed:
1184                 crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
1185                 free_xml(local_cib);
1186                 local_cib = NULL;
1187                 break;
1188             default:
1189                 crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
1190                 free_xml(local_cib);
1191                 local_cib = NULL;
1192         }
1193     }
1194 
1195     if (local_cib == NULL) {
1196         crm_trace("Re-requesting full CIB");
1197         rc = cib_api->cmds->query(cib_api, NULL, &local_cib, cib_scope_local | cib_sync_call);
1198         if(rc != pcmk_ok) {
1199             crm_err("Couldn't retrieve the CIB: %s (%d)", pcmk_strerror(rc), rc);
1200             return;
1201         }
1202         CRM_ASSERT(local_cib != NULL);
1203         need_full_refresh = true;
1204     }
1205 
1206     pcmk__refresh_node_caches_from_cib(local_cib);
1207     update_stonith_watchdog_timeout_ms(local_cib);
1208 
1209     if (timeout_ms_saved != stonith_watchdog_timeout_ms) {
1210         need_full_refresh = true;
1211     }
1212 
1213     if (need_full_refresh) {
1214         fencing_topology_init();
1215         cib_devices_update();
1216     } else {
1217         // Partial refresh
1218         update_fencing_topology(event, msg);
1219         update_cib_stonith_devices(event, msg);
1220     }
1221 
1222     watchdog_device_update();
1223 }
1224 
1225 static void
1226 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1227 {
1228     crm_info("Updating device list from CIB");
1229     have_cib_devices = TRUE;
1230     local_cib = copy_xml(output);
1231 
1232     pcmk__refresh_node_caches_from_cib(local_cib);
1233     update_stonith_watchdog_timeout_ms(local_cib);
1234 
1235     fencing_topology_init();
1236     cib_devices_update();
1237     watchdog_device_update();
1238 }
1239 
1240 static void
1241 stonith_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
1242 {
1243     crm_info("Terminating with %d clients", pcmk__ipc_client_count());
1244     stonith_shutdown_flag = TRUE;
1245     if (mainloop != NULL && g_main_loop_is_running(mainloop)) {
1246         g_main_loop_quit(mainloop);
1247     }
1248 }
1249 
1250 static void
1251 cib_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1252 {
1253     if (stonith_shutdown_flag) {
1254         crm_info("Connection to the CIB manager closed");
1255         return;
1256     } else {
1257         crm_crit("Lost connection to the CIB manager, shutting down");
1258     }
1259     if (cib_api) {
1260         cib_api->cmds->signoff(cib_api);
1261     }
1262     stonith_shutdown(0);
1263 }
1264 
1265 static void
1266 stonith_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1267 {
1268     if (cib_api) {
1269         cib_api->cmds->del_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb);
1270         cib_api->cmds->signoff(cib_api);
1271     }
1272 
1273     if (ipcs) {
1274         qb_ipcs_destroy(ipcs);
1275     }
1276 
1277     crm_peer_destroy();
1278     pcmk__client_cleanup();
1279     free_stonith_remote_op_list();
1280     free_topology_list();
1281     free_device_list();
1282     free_metadata_cache();
1283     fenced_unregister_handlers();
1284 
1285     free(stonith_our_uname);
1286     stonith_our_uname = NULL;
1287 
1288     free_xml(local_cib);
1289     local_cib = NULL;
1290 }
1291 
1292 static gboolean
1293 stand_alone_cpg_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
1294                    GError **error)
1295 {
1296     stand_alone = FALSE;
1297     options.no_cib_connect = true;
1298     return TRUE;
1299 }
1300 
1301 static void
1302 setup_cib(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1303 {
1304     int rc, retries = 0;
1305 
1306     cib_api = cib_new();
1307     if (cib_api == NULL) {
1308         crm_err("No connection to the CIB manager");
1309         return;
1310     }
1311 
1312     do {
1313         sleep(retries);
1314         rc = cib_api->cmds->signon(cib_api, CRM_SYSTEM_STONITHD, cib_command);
1315     } while (rc == -ENOTCONN && ++retries < 5);
1316 
1317     if (rc != pcmk_ok) {
1318         crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
1319 
1320     } else if (pcmk_ok !=
1321                cib_api->cmds->add_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb)) {
1322         crm_err("Could not set CIB notification callback");
1323 
1324     } else {
1325         rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_scope_local);
1326         cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL, "init_cib_cache_cb",
1327                                          init_cib_cache_cb);
1328         cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
1329         crm_info("Watching for fencing topology changes");
1330     }
1331 }
1332 
1333 struct qb_ipcs_service_handlers ipc_callbacks = {
1334     .connection_accept = st_ipc_accept,
1335     .connection_created = NULL,
1336     .msg_process = st_ipc_dispatch,
1337     .connection_closed = st_ipc_closed,
1338     .connection_destroyed = st_ipc_destroy
1339 };
1340 
1341 /*!
1342  * \internal
1343  * \brief Callback for peer status changes
1344  *
1345  * \param[in] type  What changed
1346  * \param[in] node  What peer had the change
1347  * \param[in] data  Previous value of what changed
1348  */
1349 static void
1350 st_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1351 {
1352     if ((type != crm_status_processes)
1353         && !pcmk_is_set(node->flags, crm_remote_node)) {
1354         /*
1355          * This is a hack until we can send to a nodeid and/or we fix node name lookups
1356          * These messages are ignored in stonith_peer_callback()
1357          */
1358         xmlNode *query = create_xml_node(NULL, "stonith_command");
1359 
1360         crm_xml_add(query, F_XML_TAGNAME, "stonith_command");
1361         crm_xml_add(query, F_TYPE, T_STONITH_NG);
1362         crm_xml_add(query, F_STONITH_OPERATION, "poke");
1363 
1364         crm_debug("Broadcasting our uname because of node %u", node->id);
1365         send_cluster_message(NULL, crm_msg_stonith_ng, query, FALSE);
1366 
1367         free_xml(query);
1368     }
1369 }
1370 
1371 static pcmk__cluster_option_t fencer_options[] = {
1372     /* name, old name, type, allowed values,
1373      * default value, validator,
1374      * short description,
1375      * long description
1376      */
1377     {
1378         PCMK_STONITH_HOST_ARGUMENT, NULL, "string", NULL, "port", NULL,
1379         N_("Advanced use only: An alternate parameter to supply instead of 'port'"),
1380         N_("some devices do not support the "
1381            "standard 'port' parameter or may provide additional ones. Use "
1382            "this to specify an alternate, device-specific, parameter "
1383            "that should indicate the machine to be fenced. A value of "
1384            "none can be used to tell the cluster not to supply any "
1385            "additional parameters.")
1386     },
1387     {
1388         PCMK_STONITH_HOST_MAP,NULL, "string", NULL, "", NULL,
1389         N_("A mapping of host names to ports numbers for devices that do not support host names."),
1390         N_("Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2")
1391     },
1392     {
1393         PCMK_STONITH_HOST_LIST,NULL, "string", NULL, "", NULL,
1394         N_("Eg. node1,node2,node3"),
1395         N_("A list of machines controlled by "
1396                "this device (Optional unless pcmk_host_list=static-list)")
1397     },
1398     {
1399         PCMK_STONITH_HOST_CHECK,NULL, "string", NULL, "dynamic-list", NULL,
1400         N_("How to determine which machines are controlled by the device."),
1401         N_("Allowed values: dynamic-list "
1402                "(query the device via the 'list' command), static-list "
1403                "(check the pcmk_host_list attribute), status "
1404                "(query the device via the 'status' command), "
1405                "none (assume every device can fence every "
1406                "machine)")
1407     },
1408     {
1409         PCMK_STONITH_DELAY_MAX,NULL, "time", NULL, "0s", NULL,
1410         N_("Enable a base delay for fencing actions and specify base delay value."),
1411         N_("Enable a delay of no more than the "
1412                "time specified before executing fencing actions. Pacemaker "
1413                "derives the overall delay by taking the value of "
1414                "pcmk_delay_base and adding a random delay value such "
1415                "that the sum is kept below this maximum.")
1416     },
1417     {
1418         PCMK_STONITH_DELAY_BASE,NULL, "string", NULL, "0s", NULL,
1419         N_("Enable a base delay for "
1420                "fencing actions and specify base delay value."),
1421         N_("This enables a static delay for "
1422                "fencing actions, which can help avoid \"death matches\" where "
1423                "two nodes try to fence each other at the same time. If "
1424                "pcmk_delay_max  is also used, a random delay will be "
1425                "added such that the total delay is kept below that value."
1426                "This can be set to a single time value to apply to any node "
1427                "targeted by this device (useful if a separate device is "
1428                "configured for each target), or to a node map (for example, "
1429                "\"node1:1s;node2:5\") to set a different value per target.")
1430     },
1431     {
1432         PCMK_STONITH_ACTION_LIMIT,NULL, "integer", NULL, "1", NULL,
1433         N_("The maximum number of actions can be performed in parallel on this device"),
1434         N_("Cluster property concurrent-fencing=true needs to be configured first."
1435              "Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited.")
1436     },
1437     {
1438         "pcmk_reboot_action",NULL, "string", NULL, "reboot", NULL,
1439         N_("Advanced use only: An alternate command to run instead of 'reboot'"),
1440         N_("Some devices do not support the standard commands or may provide additional ones.\n"
1441                  "Use this to specify an alternate, device-specific, command that implements the \'reboot\' action.")
1442     },
1443     {
1444         "pcmk_reboot_timeout",NULL, "time", NULL, "60s", NULL,
1445         N_("Advanced use only: Specify an alternate timeout to use for reboot actions instead of stonith-timeout"),
1446         N_("Some devices need much more/less time to complete than normal."
1447            "Use this to specify an alternate, device-specific, timeout for \'reboot\' actions.")
1448     },
1449     {
1450         "pcmk_reboot_retries",NULL, "integer", NULL, "2", NULL,
1451         N_("Advanced use only: The maximum number of times to retry the 'reboot' command within the timeout period"),
1452         N_("Some devices do not support multiple connections."
1453            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1454            " Use this option to alter the number of times Pacemaker retries \'reboot\' actions before giving up.")
1455     },
1456     {
1457         "pcmk_off_action",NULL, "string", NULL, "off", NULL,
1458         N_("Advanced use only: An alternate command to run instead of \'off\'"),
1459         N_("Some devices do not support the standard commands or may provide additional ones."
1460                  "Use this to specify an alternate, device-specific, command that implements the \'off\' action.")
1461     },
1462     {
1463         "pcmk_off_timeout",NULL, "time", NULL, "60s", NULL,
1464         N_("Advanced use only: Specify an alternate timeout to use for off actions instead of stonith-timeout"),
1465         N_("Some devices need much more/less time to complete than normal."
1466            "Use this to specify an alternate, device-specific, timeout for \'off\' actions.")
1467     },
1468     {
1469         "pcmk_off_retries",NULL, "integer", NULL, "2", NULL,
1470         N_("Advanced use only: The maximum number of times to retry the 'off' command within the timeout period"),
1471         N_("Some devices do not support multiple connections."
1472            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1473            " Use this option to alter the number of times Pacemaker retries \'off\' actions before giving up.")
1474     },
1475     {
1476         "pcmk_on_action",NULL, "string", NULL, "on", NULL,
1477         N_("Advanced use only: An alternate command to run instead of 'on'"),
1478         N_("Some devices do not support the standard commands or may provide additional ones."
1479                  "Use this to specify an alternate, device-specific, command that implements the \'on\' action.")
1480     },
1481     {
1482         "pcmk_on_timeout",NULL, "time", NULL, "60s", NULL,
1483         N_("Advanced use only: Specify an alternate timeout to use for on actions instead of stonith-timeout"),
1484         N_("Some devices need much more/less time to complete than normal."
1485            "Use this to specify an alternate, device-specific, timeout for \'on\' actions.")
1486     },
1487     {
1488         "pcmk_on_retries",NULL, "integer", NULL, "2", NULL,
1489         N_("Advanced use only: The maximum number of times to retry the 'on' command within the timeout period"),
1490         N_("Some devices do not support multiple connections."
1491            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1492            " Use this option to alter the number of times Pacemaker retries \'on\' actions before giving up.")
1493     },
1494     {
1495         "pcmk_list_action",NULL, "string", NULL, "list", NULL,
1496         N_("Advanced use only: An alternate command to run instead of \'list\'"),
1497         N_("Some devices do not support the standard commands or may provide additional ones."
1498                  "Use this to specify an alternate, device-specific, command that implements the \'list\' action.")
1499     },
1500     {
1501         "pcmk_list_timeout",NULL, "time", NULL, "60s", NULL,
1502         N_("Advanced use only: Specify an alternate timeout to use for list actions instead of stonith-timeout"),
1503         N_("Some devices need much more/less time to complete than normal."
1504            "Use this to specify an alternate, device-specific, timeout for \'list\' actions.")
1505     },
1506     {
1507         "pcmk_list_retries",NULL, "integer", NULL, "2", NULL,
1508         N_("Advanced use only: The maximum number of times to retry the \'list\' command within the timeout period"),
1509         N_("Some devices do not support multiple connections."
1510            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1511            " Use this option to alter the number of times Pacemaker retries \'list\' actions before giving up.")
1512     },
1513     {
1514         "pcmk_monitor_action",NULL, "string", NULL, "monitor", NULL,
1515         N_("Advanced use only: An alternate command to run instead of \'monitor\'"),
1516         N_("Some devices do not support the standard commands or may provide additional ones."
1517                  "Use this to specify an alternate, device-specific, command that implements the \'monitor\' action.")
1518     },
1519     {
1520         "pcmk_monitor_timeout",NULL, "time", NULL, "60s", NULL,
1521         N_("Advanced use only: Specify an alternate timeout to use for monitor actions instead of stonith-timeout"),
1522         N_("Some devices need much more/less time to complete than normal.\n"
1523            "Use this to specify an alternate, device-specific, timeout for \'monitor\' actions.")
1524     },
1525     {
1526         "pcmk_monitor_retries",NULL, "integer", NULL, "2", NULL,
1527         N_("Advanced use only: The maximum number of times to retry the \'monitor\' command within the timeout period"),
1528         N_("Some devices do not support multiple connections."
1529            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1530            " Use this option to alter the number of times Pacemaker retries \'monitor\' actions before giving up.")
1531     },
1532     {
1533         "pcmk_status_action",NULL, "string", NULL, "status", NULL,
1534         N_("Advanced use only: An alternate command to run instead of \'status\'"),
1535         N_("Some devices do not support the standard commands or may provide additional ones."
1536                  "Use this to specify an alternate, device-specific, command that implements the \'status\' action.")
1537     },
1538     {
1539         "pcmk_status_timeout",NULL, "time", NULL, "60s", NULL,
1540         N_("Advanced use only: Specify an alternate timeout to use for status actions instead of stonith-timeout"),
1541         N_("Some devices need much more/less time to complete than normal."
1542            "Use this to specify an alternate, device-specific, timeout for \'status\' actions.")
1543     },
1544     {
1545         "pcmk_status_retries",NULL, "integer", NULL, "2", NULL,
1546         N_("Advanced use only: The maximum number of times to retry the \'status\' command within the timeout period"),
1547         N_("Some devices do not support multiple connections."
1548            " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation,      if there is time remaining."
1549            " Use this option to alter the number of times Pacemaker retries \'status\' actions before giving up.")
1550     },
1551 };
1552 
1553 void
1554 fencer_metadata(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1555 {
1556     const char *desc_short = N_("Instance attributes available for all "
1557                              "\"stonith\"-class resources");
1558     const char *desc_long = N_("Instance attributes available for all \"stonith\"-"
1559                             "class resources and used by Pacemaker's fence "
1560                             "daemon, formerly known as stonithd");
1561 
1562     gchar *s = pcmk__format_option_metadata("pacemaker-fenced", desc_short,
1563                                             desc_long, fencer_options,
1564                                             PCMK__NELEM(fencer_options));
1565     printf("%s", s);
1566     g_free(s);
1567 }
1568 
1569 static GOptionEntry entries[] = {
1570     { "stand-alone", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &stand_alone,
1571       "Deprecated (will be removed in a future release)", NULL },
1572 
1573     { "stand-alone-w-cpg", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
1574       stand_alone_cpg_cb, "Intended for use in regression testing only", NULL },
1575 
1576     { "logfile", 'l', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME_ARRAY,
1577       &options.log_files, "Send logs to the additional named logfile", NULL },
1578 
1579     { NULL }
1580 };
1581 
1582 static GOptionContext *
1583 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
     /* [previous][next][first][last][top][bottom][index][help] */
1584 {
1585     GOptionContext *context = NULL;
1586 
1587     context = pcmk__build_arg_context(args, "text (default), xml", group,
1588                                       "[metadata]");
1589     pcmk__add_main_args(context, entries);
1590     return context;
1591 }
1592 
1593 int
1594 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
1595 {
1596     int rc = pcmk_rc_ok;
1597     crm_cluster_t *cluster = NULL;
1598     crm_ipc_t *old_instance = NULL;
1599 
1600     GError *error = NULL;
1601 
1602     GOptionGroup *output_group = NULL;
1603     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
1604     gchar **processed_args = pcmk__cmdline_preproc(argv, "l");
1605     GOptionContext *context = build_arg_context(args, &output_group);
1606 
1607     crm_log_preinit(NULL, argc, argv);
1608 
1609     pcmk__register_formats(output_group, formats);
1610     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
1611         exit_code = CRM_EX_USAGE;
1612         goto done;
1613     }
1614 
1615     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
1616     if (rc != pcmk_rc_ok) {
1617         exit_code = CRM_EX_ERROR;
1618         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1619                     "Error creating output format %s: %s",
1620                     args->output_ty, pcmk_rc_str(rc));
1621         goto done;
1622     }
1623 
1624     if (args->version) {
1625         out->version(out, false);
1626         goto done;
1627     }
1628 
1629     if ((g_strv_length(processed_args) >= 2)
1630         && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
1631         fencer_metadata();
1632         goto done;
1633     }
1634 
1635     // Open additional log files
1636     pcmk__add_logfiles(options.log_files, out);
1637 
1638     crm_log_init(NULL, LOG_INFO + args->verbosity, TRUE,
1639                  (args->verbosity > 0), argc, argv, FALSE);
1640 
1641     crm_notice("Starting Pacemaker fencer");
1642 
1643     old_instance = crm_ipc_new("stonith-ng", 0);
1644     if (old_instance == NULL) {
1645         /* crm_ipc_new() will have already logged an error message with
1646          * crm_err()
1647          */
1648         exit_code = CRM_EX_FATAL;
1649         goto done;
1650     }
1651 
1652     if (crm_ipc_connect(old_instance)) {
1653         // IPC endpoint already up
1654         crm_ipc_close(old_instance);
1655         crm_ipc_destroy(old_instance);
1656         crm_err("pacemaker-fenced is already active, aborting startup");
1657         goto done;
1658     } else {
1659         // Not up or not authentic, we'll proceed either way
1660         crm_ipc_destroy(old_instance);
1661         old_instance = NULL;
1662     }
1663 
1664     mainloop_add_signal(SIGTERM, stonith_shutdown);
1665 
1666     crm_peer_init();
1667 
1668     fenced_data_set = pe_new_working_set();
1669     CRM_ASSERT(fenced_data_set != NULL);
1670 
1671     cluster = pcmk_cluster_new();
1672 
1673     /* Initialize the logger prior to setup_cib(). update_cib_cache_cb() may
1674      * call the "xml-patchset" message function, which needs the logger, after
1675      * setup_cib() has run.
1676      */
1677     rc = pcmk__log_output_new(&logger_out) != pcmk_rc_ok;
1678     if (rc != pcmk_rc_ok) {
1679         exit_code = CRM_EX_FATAL;
1680         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1681                     "Error creating output format log: %s", pcmk_rc_str(rc));
1682         goto done;
1683     }
1684     pe__register_messages(logger_out);
1685     pcmk__register_lib_messages(logger_out);
1686     pcmk__output_set_log_level(logger_out, LOG_TRACE);
1687     fenced_data_set->priv = logger_out;
1688 
1689     if (!stand_alone) {
1690 #if SUPPORT_COROSYNC
1691         if (is_corosync_cluster()) {
1692             cluster->destroy = stonith_peer_cs_destroy;
1693             cluster->cpg.cpg_deliver_fn = stonith_peer_ais_callback;
1694             cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
1695         }
1696 #endif // SUPPORT_COROSYNC
1697 
1698         crm_set_status_callback(&st_peer_update_callback);
1699 
1700         if (crm_cluster_connect(cluster) == FALSE) {
1701             exit_code = CRM_EX_FATAL;
1702             crm_crit("Cannot sign in to the cluster... terminating");
1703             goto done;
1704         }
1705         pcmk__str_update(&stonith_our_uname, cluster->uname);
1706 
1707         if (!options.no_cib_connect) {
1708             setup_cib();
1709         }
1710 
1711     } else {
1712         pcmk__str_update(&stonith_our_uname, "localhost");
1713         crm_warn("Stand-alone mode is deprecated and will be removed "
1714                  "in a future release");
1715     }
1716 
1717     init_device_list();
1718     init_topology_list();
1719 
1720     pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks);
1721 
1722     // Create the mainloop and run it...
1723     mainloop = g_main_loop_new(NULL, FALSE);
1724     crm_notice("Pacemaker fencer successfully started and accepting connections");
1725     g_main_loop_run(mainloop);
1726 
1727 done:
1728     g_strfreev(processed_args);
1729     pcmk__free_arg_context(context);
1730 
1731     g_strfreev(options.log_files);
1732 
1733     stonith_cleanup();
1734     pcmk_cluster_free(cluster);
1735     pe_free_working_set(fenced_data_set);
1736 
1737     pcmk__output_and_clear_error(&error, out);
1738 
1739     if (logger_out != NULL) {
1740         logger_out->finish(logger_out, exit_code, true, NULL);
1741         pcmk__output_free(logger_out);
1742     }
1743 
1744     if (out != NULL) {
1745         out->finish(out, exit_code, true, NULL);
1746         pcmk__output_free(out);
1747     }
1748 
1749     pcmk__unregister_formats();
1750     crm_exit(exit_code);
1751 }

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