This source file includes following definitions.
- time_is_set
 
- get_current_time
 
- time_diff_ms
 
- cmd_original_times
 
- action_matches
 
- log_finished
 
- log_execute
 
- normalize_action_name
 
- build_rsc_from_xml
 
- create_lrmd_cmd
 
- stop_recurring_timer
 
- free_lrmd_cmd
 
- stonith_recurring_op_helper
 
- start_recurring_timer
 
- start_delay_helper
 
- find_duplicate_action
 
- merge_recurring_duplicate
 
- schedule_lrmd_cmd
 
- create_lrmd_reply
 
- send_client_notify
 
- send_cmd_complete_notify
 
- send_generic_notify
 
- cmd_reset
 
- cmd_finalize
 
- notify_one_client
 
- notify_of_new_client
 
- client_disconnect_cleanup
 
- action_complete
 
- stonith_action_complete
 
- lrmd_stonith_callback
 
- stonith_connection_failed
 
- execd_stonith_start
 
- execd_stonith_stop
 
- execd_stonith_monitor
 
- execute_stonith_action
 
- execute_nonstonith_action
 
- execute_resource_action
 
- free_rsc
 
- process_lrmd_signon
 
- process_lrmd_rsc_register
 
- process_lrmd_get_rsc_info
 
- process_lrmd_rsc_unregister
 
- process_lrmd_rsc_exec
 
- cancel_op
 
- cancel_all_recurring
 
- process_lrmd_rsc_cancel
 
- add_recurring_op_xml
 
- process_lrmd_get_recurring
 
- process_lrmd_message
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 #include <crm/fencing/internal.h>
  12 
  13 #include <glib.h>
  14 
  15 
  16 #undef PCMK__TIME_USE_CGT
  17 #if HAVE_DECL_CLOCK_MONOTONIC && defined(CLOCK_MONOTONIC)
  18 #  define PCMK__TIME_USE_CGT
  19 #  include <time.h>  
  20 #endif
  21 
  22 #include <unistd.h>
  23 
  24 #include <crm/crm.h>
  25 #include <crm/fencing/internal.h>
  26 #include <crm/services.h>
  27 #include <crm/services_internal.h>
  28 #include <crm/common/mainloop.h>
  29 #include <crm/common/ipc.h>
  30 #include <crm/common/ipc_internal.h>
  31 #include <crm/common/xml.h>
  32 
  33 #include "pacemaker-execd.h"
  34 
  35 GHashTable *rsc_list = NULL;
  36 
  37 typedef struct lrmd_cmd_s {
  38     int timeout;
  39     guint interval_ms;
  40     int start_delay;
  41     int timeout_orig;
  42 
  43     int call_id;
  44 
  45     int call_opts;
  46     
  47     int delay_id;
  48     int stonith_recurring_id;
  49 
  50     int rsc_deleted;
  51 
  52     int service_flags;
  53 
  54     char *client_id;
  55     char *origin;
  56     char *rsc_id;
  57     char *action;
  58     char *real_action;
  59     char *userdata_str;
  60 
  61     pcmk__action_result_t result;
  62 
  63     
  64 
  65 
  66 
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 #ifdef PCMK__TIME_USE_CGT
  80     
  81 
  82 
  83 
  84     struct timespec t_first_run;    
  85     struct timespec t_run;          
  86     struct timespec t_first_queue;  
  87     struct timespec t_queue;        
  88 #endif
  89     time_t epoch_last_run;          
  90     time_t epoch_rcchange;          
  91 
  92     bool first_notify_sent;
  93     int last_notify_rc;
  94     int last_notify_op_status;
  95     int last_pid;
  96 
  97     GHashTable *params;
  98 } lrmd_cmd_t;
  99 
 100 static void cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc);
 101 static gboolean execute_resource_action(gpointer user_data);
 102 static void cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id);
 103 
 104 #ifdef PCMK__TIME_USE_CGT
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 static inline bool
 115 time_is_set(const struct timespec *timespec)
     
 116 {
 117     return (timespec != NULL) &&
 118            ((timespec->tv_sec != 0) || (timespec->tv_nsec != 0));
 119 }
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 static void
 129 get_current_time(struct timespec *t_current, struct timespec *t_orig)
     
 130 {
 131     clock_gettime(CLOCK_MONOTONIC, t_current);
 132     if ((t_orig != NULL) && !time_is_set(t_orig)) {
 133         *t_orig = *t_current;
 134     }
 135 }
 136 
 137 
 138 
 139 
 140 
 141 
 142 
 143 
 144 
 145 
 146 
 147 
 148 
 149 static int
 150 time_diff_ms(const struct timespec *now, const struct timespec *old)
     
 151 {
 152     int diff_ms = 0;
 153 
 154     if (time_is_set(old)) {
 155         struct timespec local_now = { 0, };
 156 
 157         if (now == NULL) {
 158             clock_gettime(CLOCK_MONOTONIC, &local_now);
 159             now = &local_now;
 160         }
 161         diff_ms = (now->tv_sec - old->tv_sec) * 1000
 162                   + (now->tv_nsec - old->tv_nsec) / 1000000;
 163     }
 164     return diff_ms;
 165 }
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173 
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 static void
 188 cmd_original_times(lrmd_cmd_t * cmd)
     
 189 {
 190     cmd->t_run = cmd->t_first_run;
 191     cmd->t_queue = cmd->t_first_queue;
 192 }
 193 #endif
 194 
 195 static inline bool
 196 action_matches(const lrmd_cmd_t *cmd, const char *action, guint interval_ms)
     
 197 {
 198     return (cmd->interval_ms == interval_ms)
 199            && pcmk__str_eq(cmd->action, action, pcmk__str_casei);
 200 }
 201 
 202 
 203 
 204 
 205 
 206 
 207 
 208 
 209 
 210 static void
 211 log_finished(const lrmd_cmd_t *cmd, int exec_time_ms, int queue_time_ms)
     
 212 {
 213     int log_level = LOG_INFO;
 214     GString *str = g_string_sized_new(100); 
 215 
 216     if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
 217         log_level = LOG_DEBUG;
 218     }
 219 
 220     g_string_append_printf(str, "%s %s (call %d",
 221                            cmd->rsc_id, cmd->action, cmd->call_id);
 222     if (cmd->last_pid != 0) {
 223         g_string_append_printf(str, ", PID %d", cmd->last_pid);
 224     }
 225     if (cmd->result.execution_status == PCMK_EXEC_DONE) {
 226         g_string_append_printf(str, ") exited with status %d",
 227                                cmd->result.exit_status);
 228     } else {
 229         pcmk__g_strcat(str, ") could not be executed: ",
 230                        pcmk_exec_status_str(cmd->result.execution_status),
 231                        NULL);
 232     }
 233     if (cmd->result.exit_reason != NULL) {
 234         pcmk__g_strcat(str, " (", cmd->result.exit_reason, ")", NULL);
 235     }
 236 
 237 #ifdef PCMK__TIME_USE_CGT
 238     pcmk__g_strcat(str, " (execution time ",
 239                    pcmk__readable_interval(exec_time_ms), NULL);
 240     if (queue_time_ms > 0) {
 241         pcmk__g_strcat(str, " after being queued ",
 242                        pcmk__readable_interval(queue_time_ms), NULL);
 243     }
 244     g_string_append_c(str, ')');
 245 #endif
 246 
 247     do_crm_log(log_level, "%s", str->str);
 248     g_string_free(str, TRUE);
 249 }
 250 
 251 static void
 252 log_execute(lrmd_cmd_t * cmd)
     
 253 {
 254     int log_level = LOG_INFO;
 255 
 256     if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
 257         log_level = LOG_DEBUG;
 258     }
 259 
 260     do_crm_log(log_level, "executing - rsc:%s action:%s call_id:%d",
 261                cmd->rsc_id, cmd->action, cmd->call_id);
 262 }
 263 
 264 static const char *
 265 normalize_action_name(lrmd_rsc_t * rsc, const char *action)
     
 266 {
 267     if (pcmk__str_eq(action, PCMK_ACTION_MONITOR, pcmk__str_casei) &&
 268         pcmk_is_set(pcmk_get_ra_caps(rsc->class), pcmk_ra_cap_status)) {
 269         return PCMK_ACTION_STATUS;
 270     }
 271     return action;
 272 }
 273 
 274 static lrmd_rsc_t *
 275 build_rsc_from_xml(xmlNode * msg)
     
 276 {
 277     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, msg, LOG_ERR);
 278     lrmd_rsc_t *rsc = NULL;
 279 
 280     rsc = pcmk__assert_alloc(1, sizeof(lrmd_rsc_t));
 281 
 282     crm_element_value_int(msg, PCMK__XA_LRMD_CALLOPT, &rsc->call_opts);
 283 
 284     rsc->rsc_id = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ID);
 285     rsc->class = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_CLASS);
 286     rsc->provider = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_PROVIDER);
 287     rsc->type = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_TYPE);
 288     rsc->work = mainloop_add_trigger(G_PRIORITY_HIGH, execute_resource_action,
 289                                      rsc);
 290 
 291     
 292     pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
 293                      PCMK_EXEC_NO_FENCE_DEVICE, NULL);
 294     return rsc;
 295 }
 296 
 297 static lrmd_cmd_t *
 298 create_lrmd_cmd(xmlNode *msg, pcmk__client_t *client)
     
 299 {
 300     int call_options = 0;
 301     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, msg, LOG_ERR);
 302     lrmd_cmd_t *cmd = NULL;
 303 
 304     cmd = pcmk__assert_alloc(1, sizeof(lrmd_cmd_t));
 305 
 306     crm_element_value_int(msg, PCMK__XA_LRMD_CALLOPT, &call_options);
 307     cmd->call_opts = call_options;
 308     cmd->client_id = pcmk__str_copy(client->id);
 309 
 310     crm_element_value_int(msg, PCMK__XA_LRMD_CALLID, &cmd->call_id);
 311     crm_element_value_ms(rsc_xml, PCMK__XA_LRMD_RSC_INTERVAL,
 312                          &cmd->interval_ms);
 313     crm_element_value_int(rsc_xml, PCMK__XA_LRMD_TIMEOUT, &cmd->timeout);
 314     crm_element_value_int(rsc_xml, PCMK__XA_LRMD_RSC_START_DELAY,
 315                           &cmd->start_delay);
 316     cmd->timeout_orig = cmd->timeout;
 317 
 318     cmd->origin = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_ORIGIN);
 319     cmd->action = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ACTION);
 320     cmd->userdata_str = crm_element_value_copy(rsc_xml,
 321                                                PCMK__XA_LRMD_RSC_USERDATA_STR);
 322     cmd->rsc_id = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ID);
 323 
 324     cmd->params = xml2list(rsc_xml);
 325 
 326     if (pcmk__str_eq(g_hash_table_lookup(cmd->params, "CRM_meta_on_fail"),
 327                      PCMK_VALUE_BLOCK, pcmk__str_casei)) {
 328         crm_debug("Setting flag to leave pid group on timeout and "
 329                   "only kill action pid for " PCMK__OP_FMT,
 330                   cmd->rsc_id, cmd->action, cmd->interval_ms);
 331         cmd->service_flags = pcmk__set_flags_as(__func__, __LINE__,
 332                                                 LOG_TRACE, "Action",
 333                                                 cmd->action, 0,
 334                                                 SVC_ACTION_LEAVE_GROUP,
 335                                                 "SVC_ACTION_LEAVE_GROUP");
 336     }
 337     return cmd;
 338 }
 339 
 340 static void
 341 stop_recurring_timer(lrmd_cmd_t *cmd)
     
 342 {
 343     if (cmd) {
 344         if (cmd->stonith_recurring_id) {
 345             g_source_remove(cmd->stonith_recurring_id);
 346         }
 347         cmd->stonith_recurring_id = 0;
 348     }
 349 }
 350 
 351 static void
 352 free_lrmd_cmd(lrmd_cmd_t * cmd)
     
 353 {
 354     stop_recurring_timer(cmd);
 355     if (cmd->delay_id) {
 356         g_source_remove(cmd->delay_id);
 357     }
 358     if (cmd->params) {
 359         g_hash_table_destroy(cmd->params);
 360     }
 361     pcmk__reset_result(&(cmd->result));
 362     free(cmd->origin);
 363     free(cmd->action);
 364     free(cmd->real_action);
 365     free(cmd->userdata_str);
 366     free(cmd->rsc_id);
 367     free(cmd->client_id);
 368     free(cmd);
 369 }
 370 
 371 static gboolean
 372 stonith_recurring_op_helper(gpointer data)
     
 373 {
 374     lrmd_cmd_t *cmd = data;
 375     lrmd_rsc_t *rsc;
 376 
 377     cmd->stonith_recurring_id = 0;
 378 
 379     if (!cmd->rsc_id) {
 380         return FALSE;
 381     }
 382 
 383     rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
 384 
 385     CRM_ASSERT(rsc != NULL);
 386     
 387 
 388     rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
 389     rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
 390 #ifdef PCMK__TIME_USE_CGT
 391     get_current_time(&(cmd->t_queue), &(cmd->t_first_queue));
 392 #endif
 393     mainloop_set_trigger(rsc->work);
 394 
 395     return FALSE;
 396 }
 397 
 398 static inline void
 399 start_recurring_timer(lrmd_cmd_t *cmd)
     
 400 {
 401     if (cmd && (cmd->interval_ms > 0)) {
 402         cmd->stonith_recurring_id = g_timeout_add(cmd->interval_ms,
 403                                                   stonith_recurring_op_helper,
 404                                                   cmd);
 405     }
 406 }
 407 
 408 static gboolean
 409 start_delay_helper(gpointer data)
     
 410 {
 411     lrmd_cmd_t *cmd = data;
 412     lrmd_rsc_t *rsc = NULL;
 413 
 414     cmd->delay_id = 0;
 415     rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
 416 
 417     if (rsc) {
 418         mainloop_set_trigger(rsc->work);
 419     }
 420 
 421     return FALSE;
 422 }
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 static lrmd_cmd_t *
 432 find_duplicate_action(const GList *action_list, const lrmd_cmd_t *cmd)
     
 433 {
 434     for (const GList *item = action_list; item != NULL; item = item->next) {
 435         lrmd_cmd_t *dup = item->data;
 436 
 437         if (action_matches(cmd, dup->action, dup->interval_ms)) {
 438             return dup;
 439         }
 440     }
 441     return NULL;
 442 }
 443 
 444 static bool
 445 merge_recurring_duplicate(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
     
 446 {
 447     lrmd_cmd_t * dup = NULL;
 448     bool dup_pending = true;
 449 
 450     if (cmd->interval_ms == 0) {
 451         return false;
 452     }
 453 
 454     
 455     dup = find_duplicate_action(rsc->pending_ops, cmd);
 456     if (dup == NULL) {
 457         dup_pending = false;
 458         dup = find_duplicate_action(rsc->recurring_ops, cmd);
 459         if (dup == NULL) {
 460             return false;
 461         }
 462     }
 463 
 464     
 465 
 466 
 467     if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
 468                      pcmk__str_casei)
 469         && (dup->result.execution_status == PCMK_EXEC_CANCELLED)) {
 470         return false;
 471     }
 472 
 473     
 474 
 475 
 476     crm_warn("Duplicate recurring op entry detected (" PCMK__OP_FMT
 477              "), merging with previous op entry",
 478              rsc->rsc_id, normalize_action_name(rsc, dup->action),
 479              dup->interval_ms);
 480 
 481     
 482     dup->first_notify_sent = false;
 483     free(dup->userdata_str);
 484     dup->userdata_str = cmd->userdata_str;
 485     cmd->userdata_str = NULL;
 486     dup->call_id = cmd->call_id;
 487     free_lrmd_cmd(cmd);
 488     cmd = NULL;
 489 
 490     
 491 
 492 
 493 
 494     if (!dup_pending) {
 495         if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
 496                          pcmk__str_casei)) {
 497             stop_recurring_timer(dup);
 498             stonith_recurring_op_helper(dup);
 499         } else {
 500             services_action_kick(rsc->rsc_id,
 501                                  normalize_action_name(rsc, dup->action),
 502                                  dup->interval_ms);
 503         }
 504     }
 505     return true;
 506 }
 507 
 508 static void
 509 schedule_lrmd_cmd(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
     
 510 {
 511     CRM_CHECK(cmd != NULL, return);
 512     CRM_CHECK(rsc != NULL, return);
 513 
 514     crm_trace("Scheduling %s on %s", cmd->action, rsc->rsc_id);
 515 
 516     if (merge_recurring_duplicate(rsc, cmd)) {
 517         
 518         return;
 519     }
 520 
 521     
 522 
 523 
 524     if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
 525         cancel_all_recurring(rsc, NULL);
 526     }
 527 
 528     rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
 529 #ifdef PCMK__TIME_USE_CGT
 530     get_current_time(&(cmd->t_queue), &(cmd->t_first_queue));
 531 #endif
 532     mainloop_set_trigger(rsc->work);
 533 
 534     if (cmd->start_delay) {
 535         cmd->delay_id = g_timeout_add(cmd->start_delay, start_delay_helper, cmd);
 536     }
 537 }
 538 
 539 static xmlNode *
 540 create_lrmd_reply(const char *origin, int rc, int call_id)
     
 541 {
 542     xmlNode *reply = pcmk__xe_create(NULL, PCMK__XE_LRMD_REPLY);
 543 
 544     crm_xml_add(reply, PCMK__XA_LRMD_ORIGIN, origin);
 545     crm_xml_add_int(reply, PCMK__XA_LRMD_RC, rc);
 546     crm_xml_add_int(reply, PCMK__XA_LRMD_CALLID, call_id);
 547     return reply;
 548 }
 549 
 550 static void
 551 send_client_notify(gpointer key, gpointer value, gpointer user_data)
     
 552 {
 553     xmlNode *update_msg = user_data;
 554     pcmk__client_t *client = value;
 555     int rc;
 556     int log_level = LOG_WARNING;
 557     const char *msg = NULL;
 558 
 559     CRM_CHECK(client != NULL, return);
 560     if (client->name == NULL) {
 561         crm_trace("Skipping notification to client without name");
 562         return;
 563     }
 564     if (pcmk_is_set(client->flags, pcmk__client_to_proxy)) {
 565         
 566 
 567 
 568 
 569         crm_trace("Skipping executor API notification to client %s",
 570                   pcmk__client_name(client));
 571         return;
 572     }
 573 
 574     rc = lrmd_server_send_notify(client, update_msg);
 575     if (rc == pcmk_rc_ok) {
 576         return;
 577     }
 578 
 579     switch (rc) {
 580         case ENOTCONN:
 581         case EPIPE: 
 582             log_level = LOG_INFO;
 583             msg = "Disconnected";
 584             break;
 585 
 586         default:
 587             msg = pcmk_rc_str(rc);
 588             break;
 589     }
 590     do_crm_log(log_level, "Could not notify client %s: %s " CRM_XS " rc=%d",
 591                pcmk__client_name(client), msg, rc);
 592 }
 593 
 594 static void
 595 send_cmd_complete_notify(lrmd_cmd_t * cmd)
     
 596 {
 597     xmlNode *notify = NULL;
 598     int exec_time = 0;
 599     int queue_time = 0;
 600 
 601 #ifdef PCMK__TIME_USE_CGT
 602     exec_time = time_diff_ms(NULL, &(cmd->t_run));
 603     queue_time = time_diff_ms(&cmd->t_run, &(cmd->t_queue));
 604 #endif
 605     log_finished(cmd, exec_time, queue_time);
 606 
 607     
 608 
 609 
 610     if (cmd->first_notify_sent
 611         && pcmk_is_set(cmd->call_opts, lrmd_opt_notify_changes_only)
 612         && (cmd->last_notify_rc == cmd->result.exit_status)
 613         && (cmd->last_notify_op_status == cmd->result.execution_status)) {
 614         return;
 615     }
 616 
 617     cmd->first_notify_sent = true;
 618     cmd->last_notify_rc = cmd->result.exit_status;
 619     cmd->last_notify_op_status = cmd->result.execution_status;
 620 
 621     notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
 622 
 623     crm_xml_add(notify, PCMK__XA_LRMD_ORIGIN, __func__);
 624     crm_xml_add_int(notify, PCMK__XA_LRMD_TIMEOUT, cmd->timeout);
 625     crm_xml_add_ms(notify, PCMK__XA_LRMD_RSC_INTERVAL, cmd->interval_ms);
 626     crm_xml_add_int(notify, PCMK__XA_LRMD_RSC_START_DELAY, cmd->start_delay);
 627     crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_RC, cmd->result.exit_status);
 628     crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_OP_STATUS,
 629                     cmd->result.execution_status);
 630     crm_xml_add_int(notify, PCMK__XA_LRMD_CALLID, cmd->call_id);
 631     crm_xml_add_int(notify, PCMK__XA_LRMD_RSC_DELETED, cmd->rsc_deleted);
 632 
 633     crm_xml_add_ll(notify, PCMK__XA_LRMD_RUN_TIME,
 634                    (long long) cmd->epoch_last_run);
 635     crm_xml_add_ll(notify, PCMK__XA_LRMD_RCCHANGE_TIME,
 636                    (long long) cmd->epoch_rcchange);
 637 #ifdef PCMK__TIME_USE_CGT
 638     crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_TIME, exec_time);
 639     crm_xml_add_int(notify, PCMK__XA_LRMD_QUEUE_TIME, queue_time);
 640 #endif
 641 
 642     crm_xml_add(notify, PCMK__XA_LRMD_OP, LRMD_OP_RSC_EXEC);
 643     crm_xml_add(notify, PCMK__XA_LRMD_RSC_ID, cmd->rsc_id);
 644     if(cmd->real_action) {
 645         crm_xml_add(notify, PCMK__XA_LRMD_RSC_ACTION, cmd->real_action);
 646     } else {
 647         crm_xml_add(notify, PCMK__XA_LRMD_RSC_ACTION, cmd->action);
 648     }
 649     crm_xml_add(notify, PCMK__XA_LRMD_RSC_USERDATA_STR, cmd->userdata_str);
 650     crm_xml_add(notify, PCMK__XA_LRMD_RSC_EXIT_REASON, cmd->result.exit_reason);
 651 
 652     if (cmd->result.action_stderr != NULL) {
 653         crm_xml_add(notify, PCMK__XA_LRMD_RSC_OUTPUT,
 654                     cmd->result.action_stderr);
 655 
 656     } else if (cmd->result.action_stdout != NULL) {
 657         crm_xml_add(notify, PCMK__XA_LRMD_RSC_OUTPUT,
 658                     cmd->result.action_stdout);
 659     }
 660 
 661     if (cmd->params) {
 662         char *key = NULL;
 663         char *value = NULL;
 664         GHashTableIter iter;
 665 
 666         xmlNode *args = pcmk__xe_create(notify, PCMK__XE_ATTRIBUTES);
 667 
 668         g_hash_table_iter_init(&iter, cmd->params);
 669         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
 670             hash2smartfield((gpointer) key, (gpointer) value, args);
 671         }
 672     }
 673     if ((cmd->client_id != NULL)
 674         && pcmk_is_set(cmd->call_opts, lrmd_opt_notify_orig_only)) {
 675 
 676         pcmk__client_t *client = pcmk__find_client_by_id(cmd->client_id);
 677 
 678         if (client != NULL) {
 679             send_client_notify(client->id, client, notify);
 680         }
 681     } else {
 682         pcmk__foreach_ipc_client(send_client_notify, notify);
 683     }
 684 
 685     free_xml(notify);
 686 }
 687 
 688 static void
 689 send_generic_notify(int rc, xmlNode * request)
     
 690 {
 691     if (pcmk__ipc_client_count() != 0) {
 692         int call_id = 0;
 693         xmlNode *notify = NULL;
 694         xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
 695                                             LOG_ERR);
 696         const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
 697         const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
 698 
 699         crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &call_id);
 700 
 701         notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
 702         crm_xml_add(notify, PCMK__XA_LRMD_ORIGIN, __func__);
 703         crm_xml_add_int(notify, PCMK__XA_LRMD_RC, rc);
 704         crm_xml_add_int(notify, PCMK__XA_LRMD_CALLID, call_id);
 705         crm_xml_add(notify, PCMK__XA_LRMD_OP, op);
 706         crm_xml_add(notify, PCMK__XA_LRMD_RSC_ID, rsc_id);
 707 
 708         pcmk__foreach_ipc_client(send_client_notify, notify);
 709 
 710         free_xml(notify);
 711     }
 712 }
 713 
 714 static void
 715 cmd_reset(lrmd_cmd_t * cmd)
     
 716 {
 717     cmd->last_pid = 0;
 718 #ifdef PCMK__TIME_USE_CGT
 719     memset(&cmd->t_run, 0, sizeof(cmd->t_run));
 720     memset(&cmd->t_queue, 0, sizeof(cmd->t_queue));
 721 #endif
 722     cmd->epoch_last_run = 0;
 723 
 724     pcmk__reset_result(&(cmd->result));
 725     cmd->result.execution_status = PCMK_EXEC_DONE;
 726 }
 727 
 728 static void
 729 cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc)
     
 730 {
 731     crm_trace("Resource operation rsc:%s action:%s completed (%p %p)", cmd->rsc_id, cmd->action,
 732               rsc ? rsc->active : NULL, cmd);
 733 
 734     if (rsc && (rsc->active == cmd)) {
 735         rsc->active = NULL;
 736         mainloop_set_trigger(rsc->work);
 737     }
 738 
 739     if (!rsc) {
 740         cmd->rsc_deleted = 1;
 741     }
 742 
 743     
 744     cmd->timeout = cmd->timeout_orig;
 745 
 746     send_cmd_complete_notify(cmd);
 747 
 748     if ((cmd->interval_ms != 0)
 749         && (cmd->result.execution_status == PCMK_EXEC_CANCELLED)) {
 750 
 751         if (rsc) {
 752             rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
 753             rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
 754         }
 755         free_lrmd_cmd(cmd);
 756     } else if (cmd->interval_ms == 0) {
 757         if (rsc) {
 758             rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
 759         }
 760         free_lrmd_cmd(cmd);
 761     } else {
 762         
 763         cmd_reset(cmd);
 764     }
 765 }
 766 
 767 struct notify_new_client_data {
 768     xmlNode *notify;
 769     pcmk__client_t *new_client;
 770 };
 771 
 772 static void
 773 notify_one_client(gpointer key, gpointer value, gpointer user_data)
     
 774 {
 775     pcmk__client_t *client = value;
 776     struct notify_new_client_data *data = user_data;
 777 
 778     if (!pcmk__str_eq(client->id, data->new_client->id, pcmk__str_casei)) {
 779         send_client_notify(key, (gpointer) client, (gpointer) data->notify);
 780     }
 781 }
 782 
 783 void
 784 notify_of_new_client(pcmk__client_t *new_client)
     
 785 {
 786     struct notify_new_client_data data;
 787 
 788     data.new_client = new_client;
 789     data.notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
 790     crm_xml_add(data.notify, PCMK__XA_LRMD_ORIGIN, __func__);
 791     crm_xml_add(data.notify, PCMK__XA_LRMD_OP, LRMD_OP_NEW_CLIENT);
 792     pcmk__foreach_ipc_client(notify_one_client, &data);
 793     free_xml(data.notify);
 794 }
 795 
 796 void
 797 client_disconnect_cleanup(const char *client_id)
     
 798 {
 799     GHashTableIter iter;
 800     lrmd_rsc_t *rsc = NULL;
 801     char *key = NULL;
 802 
 803     g_hash_table_iter_init(&iter, rsc_list);
 804     while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
 805         if (pcmk_all_flags_set(rsc->call_opts, lrmd_opt_drop_recurring)) {
 806             
 807 
 808             cancel_all_recurring(rsc, client_id);
 809         }
 810     }
 811 }
 812 
 813 static void
 814 action_complete(svc_action_t * action)
     
 815 {
 816     lrmd_rsc_t *rsc;
 817     lrmd_cmd_t *cmd = action->cb_data;
 818     enum ocf_exitcode code;
 819 
 820 #ifdef PCMK__TIME_USE_CGT
 821     const char *rclass = NULL;
 822     bool goagain = false;
 823 #endif
 824 
 825     if (!cmd) {
 826         crm_err("Completed executor action (%s) does not match any known operations",
 827                 action->id);
 828         return;
 829     }
 830 
 831 #ifdef PCMK__TIME_USE_CGT
 832     if (cmd->result.exit_status != action->rc) {
 833         cmd->epoch_rcchange = time(NULL);
 834     }
 835 #endif
 836 
 837     cmd->last_pid = action->pid;
 838 
 839     
 840     code = services_result2ocf(action->standard, cmd->action, action->rc);
 841     pcmk__set_result(&(cmd->result), (int) code,
 842                      action->status, services__exit_reason(action));
 843 
 844     rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
 845 
 846 #ifdef PCMK__TIME_USE_CGT
 847     if (rsc && pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_SERVICE, pcmk__str_casei)) {
 848         rclass = resources_find_service_class(rsc->type);
 849     } else if(rsc) {
 850         rclass = rsc->class;
 851     }
 852 
 853     if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_SYSTEMD, pcmk__str_casei)) {
 854         if (pcmk__result_ok(&(cmd->result))
 855             && pcmk__strcase_any_of(cmd->action, PCMK_ACTION_START,
 856                                     PCMK_ACTION_STOP, NULL)) {
 857             
 858 
 859 
 860 
 861 
 862             goagain = true;
 863             cmd->real_action = cmd->action;
 864             cmd->action = pcmk__str_copy(PCMK_ACTION_MONITOR);
 865 
 866         } else if (cmd->real_action != NULL) {
 867             
 868             if (cmd->result.execution_status == PCMK_EXEC_PENDING) {
 869                 goagain = true;
 870 
 871             } else if (pcmk__result_ok(&(cmd->result))
 872                        && pcmk__str_eq(cmd->real_action, PCMK_ACTION_STOP,
 873                                        pcmk__str_casei)) {
 874                 goagain = true;
 875 
 876             } else {
 877                 int time_sum = time_diff_ms(NULL, &(cmd->t_first_run));
 878                 int timeout_left = cmd->timeout_orig - time_sum;
 879 
 880                 crm_debug("%s systemd %s is now complete (elapsed=%dms, "
 881                           "remaining=%dms): %s (%d)",
 882                           cmd->rsc_id, cmd->real_action, time_sum, timeout_left,
 883                           services_ocf_exitcode_str(cmd->result.exit_status),
 884                           cmd->result.exit_status);
 885                 cmd_original_times(cmd);
 886 
 887                 
 888                 if ((cmd->result.execution_status == PCMK_EXEC_DONE)
 889                     && (cmd->result.exit_status == PCMK_OCF_NOT_RUNNING)) {
 890 
 891                     if (pcmk__str_eq(cmd->real_action, PCMK_ACTION_START,
 892                                      pcmk__str_casei)) {
 893                         cmd->result.exit_status = PCMK_OCF_UNKNOWN_ERROR;
 894                     } else if (pcmk__str_eq(cmd->real_action, PCMK_ACTION_STOP,
 895                                             pcmk__str_casei)) {
 896                         cmd->result.exit_status = PCMK_OCF_OK;
 897                     }
 898                 }
 899             }
 900         }
 901     }
 902 #endif
 903 
 904 #if SUPPORT_NAGIOS
 905     if (rsc && pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
 906         if (action_matches(cmd, PCMK_ACTION_MONITOR, 0)
 907             && pcmk__result_ok(&(cmd->result))) {
 908             
 909             cmd->result.exit_status = PCMK_OCF_NOT_RUNNING;
 910 
 911         } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)
 912                    && !pcmk__result_ok(&(cmd->result))) {
 913 #ifdef PCMK__TIME_USE_CGT
 914             goagain = true;
 915 #endif
 916         }
 917     }
 918 #endif
 919 
 920 #ifdef PCMK__TIME_USE_CGT
 921     if (goagain) {
 922         int time_sum = time_diff_ms(NULL, &(cmd->t_first_run));
 923         int timeout_left = cmd->timeout_orig - time_sum;
 924         int delay = cmd->timeout_orig / 10;
 925 
 926         if(delay >= timeout_left && timeout_left > 20) {
 927             delay = timeout_left/2;
 928         }
 929 
 930         delay = QB_MIN(2000, delay);
 931         if (delay < timeout_left) {
 932             cmd->start_delay = delay;
 933             cmd->timeout = timeout_left;
 934 
 935             if (pcmk__result_ok(&(cmd->result))) {
 936                 crm_debug("%s %s may still be in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
 937                           cmd->rsc_id, cmd->real_action, time_sum, timeout_left, delay);
 938 
 939             } else if (cmd->result.execution_status == PCMK_EXEC_PENDING) {
 940                 crm_info("%s %s is still in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
 941                          cmd->rsc_id, cmd->action, time_sum, timeout_left, delay);
 942 
 943             } else {
 944                 crm_notice("%s %s failed '%s' (%d): re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
 945                            cmd->rsc_id, cmd->action,
 946                            services_ocf_exitcode_str(cmd->result.exit_status),
 947                            cmd->result.exit_status, time_sum, timeout_left,
 948                            delay);
 949             }
 950 
 951             cmd_reset(cmd);
 952             if(rsc) {
 953                 rsc->active = NULL;
 954             }
 955             schedule_lrmd_cmd(rsc, cmd);
 956 
 957             
 958             return;
 959 
 960         } else {
 961             crm_notice("Giving up on %s %s (rc=%d): timeout (elapsed=%dms, remaining=%dms)",
 962                        cmd->rsc_id,
 963                        (cmd->real_action? cmd->real_action : cmd->action),
 964                        cmd->result.exit_status, time_sum, timeout_left);
 965             pcmk__set_result(&(cmd->result), PCMK_OCF_UNKNOWN_ERROR,
 966                              PCMK_EXEC_TIMEOUT,
 967                              "Investigate reason for timeout, and adjust "
 968                              "configured operation timeout if necessary");
 969             cmd_original_times(cmd);
 970         }
 971     }
 972 #endif
 973 
 974     pcmk__set_result_output(&(cmd->result), services__grab_stdout(action),
 975                             services__grab_stderr(action));
 976     cmd_finalize(cmd, rsc);
 977 }
 978 
 979 
 980 
 981 
 982 
 983 
 984 
 985 
 986 
 987 
 988 static void
 989 stonith_action_complete(lrmd_cmd_t *cmd, int exit_status,
     
 990                         enum pcmk_exec_status execution_status,
 991                         const char *exit_reason)
 992 {
 993     
 994     lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
 995 
 996     
 997     if (exit_status != CRM_EX_OK) {
 998         exit_status = PCMK_OCF_UNKNOWN_ERROR;
 999     }
1000 
1001     if (cmd->result.execution_status == PCMK_EXEC_CANCELLED) {
1002         
1003 
1004 
1005         execution_status = PCMK_EXEC_CANCELLED;
1006 
1007     } else {
1008         
1009 
1010 
1011 
1012         switch (execution_status) {
1013             case PCMK_EXEC_NOT_CONNECTED:
1014             case PCMK_EXEC_INVALID:
1015                 execution_status = PCMK_EXEC_ERROR;
1016                 break;
1017 
1018             case PCMK_EXEC_NO_FENCE_DEVICE:
1019                 
1020 
1021 
1022                 if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR,
1023                                  pcmk__str_none)) {
1024                     exit_status = PCMK_OCF_NOT_RUNNING;
1025 
1026                 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP,
1027                                         pcmk__str_none)) {
1028                     exit_status = PCMK_OCF_OK;
1029 
1030                 } else {
1031                     exit_status = PCMK_OCF_NOT_INSTALLED;
1032                 }
1033                 execution_status = PCMK_EXEC_ERROR;
1034                 break;
1035 
1036             case PCMK_EXEC_NOT_SUPPORTED:
1037                 exit_status = PCMK_OCF_UNIMPLEMENT_FEATURE;
1038                 break;
1039 
1040             default:
1041                 break;
1042         }
1043     }
1044 
1045     pcmk__set_result(&cmd->result, exit_status, execution_status, exit_reason);
1046 
1047     
1048     if ((rsc != NULL) && pcmk__result_ok(&(cmd->result))) {
1049 
1050         if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) {
1051             pcmk__set_result(&rsc->fence_probe_result, CRM_EX_OK,
1052                              PCMK_EXEC_DONE, NULL); 
1053 
1054         } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP,
1055                                 pcmk__str_casei)) {
1056             pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
1057                              PCMK_EXEC_NO_FENCE_DEVICE, NULL); 
1058         }
1059     }
1060 
1061     
1062 
1063 
1064     stop_recurring_timer(cmd);
1065 
1066     
1067 
1068 
1069 
1070     if (rsc && (cmd->interval_ms > 0)
1071         && (cmd->result.execution_status != PCMK_EXEC_CANCELLED)) {
1072         start_recurring_timer(cmd);
1073     }
1074 
1075     cmd_finalize(cmd, rsc);
1076 }
1077 
1078 static void
1079 lrmd_stonith_callback(stonith_t * stonith, stonith_callback_data_t * data)
     
1080 {
1081     if ((data == NULL) || (data->userdata == NULL)) {
1082         crm_err("Ignoring fence action result: "
1083                 "Invalid callback arguments (bug?)");
1084     } else {
1085         stonith_action_complete((lrmd_cmd_t *) data->userdata,
1086                                 stonith__exit_status(data),
1087                                 stonith__execution_status(data),
1088                                 stonith__exit_reason(data));
1089     }
1090 }
1091 
1092 void
1093 stonith_connection_failed(void)
     
1094 {
1095     GHashTableIter iter;
1096     lrmd_rsc_t *rsc = NULL;
1097 
1098     crm_warn("Connection to fencer lost (any pending operations for "
1099              "fence devices will be considered failed)");
1100 
1101     g_hash_table_iter_init(&iter, rsc_list);
1102     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &rsc)) {
1103         if (!pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
1104                           pcmk__str_none)) {
1105             continue;
1106         }
1107 
1108         
1109 
1110 
1111 
1112 
1113 
1114 
1115         if (rsc->fence_probe_result.execution_status == PCMK_EXEC_DONE) {
1116             pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
1117                              PCMK_EXEC_NOT_CONNECTED,
1118                              "Lost connection to fencer");
1119         }
1120 
1121         
1122 
1123         for (GList *op = rsc->recurring_ops; op != NULL; op = op->next) {
1124             lrmd_cmd_t *cmd = op->data;
1125 
1126             
1127 
1128 
1129 
1130             stonith_action_complete(cmd,
1131                                     CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED,
1132                                     "Lost connection to fencer");
1133         }
1134 
1135         if (rsc->active != NULL) {
1136             rsc->pending_ops = g_list_prepend(rsc->pending_ops, rsc->active);
1137         }
1138         while (rsc->pending_ops != NULL) {
1139             
1140             stonith_action_complete((lrmd_cmd_t *) rsc->pending_ops->data,
1141                                     CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED,
1142                                     "Lost connection to fencer");
1143         }
1144     }
1145 }
1146 
1147 
1148 
1149 
1150 
1151 
1152 
1153 
1154 
1155 
1156 
1157 
1158 
1159 
1160 static int
1161 execd_stonith_start(stonith_t *stonith_api, const lrmd_rsc_t *rsc,
     
1162                     const lrmd_cmd_t *cmd)
1163 {
1164     char *key = NULL;
1165     char *value = NULL;
1166     stonith_key_value_t *device_params = NULL;
1167     int rc = pcmk_ok;
1168 
1169     
1170     if (cmd->params) {
1171         GHashTableIter iter;
1172 
1173         g_hash_table_iter_init(&iter, cmd->params);
1174         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1175             device_params = stonith_key_value_add(device_params, key, value);
1176         }
1177     }
1178 
1179     
1180 
1181 
1182 
1183 
1184 
1185     rc = stonith_api->cmds->register_device(stonith_api, st_opt_sync_call,
1186                                             cmd->rsc_id, rsc->provider,
1187                                             rsc->type, device_params);
1188 
1189     stonith_key_value_freeall(device_params, 1, 1);
1190     return rc;
1191 }
1192 
1193 
1194 
1195 
1196 
1197 
1198 
1199 
1200 
1201 
1202 
1203 
1204 
1205 static inline int
1206 execd_stonith_stop(stonith_t *stonith_api, const lrmd_rsc_t *rsc)
     
1207 {
1208     
1209 
1210 
1211     return stonith_api->cmds->remove_device(stonith_api, st_opt_sync_call,
1212                                             rsc->rsc_id);
1213 }
1214 
1215 
1216 
1217 
1218 
1219 
1220 
1221 
1222 
1223 
1224 
1225 static inline int
1226 execd_stonith_monitor(stonith_t *stonith_api, lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
     
1227 {
1228     int rc = stonith_api->cmds->monitor(stonith_api, 0, cmd->rsc_id,
1229                                         cmd->timeout / 1000);
1230 
1231     rc = stonith_api->cmds->register_callback(stonith_api, rc, 0, 0, cmd,
1232                                               "lrmd_stonith_callback",
1233                                               lrmd_stonith_callback);
1234     if (rc == TRUE) {
1235         rsc->active = cmd;
1236         rc = pcmk_ok;
1237     } else {
1238         rc = -pcmk_err_generic;
1239     }
1240     return rc;
1241 }
1242 
1243 static void
1244 execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
     
1245 {
1246     int rc = 0;
1247     bool do_monitor = FALSE;
1248 
1249     stonith_t *stonith_api = get_stonith_connection();
1250 
1251     if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)
1252         && (cmd->interval_ms == 0)) {
1253         
1254         stonith_action_complete(cmd, rsc->fence_probe_result.exit_status,
1255                                 rsc->fence_probe_result.execution_status,
1256                                 rsc->fence_probe_result.exit_reason);
1257         return;
1258 
1259     } else if (stonith_api == NULL) {
1260         stonith_action_complete(cmd, PCMK_OCF_UNKNOWN_ERROR,
1261                                 PCMK_EXEC_NOT_CONNECTED,
1262                                 "No connection to fencer");
1263         return;
1264 
1265     } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) {
1266         rc = execd_stonith_start(stonith_api, rsc, cmd);
1267         if (rc == pcmk_ok) {
1268             do_monitor = TRUE;
1269         }
1270 
1271     } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
1272         rc = execd_stonith_stop(stonith_api, rsc);
1273 
1274     } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR,
1275                             pcmk__str_casei)) {
1276         do_monitor = TRUE;
1277 
1278     } else {
1279         stonith_action_complete(cmd, PCMK_OCF_UNIMPLEMENT_FEATURE,
1280                                 PCMK_EXEC_ERROR,
1281                                 "Invalid fence device action (bug?)");
1282         return;
1283     }
1284 
1285     if (do_monitor) {
1286         rc = execd_stonith_monitor(stonith_api, rsc, cmd);
1287         if (rc == pcmk_ok) {
1288             
1289             return;
1290         }
1291     }
1292 
1293     stonith_action_complete(cmd,
1294                             ((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR),
1295                             stonith__legacy2status(rc),
1296                             ((rc == -pcmk_err_generic)? NULL : pcmk_strerror(rc)));
1297 }
1298 
1299 static void
1300 execute_nonstonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
     
1301 {
1302     svc_action_t *action = NULL;
1303     GHashTable *params_copy = NULL;
1304 
1305     CRM_ASSERT(rsc);
1306     CRM_ASSERT(cmd);
1307 
1308     crm_trace("Creating action, resource:%s action:%s class:%s provider:%s agent:%s",
1309               rsc->rsc_id, cmd->action, rsc->class, rsc->provider, rsc->type);
1310 
1311 #if SUPPORT_NAGIOS
1312     
1313     if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)
1314         && pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
1315 
1316         cmd->result.exit_status = PCMK_OCF_OK;
1317         cmd_finalize(cmd, rsc);
1318         return;
1319     }
1320 #endif
1321 
1322     params_copy = pcmk__str_table_dup(cmd->params);
1323 
1324     action = services__create_resource_action(rsc->rsc_id, rsc->class, rsc->provider,
1325                                      rsc->type,
1326                                      normalize_action_name(rsc, cmd->action),
1327                                      cmd->interval_ms, cmd->timeout,
1328                                      params_copy, cmd->service_flags);
1329 
1330     if (action == NULL) {
1331         pcmk__set_result(&(cmd->result), PCMK_OCF_UNKNOWN_ERROR,
1332                          PCMK_EXEC_ERROR, strerror(ENOMEM));
1333         cmd_finalize(cmd, rsc);
1334         return;
1335     }
1336 
1337     if (action->rc != PCMK_OCF_UNKNOWN) {
1338         pcmk__set_result(&(cmd->result), action->rc, action->status,
1339                          services__exit_reason(action));
1340         services_action_free(action);
1341         cmd_finalize(cmd, rsc);
1342         return;
1343     }
1344 
1345     action->cb_data = cmd;
1346 
1347     if (services_action_async(action, action_complete)) {
1348         
1349 
1350 
1351 
1352 
1353 
1354 
1355 
1356 
1357     } else {
1358         
1359 
1360 
1361 
1362 
1363 
1364 
1365         pcmk__set_result(&(cmd->result), action->rc, action->status,
1366                          services__exit_reason(action));
1367         services_action_free(action);
1368     }
1369 }
1370 
1371 static gboolean
1372 execute_resource_action(gpointer user_data)
     
1373 {
1374     lrmd_rsc_t *rsc = (lrmd_rsc_t *) user_data;
1375     lrmd_cmd_t *cmd = NULL;
1376 
1377     CRM_CHECK(rsc != NULL, return FALSE);
1378 
1379     if (rsc->active) {
1380         crm_trace("%s is still active", rsc->rsc_id);
1381         return TRUE;
1382     }
1383 
1384     if (rsc->pending_ops) {
1385         GList *first = rsc->pending_ops;
1386 
1387         cmd = first->data;
1388         if (cmd->delay_id) {
1389             crm_trace
1390                 ("Command %s %s was asked to run too early, waiting for start_delay timeout of %dms",
1391                  cmd->rsc_id, cmd->action, cmd->start_delay);
1392             return TRUE;
1393         }
1394         rsc->pending_ops = g_list_remove_link(rsc->pending_ops, first);
1395         g_list_free_1(first);
1396 
1397 #ifdef PCMK__TIME_USE_CGT
1398         get_current_time(&(cmd->t_run), &(cmd->t_first_run));
1399 #endif
1400         cmd->epoch_last_run = time(NULL);
1401     }
1402 
1403     if (!cmd) {
1404         crm_trace("Nothing further to do for %s", rsc->rsc_id);
1405         return TRUE;
1406     }
1407 
1408     rsc->active = cmd;          
1409     if (cmd->interval_ms) {
1410         rsc->recurring_ops = g_list_append(rsc->recurring_ops, cmd);
1411     }
1412 
1413     log_execute(cmd);
1414 
1415     if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1416         execute_stonith_action(rsc, cmd);
1417     } else {
1418         execute_nonstonith_action(rsc, cmd);
1419     }
1420 
1421     return TRUE;
1422 }
1423 
1424 void
1425 free_rsc(gpointer data)
     
1426 {
1427     GList *gIter = NULL;
1428     lrmd_rsc_t *rsc = data;
1429     int is_stonith = pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
1430                                   pcmk__str_casei);
1431 
1432     gIter = rsc->pending_ops;
1433     while (gIter != NULL) {
1434         GList *next = gIter->next;
1435         lrmd_cmd_t *cmd = gIter->data;
1436 
1437         
1438         cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1439         cmd_finalize(cmd, NULL);
1440 
1441         gIter = next;
1442     }
1443     
1444     g_list_free(rsc->pending_ops);
1445 
1446     gIter = rsc->recurring_ops;
1447     while (gIter != NULL) {
1448         GList *next = gIter->next;
1449         lrmd_cmd_t *cmd = gIter->data;
1450 
1451         if (is_stonith) {
1452             cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1453             
1454 
1455 
1456 
1457             if (rsc->active != cmd) {
1458                 cmd_finalize(cmd, NULL);
1459             }
1460         } else {
1461             
1462 
1463 
1464 
1465             services_action_cancel(rsc->rsc_id,
1466                                    normalize_action_name(rsc, cmd->action),
1467                                    cmd->interval_ms);
1468         }
1469 
1470         gIter = next;
1471     }
1472     
1473     g_list_free(rsc->recurring_ops);
1474 
1475     free(rsc->rsc_id);
1476     free(rsc->class);
1477     free(rsc->provider);
1478     free(rsc->type);
1479     mainloop_destroy_trigger(rsc->work);
1480 
1481     free(rsc);
1482 }
1483 
1484 static int
1485 process_lrmd_signon(pcmk__client_t *client, xmlNode *request, int call_id,
     
1486                     xmlNode **reply)
1487 {
1488     int rc = pcmk_ok;
1489     time_t now = time(NULL);
1490     const char *protocol_version =
1491         crm_element_value(request, PCMK__XA_LRMD_PROTOCOL_VERSION);
1492     const char *start_state = pcmk__env_option(PCMK__ENV_NODE_START_STATE);
1493 
1494     if (compare_version(protocol_version, LRMD_COMPATIBLE_PROTOCOL) < 0) {
1495         crm_err("Cluster API version must be greater than or equal to %s, not %s",
1496                 LRMD_COMPATIBLE_PROTOCOL, protocol_version);
1497         rc = -EPROTO;
1498     }
1499 
1500     if (pcmk__xe_attr_is_true(request, PCMK__XA_LRMD_IS_IPC_PROVIDER)) {
1501 #ifdef PCMK__COMPILE_REMOTE
1502         if ((client->remote != NULL)
1503             && pcmk_is_set(client->flags,
1504                            pcmk__client_tls_handshake_complete)) {
1505             const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
1506 
1507             
1508             ipc_proxy_add_provider(client);
1509 
1510             
1511 
1512 
1513             if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none) &&
1514                 LRMD_SUPPORTS_SCHEMA_XFER(protocol_version)) {
1515                 remoted_request_cib_schema_files();
1516             }
1517         } else {
1518             rc = -EACCES;
1519         }
1520 #else
1521         rc = -EPROTONOSUPPORT;
1522 #endif
1523     }
1524 
1525     *reply = create_lrmd_reply(__func__, rc, call_id);
1526     crm_xml_add(*reply, PCMK__XA_LRMD_OP, CRM_OP_REGISTER);
1527     crm_xml_add(*reply, PCMK__XA_LRMD_CLIENTID, client->id);
1528     crm_xml_add(*reply, PCMK__XA_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
1529     crm_xml_add_ll(*reply, PCMK__XA_UPTIME, now - start_time);
1530 
1531     if (start_state) {
1532         crm_xml_add(*reply, PCMK__XA_NODE_START_STATE, start_state);
1533     }
1534 
1535     return rc;
1536 }
1537 
1538 static int
1539 process_lrmd_rsc_register(pcmk__client_t *client, uint32_t id, xmlNode *request)
     
1540 {
1541     int rc = pcmk_ok;
1542     lrmd_rsc_t *rsc = build_rsc_from_xml(request);
1543     lrmd_rsc_t *dup = g_hash_table_lookup(rsc_list, rsc->rsc_id);
1544 
1545     if (dup &&
1546         pcmk__str_eq(rsc->class, dup->class, pcmk__str_casei) &&
1547         pcmk__str_eq(rsc->provider, dup->provider, pcmk__str_casei) && pcmk__str_eq(rsc->type, dup->type, pcmk__str_casei)) {
1548 
1549         crm_notice("Ignoring duplicate registration of '%s'", rsc->rsc_id);
1550         free_rsc(rsc);
1551         return rc;
1552     }
1553 
1554     g_hash_table_replace(rsc_list, rsc->rsc_id, rsc);
1555     crm_info("Cached agent information for '%s'", rsc->rsc_id);
1556     return rc;
1557 }
1558 
1559 static xmlNode *
1560 process_lrmd_get_rsc_info(xmlNode *request, int call_id)
     
1561 {
1562     int rc = pcmk_ok;
1563     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1564                                         LOG_ERR);
1565     const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1566     xmlNode *reply = NULL;
1567     lrmd_rsc_t *rsc = NULL;
1568 
1569     if (rsc_id == NULL) {
1570         rc = -ENODEV;
1571     } else {
1572         rsc = g_hash_table_lookup(rsc_list, rsc_id);
1573         if (rsc == NULL) {
1574             crm_info("Agent information for '%s' not in cache", rsc_id);
1575             rc = -ENODEV;
1576         }
1577     }
1578 
1579     reply = create_lrmd_reply(__func__, rc, call_id);
1580     if (rsc) {
1581         crm_xml_add(reply, PCMK__XA_LRMD_RSC_ID, rsc->rsc_id);
1582         crm_xml_add(reply, PCMK__XA_LRMD_CLASS, rsc->class);
1583         crm_xml_add(reply, PCMK__XA_LRMD_PROVIDER, rsc->provider);
1584         crm_xml_add(reply, PCMK__XA_LRMD_TYPE, rsc->type);
1585     }
1586     return reply;
1587 }
1588 
1589 static int
1590 process_lrmd_rsc_unregister(pcmk__client_t *client, uint32_t id,
     
1591                             xmlNode *request)
1592 {
1593     int rc = pcmk_ok;
1594     lrmd_rsc_t *rsc = NULL;
1595     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1596                                         LOG_ERR);
1597     const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1598 
1599     if (!rsc_id) {
1600         return -ENODEV;
1601     }
1602 
1603     rsc = g_hash_table_lookup(rsc_list, rsc_id);
1604     if (rsc == NULL) {
1605         crm_info("Ignoring unregistration of resource '%s', which is not registered",
1606                  rsc_id);
1607         return pcmk_ok;
1608     }
1609 
1610     if (rsc->active) {
1611         
1612         crm_trace("Operation (%p) still in progress for unregistered resource %s",
1613                   rsc->active, rsc_id);
1614         rc = -EINPROGRESS;
1615     }
1616 
1617     g_hash_table_remove(rsc_list, rsc_id);
1618 
1619     return rc;
1620 }
1621 
1622 static int
1623 process_lrmd_rsc_exec(pcmk__client_t *client, uint32_t id, xmlNode *request)
     
1624 {
1625     lrmd_rsc_t *rsc = NULL;
1626     lrmd_cmd_t *cmd = NULL;
1627     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1628                                         LOG_ERR);
1629     const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1630     int call_id;
1631 
1632     if (!rsc_id) {
1633         return -EINVAL;
1634     }
1635     if (!(rsc = g_hash_table_lookup(rsc_list, rsc_id))) {
1636         crm_info("Resource '%s' not found (%d active resources)",
1637                  rsc_id, g_hash_table_size(rsc_list));
1638         return -ENODEV;
1639     }
1640 
1641     cmd = create_lrmd_cmd(request, client);
1642     call_id = cmd->call_id;
1643 
1644     
1645 
1646     schedule_lrmd_cmd(rsc, cmd);
1647 
1648     return call_id;
1649 }
1650 
1651 static int
1652 cancel_op(const char *rsc_id, const char *action, guint interval_ms)
     
1653 {
1654     GList *gIter = NULL;
1655     lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, rsc_id);
1656 
1657     
1658 
1659 
1660 
1661 
1662 
1663 
1664 
1665 
1666 
1667 
1668     if (!rsc) {
1669         return -ENODEV;
1670     }
1671 
1672     for (gIter = rsc->pending_ops; gIter != NULL; gIter = gIter->next) {
1673         lrmd_cmd_t *cmd = gIter->data;
1674 
1675         if (action_matches(cmd, action, interval_ms)) {
1676             cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1677             cmd_finalize(cmd, rsc);
1678             return pcmk_ok;
1679         }
1680     }
1681 
1682     if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1683         
1684 
1685         for (gIter = rsc->recurring_ops; gIter != NULL; gIter = gIter->next) {
1686             lrmd_cmd_t *cmd = gIter->data;
1687 
1688             if (action_matches(cmd, action, interval_ms)) {
1689                 cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1690                 if (rsc->active != cmd) {
1691                     cmd_finalize(cmd, rsc);
1692                 }
1693                 return pcmk_ok;
1694             }
1695         }
1696     } else if (services_action_cancel(rsc_id,
1697                                       normalize_action_name(rsc, action),
1698                                       interval_ms) == TRUE) {
1699         
1700 
1701 
1702 
1703         return pcmk_ok;
1704     }
1705 
1706     return -EOPNOTSUPP;
1707 }
1708 
1709 static void
1710 cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id)
     
1711 {
1712     GList *cmd_list = NULL;
1713     GList *cmd_iter = NULL;
1714 
1715     
1716 
1717 
1718 
1719 
1720 
1721     if (rsc->recurring_ops) {
1722         cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->recurring_ops));
1723     }
1724     if (rsc->pending_ops) {
1725         cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->pending_ops));
1726     }
1727     if (!cmd_list) {
1728         return;
1729     }
1730 
1731     for (cmd_iter = cmd_list; cmd_iter; cmd_iter = cmd_iter->next) {
1732         lrmd_cmd_t *cmd = cmd_iter->data;
1733 
1734         if (cmd->interval_ms == 0) {
1735             continue;
1736         }
1737 
1738         if (client_id && !pcmk__str_eq(cmd->client_id, client_id, pcmk__str_casei)) {
1739             continue;
1740         }
1741 
1742         cancel_op(rsc->rsc_id, cmd->action, cmd->interval_ms);
1743     }
1744     
1745     g_list_free(cmd_list);
1746 }
1747 
1748 static int
1749 process_lrmd_rsc_cancel(pcmk__client_t *client, uint32_t id, xmlNode *request)
     
1750 {
1751     xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1752                                         LOG_ERR);
1753     const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1754     const char *action = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ACTION);
1755     guint interval_ms = 0;
1756 
1757     crm_element_value_ms(rsc_xml, PCMK__XA_LRMD_RSC_INTERVAL, &interval_ms);
1758 
1759     if (!rsc_id || !action) {
1760         return -EINVAL;
1761     }
1762 
1763     return cancel_op(rsc_id, action, interval_ms);
1764 }
1765 
1766 static void
1767 add_recurring_op_xml(xmlNode *reply, lrmd_rsc_t *rsc)
     
1768 {
1769     xmlNode *rsc_xml = pcmk__xe_create(reply, PCMK__XE_LRMD_RSC);
1770 
1771     crm_xml_add(rsc_xml, PCMK__XA_LRMD_RSC_ID, rsc->rsc_id);
1772     for (GList *item = rsc->recurring_ops; item != NULL; item = item->next) {
1773         lrmd_cmd_t *cmd = item->data;
1774         xmlNode *op_xml = pcmk__xe_create(rsc_xml, PCMK__XE_LRMD_RSC_OP);
1775 
1776         crm_xml_add(op_xml, PCMK__XA_LRMD_RSC_ACTION,
1777                     pcmk__s(cmd->real_action, cmd->action));
1778         crm_xml_add_ms(op_xml, PCMK__XA_LRMD_RSC_INTERVAL, cmd->interval_ms);
1779         crm_xml_add_int(op_xml, PCMK__XA_LRMD_TIMEOUT, cmd->timeout_orig);
1780     }
1781 }
1782 
1783 static xmlNode *
1784 process_lrmd_get_recurring(xmlNode *request, int call_id)
     
1785 {
1786     int rc = pcmk_ok;
1787     const char *rsc_id = NULL;
1788     lrmd_rsc_t *rsc = NULL;
1789     xmlNode *reply = NULL;
1790     xmlNode *rsc_xml = NULL;
1791 
1792     
1793     rsc_xml = pcmk__xe_first_child(request, PCMK__XE_LRMD_CALLDATA, NULL, NULL);
1794     if (rsc_xml) {
1795         rsc_xml = pcmk__xe_first_child(rsc_xml, PCMK__XE_LRMD_RSC, NULL, NULL);
1796     }
1797     if (rsc_xml) {
1798         rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1799     }
1800 
1801     
1802     if (rsc_id != NULL) {
1803         rsc = g_hash_table_lookup(rsc_list, rsc_id);
1804         if (rsc == NULL) {
1805             crm_info("Resource '%s' not found (%d active resources)",
1806                      rsc_id, g_hash_table_size(rsc_list));
1807             rc = -ENODEV;
1808         }
1809     }
1810 
1811     reply = create_lrmd_reply(__func__, rc, call_id);
1812 
1813     
1814     if (rsc_id == NULL) {
1815         GHashTableIter iter;
1816         char *key = NULL;
1817 
1818         g_hash_table_iter_init(&iter, rsc_list);
1819         while (g_hash_table_iter_next(&iter, (gpointer *) &key,
1820                                       (gpointer *) &rsc)) {
1821             add_recurring_op_xml(reply, rsc);
1822         }
1823     } else if (rsc) {
1824         add_recurring_op_xml(reply, rsc);
1825     }
1826     return reply;
1827 }
1828 
1829 void
1830 process_lrmd_message(pcmk__client_t *client, uint32_t id, xmlNode *request)
     
1831 {
1832     int rc = pcmk_ok;
1833     int call_id = 0;
1834     const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
1835     int do_reply = 0;
1836     int do_notify = 0;
1837     xmlNode *reply = NULL;
1838 
1839     
1840 
1841 
1842 
1843     bool allowed = pcmk_is_set(client->flags, pcmk__client_privileged);
1844 
1845     crm_trace("Processing %s operation from %s", op, client->id);
1846     crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &call_id);
1847 
1848     if (pcmk__str_eq(op, CRM_OP_IPC_FWD, pcmk__str_none)) {
1849 #ifdef PCMK__COMPILE_REMOTE
1850         if (allowed) {
1851             ipc_proxy_forward_client(client, request);
1852         } else {
1853             rc = -EACCES;
1854         }
1855 #else
1856         rc = -EPROTONOSUPPORT;
1857 #endif
1858         do_reply = 1;
1859     } else if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) {
1860         rc = process_lrmd_signon(client, request, call_id, &reply);
1861         do_reply = 1;
1862     } else if (pcmk__str_eq(op, LRMD_OP_RSC_REG, pcmk__str_none)) {
1863         if (allowed) {
1864             rc = process_lrmd_rsc_register(client, id, request);
1865             do_notify = 1;
1866         } else {
1867             rc = -EACCES;
1868         }
1869         do_reply = 1;
1870     } else if (pcmk__str_eq(op, LRMD_OP_RSC_INFO, pcmk__str_none)) {
1871         if (allowed) {
1872             reply = process_lrmd_get_rsc_info(request, call_id);
1873         } else {
1874             rc = -EACCES;
1875         }
1876         do_reply = 1;
1877     } else if (pcmk__str_eq(op, LRMD_OP_RSC_UNREG, pcmk__str_none)) {
1878         if (allowed) {
1879             rc = process_lrmd_rsc_unregister(client, id, request);
1880             
1881             if (rc == pcmk_ok || rc == -EINPROGRESS) {
1882                 do_notify = 1;
1883             }
1884         } else {
1885             rc = -EACCES;
1886         }
1887         do_reply = 1;
1888     } else if (pcmk__str_eq(op, LRMD_OP_RSC_EXEC, pcmk__str_none)) {
1889         if (allowed) {
1890             rc = process_lrmd_rsc_exec(client, id, request);
1891         } else {
1892             rc = -EACCES;
1893         }
1894         do_reply = 1;
1895     } else if (pcmk__str_eq(op, LRMD_OP_RSC_CANCEL, pcmk__str_none)) {
1896         if (allowed) {
1897             rc = process_lrmd_rsc_cancel(client, id, request);
1898         } else {
1899             rc = -EACCES;
1900         }
1901         do_reply = 1;
1902     } else if (pcmk__str_eq(op, LRMD_OP_POKE, pcmk__str_none)) {
1903         do_notify = 1;
1904         do_reply = 1;
1905     } else if (pcmk__str_eq(op, LRMD_OP_CHECK, pcmk__str_none)) {
1906         if (allowed) {
1907             xmlNode *wrapper = pcmk__xe_first_child(request,
1908                                                     PCMK__XE_LRMD_CALLDATA,
1909                                                     NULL, NULL);
1910             xmlNode *data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
1911 
1912             const char *timeout = NULL;
1913 
1914             CRM_LOG_ASSERT(data != NULL);
1915             timeout = crm_element_value(data, PCMK__XA_LRMD_WATCHDOG);
1916             pcmk__valid_stonith_watchdog_timeout(timeout);
1917         } else {
1918             rc = -EACCES;
1919         }
1920     } else if (pcmk__str_eq(op, LRMD_OP_ALERT_EXEC, pcmk__str_none)) {
1921         if (allowed) {
1922             rc = process_lrmd_alert_exec(client, id, request);
1923         } else {
1924             rc = -EACCES;
1925         }
1926         do_reply = 1;
1927     } else if (pcmk__str_eq(op, LRMD_OP_GET_RECURRING, pcmk__str_none)) {
1928         if (allowed) {
1929             reply = process_lrmd_get_recurring(request, call_id);
1930         } else {
1931             rc = -EACCES;
1932         }
1933         do_reply = 1;
1934     } else {
1935         rc = -EOPNOTSUPP;
1936         do_reply = 1;
1937         crm_err("Unknown IPC request '%s' from client %s",
1938                 op, pcmk__client_name(client));
1939     }
1940 
1941     if (rc == -EACCES) {
1942         crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
1943                  op, pcmk__client_name(client));
1944     }
1945 
1946     crm_debug("Processed %s operation from %s: rc=%d, reply=%d, notify=%d",
1947               op, client->id, rc, do_reply, do_notify);
1948 
1949     if (do_reply) {
1950         int send_rc = pcmk_rc_ok;
1951 
1952         if (reply == NULL) {
1953             reply = create_lrmd_reply(__func__, rc, call_id);
1954         }
1955         send_rc = lrmd_server_send_reply(client, id, reply);
1956         free_xml(reply);
1957         if (send_rc != pcmk_rc_ok) {
1958             crm_warn("Reply to client %s failed: %s " CRM_XS " rc=%d",
1959                      pcmk__client_name(client), pcmk_rc_str(send_rc), send_rc);
1960         }
1961     }
1962 
1963     if (do_notify) {
1964         send_generic_notify(rc, request);
1965     }
1966 }