pacemaker  2.0.5-31aa4f5515
Scalable High-Availability cluster resource manager
st_client.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <libgen.h>
18 
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 
23 #include <glib.h>
24 
25 #include <crm/crm.h>
26 #include <crm/stonith-ng.h>
27 #include <crm/fencing/internal.h>
28 #include <crm/msg_xml.h>
29 #include <crm/common/xml.h>
31 
32 #include <crm/common/mainloop.h>
33 
35 
36 struct stonith_action_s {
38  char *agent;
39  char *action;
40  char *victim;
41  GHashTable *args;
42  int timeout;
43  int async;
44  void *userdata;
45  void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data);
46  void (*fork_cb) (GPid pid, gpointer user_data);
47 
48  svc_action_t *svc_action;
49 
51  time_t initial_start_time;
52  int tries;
53  int remaining_timeout;
54  int max_retries;
55 
56  /* device output data */
57  GPid pid;
58  int rc;
59  char *output;
60  char *error;
61 };
62 
63 typedef struct stonith_private_s {
64  char *token;
65  crm_ipc_t *ipc;
66  mainloop_io_t *source;
67  GHashTable *stonith_op_callback_table;
68  GList *notify_list;
69  int notify_refcnt;
70  bool notify_deletes;
71 
72  void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
73 
75 
76 typedef struct stonith_notify_client_s {
77  const char *event;
78  const char *obj_id; /* implement one day */
79  const char *obj_type; /* implement one day */
80  void (*notify) (stonith_t * st, stonith_event_t * e);
81  bool delete;
82 
84 
85 typedef struct stonith_callback_client_s {
86  void (*callback) (stonith_t * st, stonith_callback_data_t * data);
87  const char *id;
88  void *user_data;
89  gboolean only_success;
90  gboolean allow_timeout_updates;
91  struct timer_rec_s *timer;
92 
94 
95 struct notify_blob_s {
96  stonith_t *stonith;
97  xmlNode *xml;
98 };
99 
100 struct timer_rec_s {
101  int call_id;
102  int timeout;
103  guint ref;
105 };
106 
107 typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
108  xmlNode *, xmlNode *, xmlNode **, xmlNode **);
109 
111 xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
112  int call_options);
113 static int stonith_send_command(stonith_t *stonith, const char *op,
114  xmlNode *data, xmlNode **output_data,
115  int call_options, int timeout);
116 
117 static void stonith_connection_destroy(gpointer user_data);
118 static void stonith_send_notification(gpointer data, gpointer user_data);
119 static int internal_stonith_action_execute(stonith_action_t * action);
120 static void log_action(stonith_action_t *action, pid_t pid);
121 
130 stonith_text2namespace(const char *namespace_s)
131 {
132  if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
133  return st_namespace_any;
134 
135  } else if (!strcmp(namespace_s, "redhat")
136  || !strcmp(namespace_s, "stonith-ng")) {
137  return st_namespace_rhcs;
138 
139  } else if (!strcmp(namespace_s, "internal")) {
140  return st_namespace_internal;
141 
142  } else if (!strcmp(namespace_s, "heartbeat")) {
143  return st_namespace_lha;
144  }
145  return st_namespace_invalid;
146 }
147 
155 const char *
157 {
158  switch (st_namespace) {
159  case st_namespace_any: return "any";
160  case st_namespace_rhcs: return "stonith-ng";
161  case st_namespace_internal: return "internal";
162  case st_namespace_lha: return "heartbeat";
163  default: break;
164  }
165  return "unsupported";
166 }
167 
177 stonith_get_namespace(const char *agent, const char *namespace_s)
178 {
179  if (pcmk__str_eq(namespace_s, "internal", pcmk__str_casei)) {
180  return st_namespace_internal;
181  }
182 
183  if (stonith__agent_is_rhcs(agent)) {
184  return st_namespace_rhcs;
185  }
186 
187 #if HAVE_STONITH_STONITH_H
188  if (stonith__agent_is_lha(agent)) {
189  return st_namespace_lha;
190  }
191 #endif
192 
193  crm_err("Unknown fence agent: %s", agent);
194  return st_namespace_invalid;
195 }
196 
197 static void
199 {
200  if (action->output) {
201  /* Logging the whole string confuses syslog when the string is xml */
202  char *prefix = crm_strdup_printf("%s[%d] stdout:", action->agent, pid);
203 
204  crm_log_output(LOG_TRACE, prefix, action->output);
205  free(prefix);
206  }
207 
208  if (action->error) {
209  /* Logging the whole string confuses syslog when the string is xml */
210  char *prefix = crm_strdup_printf("%s[%d] stderr:", action->agent, pid);
211 
212  crm_log_output(LOG_WARNING, prefix, action->error);
213  free(prefix);
214  }
215 }
216 
217 /* when cycling through the list we don't want to delete items
218  so just mark them and when we know nobody is using the list
219  loop over it to remove the marked items
220  */
221 static void
222 foreach_notify_entry (stonith_private_t *private,
223  GFunc func,
224  gpointer user_data)
225 {
226  private->notify_refcnt++;
227  g_list_foreach(private->notify_list, func, user_data);
228  private->notify_refcnt--;
229  if ((private->notify_refcnt == 0) &&
230  private->notify_deletes) {
231  GList *list_item = private->notify_list;
232 
233  private->notify_deletes = FALSE;
234  while (list_item != NULL)
235  {
236  stonith_notify_client_t *list_client = list_item->data;
237  GList *next = g_list_next(list_item);
238 
239  if (list_client->delete) {
240  free(list_client);
241  private->notify_list =
242  g_list_delete_link(private->notify_list, list_item);
243  }
244  list_item = next;
245  }
246  }
247 }
248 
249 static void
250 stonith_connection_destroy(gpointer user_data)
251 {
252  stonith_t *stonith = user_data;
253  stonith_private_t *native = NULL;
254  struct notify_blob_s blob;
255 
256  crm_trace("Sending destroyed notification");
257  blob.stonith = stonith;
258  blob.xml = create_xml_node(NULL, "notify");
259 
260  native = stonith->st_private;
261  native->ipc = NULL;
262  native->source = NULL;
263 
264  free(native->token); native->token = NULL;
265  stonith->state = stonith_disconnected;
266  crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
268 
269  foreach_notify_entry(native, stonith_send_notification, &blob);
270  free_xml(blob.xml);
271 }
272 
273 xmlNode *
274 create_device_registration_xml(const char *id, enum stonith_namespace namespace,
275  const char *agent, stonith_key_value_t *params,
276  const char *rsc_provides)
277 {
278  xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
279  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
280 
281 #if HAVE_STONITH_STONITH_H
282  if (namespace == st_namespace_any) {
283  namespace = stonith_get_namespace(agent, NULL);
284  }
285  if (namespace == st_namespace_lha) {
286  hash2field((gpointer) "plugin", (gpointer) agent, args);
287  agent = "fence_legacy";
288  }
289 #endif
290 
292  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
293  crm_xml_add(data, "agent", agent);
294  if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
295  crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
296  }
297  if (rsc_provides) {
298  crm_xml_add(data, "rsc_provides", rsc_provides);
299  }
300 
301  for (; params; params = params->next) {
302  hash2field((gpointer) params->key, (gpointer) params->value, args);
303  }
304 
305  return data;
306 }
307 
308 static int
309 stonith_api_register_device(stonith_t * st, int call_options,
310  const char *id, const char *namespace, const char *agent,
311  stonith_key_value_t * params)
312 {
313  int rc = 0;
314  xmlNode *data = NULL;
315 
317  agent, params, NULL);
318 
319  rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
320  free_xml(data);
321 
322  return rc;
323 }
324 
325 static int
326 stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
327 {
328  int rc = 0;
329  xmlNode *data = NULL;
330 
332  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
334  rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
335  free_xml(data);
336 
337  return rc;
338 }
339 
340 static int
341 stonith_api_remove_level_full(stonith_t *st, int options,
342  const char *node, const char *pattern,
343  const char *attr, const char *value, int level)
344 {
345  int rc = 0;
346  xmlNode *data = NULL;
347 
348  CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
349 
351  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
352 
353  if (node) {
355 
356  } else if (pattern) {
358 
359  } else {
362  }
363 
365  rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
366  free_xml(data);
367 
368  return rc;
369 }
370 
371 static int
372 stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
373 {
374  return stonith_api_remove_level_full(st, options, node,
375  NULL, NULL, NULL, level);
376 }
377 
393 xmlNode *
394 create_level_registration_xml(const char *node, const char *pattern,
395  const char *attr, const char *value,
396  int level, stonith_key_value_t *device_list)
397 {
398  size_t len = 0;
399  char *list = NULL;
400  xmlNode *data;
401 
402  CRM_CHECK(node || pattern || (attr && value), return NULL);
403 
405  CRM_CHECK(data, return NULL);
406 
407  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
410 
411  if (node) {
413 
414  } else if (pattern) {
416 
417  } else {
420  }
421 
422  // cppcheck seems not to understand the abort logic behind pcmk__realloc
423  // cppcheck-suppress memleak
424  for (; device_list; device_list = device_list->next) {
425  pcmk__add_separated_word(&list, &len, device_list->value, ",");
426  }
427 
429 
430  free(list);
431  return data;
432 }
433 
434 static int
435 stonith_api_register_level_full(stonith_t * st, int options, const char *node,
436  const char *pattern,
437  const char *attr, const char *value,
438  int level, stonith_key_value_t *device_list)
439 {
440  int rc = 0;
441  xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
442  level, device_list);
443  CRM_CHECK(data != NULL, return -EINVAL);
444 
445  rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
446  free_xml(data);
447 
448  return rc;
449 }
450 
451 static int
452 stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
453  stonith_key_value_t * device_list)
454 {
455  return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
456  level, device_list);
457 }
458 
459 static void
460 append_arg(const char *key, const char *value, GHashTable **args)
461 {
462  CRM_CHECK(key != NULL, return);
463  CRM_CHECK(value != NULL, return);
464  CRM_CHECK(args != NULL, return);
465 
466  if (strstr(key, "pcmk_")) {
467  return;
468  } else if (strstr(key, CRM_META)) {
469  return;
470  } else if (pcmk__str_eq(key, "crm_feature_set", pcmk__str_casei)) {
471  return;
472  }
473 
474  if (!*args) {
475  *args = crm_str_table_new();
476  }
477 
478  CRM_CHECK(*args != NULL, return);
479  crm_trace("Appending: %s=%s", key, value);
480  g_hash_table_replace(*args, strdup(key), strdup(value));
481 }
482 
483 static void
484 append_config_arg(gpointer key, gpointer value, gpointer user_data)
485 {
486  /* The fencer will filter action out when it registers the device,
487  * but ignore it here just in case any other library callers
488  * fail to do so.
489  */
490  if (!pcmk__str_eq(key, STONITH_ATTR_ACTION_OP, pcmk__str_casei)) {
491  append_arg(key, value, user_data);
492  return;
493  }
494 }
495 
496 static GHashTable *
497 make_args(const char *agent, const char *action, const char *victim,
498  uint32_t victim_nodeid, GHashTable * device_args,
499  GHashTable * port_map, const char *host_arg)
500 {
501  char buffer[512];
502  GHashTable *arg_list = NULL;
503  const char *value = NULL;
504 
505  CRM_CHECK(action != NULL, return NULL);
506 
507  snprintf(buffer, sizeof(buffer), "pcmk_%s_action", action);
508  if (device_args) {
509  value = g_hash_table_lookup(device_args, buffer);
510  }
511  if (value) {
512  crm_debug("Substituting action '%s' for requested operation '%s'", value, action);
513  action = value;
514  }
515 
516  append_arg(STONITH_ATTR_ACTION_OP, action, &arg_list);
517  if (victim && device_args) {
518  const char *alias = victim;
519  const char *param = g_hash_table_lookup(device_args, STONITH_ATTR_HOSTARG);
520 
521  if (port_map && g_hash_table_lookup(port_map, victim)) {
522  alias = g_hash_table_lookup(port_map, victim);
523  }
524 
525  /* Always supply the node's name, too:
526  * https://github.com/ClusterLabs/fence-agents/blob/master/doc/FenceAgentAPI.md
527  */
528  append_arg("nodename", victim, &arg_list);
529  if (victim_nodeid) {
530  char nodeid_str[33] = { 0, };
531  if (snprintf(nodeid_str, 33, "%u", (unsigned int)victim_nodeid)) {
532  crm_info("For stonith action (%s) for victim %s, adding nodeid (%s) to parameters",
533  action, victim, nodeid_str);
534  append_arg("nodeid", nodeid_str, &arg_list);
535  }
536  }
537 
538  /* Check if we need to supply the victim in any other form */
539  if(pcmk__str_eq(agent, "fence_legacy", pcmk__str_casei)) {
540  value = agent;
541 
542  } else if (param == NULL) {
543  // By default, `port` is added
544  if (host_arg == NULL) {
545  param = "port";
546 
547  } else {
548  param = host_arg;
549  }
550 
551  value = g_hash_table_lookup(device_args, param);
552 
553  } else if (pcmk__str_eq(param, "none", pcmk__str_casei)) {
554  value = param; /* Nothing more to do */
555 
556  } else {
557  value = g_hash_table_lookup(device_args, param);
558  }
559 
560  /* Don't overwrite explictly set values for $param */
561  if (pcmk__str_eq(value, "dynamic", pcmk__str_null_matches | pcmk__str_casei)) {
562  crm_debug("Performing '%s' action targeting '%s' as '%s=%s'", action, victim, param,
563  alias);
564  append_arg(param, alias, &arg_list);
565  }
566  }
567 
568  if (device_args) {
569  g_hash_table_foreach(device_args, append_config_arg, &arg_list);
570  }
571 
572  return arg_list;
573 }
574 
581 void
583 {
584  if (action) {
585  free(action->agent);
586  if (action->args) {
587  g_hash_table_destroy(action->args);
588  }
589  free(action->action);
590  free(action->victim);
591  if (action->svc_action) {
592  services_action_free(action->svc_action);
593  }
594  free(action->output);
595  free(action->error);
596  free(action);
597  }
598 }
599 
612 void
614  char **error_output)
615 {
616  if (rc) {
617  *rc = pcmk_ok;
618  }
619  if (output) {
620  *output = NULL;
621  }
622  if (error_output) {
623  *error_output = NULL;
624  }
625  if (action != NULL) {
626  if (rc) {
627  *rc = action->rc;
628  }
629  if (output && action->output) {
630  *output = action->output;
631  action->output = NULL; // hand off memory management to caller
632  }
633  if (error_output && action->error) {
634  *error_output = action->error;
635  action->error = NULL; // hand off memory management to caller
636  }
637  }
638 }
639 
640 #define FAILURE_MAX_RETRIES 2
642 stonith_action_create(const char *agent,
643  const char *_action,
644  const char *victim,
645  uint32_t victim_nodeid,
646  int timeout, GHashTable * device_args,
647  GHashTable * port_map, const char *host_arg)
648 {
650 
651  action = calloc(1, sizeof(stonith_action_t));
652  action->args = make_args(agent, _action, victim, victim_nodeid,
653  device_args, port_map, host_arg);
654  crm_debug("Preparing '%s' action for %s using agent %s",
655  _action, (victim? victim : "no target"), agent);
656  action->agent = strdup(agent);
657  action->action = strdup(_action);
658  if (victim) {
659  action->victim = strdup(victim);
660  }
661  action->timeout = action->remaining_timeout = timeout;
662  action->max_retries = FAILURE_MAX_RETRIES;
663 
664  if (device_args) {
665  char buffer[512];
666  const char *value = NULL;
667 
668  snprintf(buffer, sizeof(buffer), "pcmk_%s_retries", _action);
669  value = g_hash_table_lookup(device_args, buffer);
670 
671  if (value) {
672  action->max_retries = atoi(value);
673  }
674  }
675 
676  return action;
677 }
678 
679 static gboolean
680 update_remaining_timeout(stonith_action_t * action)
681 {
682  int diff = time(NULL) - action->initial_start_time;
683 
684  if (action->tries >= action->max_retries) {
685  crm_info("Attempted to execute agent %s (%s) the maximum number of times (%d) allowed",
686  action->agent, action->action, action->max_retries);
687  action->remaining_timeout = 0;
688  } else if ((action->rc != -ETIME) && diff < (action->timeout * 0.7)) {
689  /* only set remaining timeout period if there is 30%
690  * or greater of the original timeout period left */
691  action->remaining_timeout = action->timeout - diff;
692  } else {
693  action->remaining_timeout = 0;
694  }
695  return action->remaining_timeout ? TRUE : FALSE;
696 }
697 
698 static int
699 svc_action_to_errno(svc_action_t *svc_action) {
700  int rv = pcmk_ok;
701 
702  if (svc_action->rc > 0) {
703  /* Try to provide a useful error code based on the fence agent's
704  * error output.
705  */
706  if (svc_action->rc == PCMK_OCF_TIMEOUT) {
707  rv = -ETIME;
708 
709  } else if (svc_action->stderr_data == NULL) {
710  rv = -ENODATA;
711 
712  } else if (strstr(svc_action->stderr_data, "imed out")) {
713  /* Some agents have their own internal timeouts */
714  rv = -ETIME;
715 
716  } else if (strstr(svc_action->stderr_data, "Unrecognised action")) {
717  rv = -EOPNOTSUPP;
718 
719  } else {
720  rv = -pcmk_err_generic;
721  }
722  }
723  return rv;
724 }
725 
726 static void
727 stonith_action_async_done(svc_action_t *svc_action)
728 {
729  stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
730 
731  action->rc = svc_action_to_errno(svc_action);
732  action->output = svc_action->stdout_data;
733  svc_action->stdout_data = NULL;
734  action->error = svc_action->stderr_data;
735  svc_action->stderr_data = NULL;
736 
737  svc_action->params = NULL;
738 
739  crm_debug("Child process %d performing action '%s' exited with rc %d",
740  action->pid, action->action, svc_action->rc);
741 
742  log_action(action, action->pid);
743 
744  if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
745  int rc = internal_stonith_action_execute(action);
746  if (rc == pcmk_ok) {
747  return;
748  }
749  }
750 
751  if (action->done_cb) {
752  action->done_cb(action->pid, action->rc, action->output, action->userdata);
753  }
754 
755  action->svc_action = NULL; // don't remove our caller
757 }
758 
759 static void
760 stonith_action_async_forked(svc_action_t *svc_action)
761 {
762  stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
763 
764  action->pid = svc_action->pid;
765  action->svc_action = svc_action;
766 
767  if (action->fork_cb) {
768  (action->fork_cb) (svc_action->pid, action->userdata);
769  }
770 
771  crm_trace("Child process %d performing action '%s' successfully forked",
772  action->pid, action->action);
773 }
774 
775 static int
776 internal_stonith_action_execute(stonith_action_t * action)
777 {
778  int rc = -EPROTO;
779  int is_retry = 0;
780  svc_action_t *svc_action = NULL;
781  static int stonith_sequence = 0;
782  char *buffer = NULL;
783 
784  if (!action->tries) {
785  action->initial_start_time = time(NULL);
786  }
787  action->tries++;
788 
789  if (action->tries > 1) {
790  crm_info("Attempt %d to execute %s (%s). remaining timeout is %d",
791  action->tries, action->agent, action->action, action->remaining_timeout);
792  is_retry = 1;
793  }
794 
795  if (action->args == NULL || action->agent == NULL)
796  goto fail;
797 
798  buffer = crm_strdup_printf(RH_STONITH_DIR "/%s", basename(action->agent));
799  svc_action = services_action_create_generic(buffer, NULL);
800  free(buffer);
801  svc_action->timeout = 1000 * action->remaining_timeout;
802  svc_action->standard = strdup(PCMK_RESOURCE_CLASS_STONITH);
803  svc_action->id = crm_strdup_printf("%s_%s_%d", basename(action->agent),
804  action->action, action->tries);
805  svc_action->agent = strdup(action->agent);
806  svc_action->sequence = stonith_sequence++;
807  svc_action->params = action->args;
808  svc_action->cb_data = (void *) action;
809  svc_action->flags = pcmk__set_flags_as(__func__, __LINE__,
810  LOG_TRACE, "Action",
811  svc_action->id, svc_action->flags,
813  "SVC_ACTION_NON_BLOCKED");
814 
815  /* keep retries from executing out of control and free previous results */
816  if (is_retry) {
817  free(action->output);
818  action->output = NULL;
819  free(action->error);
820  action->error = NULL;
821  sleep(1);
822  }
823 
824  if (action->async) {
825  /* async */
826  if(services_action_async_fork_notify(svc_action,
827  &stonith_action_async_done,
828  &stonith_action_async_forked) == FALSE) {
829  services_action_free(svc_action);
830  svc_action = NULL;
831  } else {
832  rc = 0;
833  }
834 
835  } else {
836  /* sync */
837  if (services_action_sync(svc_action)) {
838  rc = 0;
839  action->rc = svc_action_to_errno(svc_action);
840  action->output = svc_action->stdout_data;
841  svc_action->stdout_data = NULL;
842  action->error = svc_action->stderr_data;
843  svc_action->stderr_data = NULL;
844  } else {
845  action->rc = -ECONNABORTED;
846  rc = action->rc;
847  }
848 
849  svc_action->params = NULL;
850  services_action_free(svc_action);
851  }
852 
853  fail:
854  return rc;
855 }
856 
868 int
870  void *userdata,
871  void (*done) (GPid pid, int rc, const char *output,
872  gpointer user_data),
873  void (*fork_cb) (GPid pid, gpointer user_data))
874 {
875  if (!action) {
876  return -EINVAL;
877  }
878 
879  action->userdata = userdata;
880  action->done_cb = done;
881  action->fork_cb = fork_cb;
882  action->async = 1;
883 
884  return internal_stonith_action_execute(action);
885 }
886 
895 int
897 {
898  int rc = pcmk_ok;
899 
900  CRM_CHECK(action != NULL, return -EINVAL);
901 
902  // Keep trying until success, max retries, or timeout
903  do {
904  rc = internal_stonith_action_execute(action);
905  } while ((rc != pcmk_ok) && update_remaining_timeout(action));
906 
907  return rc;
908 }
909 
910 static int
911 stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
912  stonith_key_value_t ** devices, int timeout)
913 {
914  int count = 0;
915  enum stonith_namespace ns = stonith_text2namespace(namespace);
916 
917  if (devices == NULL) {
918  crm_err("Parameter error: stonith_api_device_list");
919  return -EFAULT;
920  }
921 
922 #if HAVE_STONITH_STONITH_H
923  // Include Linux-HA agents if requested
924  if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
925  count += stonith__list_lha_agents(devices);
926  }
927 #endif
928 
929  // Include Red Hat agents if requested
930  if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
931  count += stonith__list_rhcs_agents(devices);
932  }
933 
934  return count;
935 }
936 
937 static int
938 stonith_api_device_metadata(stonith_t * stonith, int call_options, const char *agent,
939  const char *namespace, char **output, int timeout)
940 {
941  /* By executing meta-data directly, we can get it from stonith_admin when
942  * the cluster is not running, which is important for higher-level tools.
943  */
944 
945  enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
946 
947  crm_trace("Looking up metadata for %s agent %s",
948  stonith_namespace2text(ns), agent);
949 
950  switch (ns) {
951  case st_namespace_rhcs:
952  return stonith__rhcs_metadata(agent, timeout, output);
953 
954 #if HAVE_STONITH_STONITH_H
955  case st_namespace_lha:
956  return stonith__lha_metadata(agent, timeout, output);
957 #endif
958 
959  default:
960  crm_err("Can't get fence agent '%s' meta-data: No such agent",
961  agent);
962  break;
963  }
964  return -ENODEV;
965 }
966 
967 static int
968 stonith_api_query(stonith_t * stonith, int call_options, const char *target,
969  stonith_key_value_t ** devices, int timeout)
970 {
971  int rc = 0, lpc = 0, max = 0;
972 
973  xmlNode *data = NULL;
974  xmlNode *output = NULL;
975  xmlXPathObjectPtr xpathObj = NULL;
976 
977  CRM_CHECK(devices != NULL, return -EINVAL);
978 
980  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
983  rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
984 
985  if (rc < 0) {
986  return rc;
987  }
988 
989  xpathObj = xpath_search(output, "//@agent");
990  if (xpathObj) {
991  max = numXpathResults(xpathObj);
992 
993  for (lpc = 0; lpc < max; lpc++) {
994  xmlNode *match = getXpathResult(xpathObj, lpc);
995 
996  CRM_LOG_ASSERT(match != NULL);
997  if(match != NULL) {
998  xmlChar *match_path = xmlGetNodePath(match);
999 
1000  crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
1001  free(match_path);
1002  *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
1003  }
1004  }
1005 
1006  freeXpathObject(xpathObj);
1007  }
1008 
1009  free_xml(output);
1010  free_xml(data);
1011  return max;
1012 }
1013 
1014 static int
1015 stonith_api_call(stonith_t * stonith,
1016  int call_options,
1017  const char *id,
1018  const char *action, const char *victim, int timeout, xmlNode ** output)
1019 {
1020  int rc = 0;
1021  xmlNode *data = NULL;
1022 
1024  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
1027  crm_xml_add(data, F_STONITH_TARGET, victim);
1028 
1029  rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output, call_options, timeout);
1030  free_xml(data);
1031 
1032  return rc;
1033 }
1034 
1035 static int
1036 stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
1037  int timeout)
1038 {
1039  int rc;
1040  xmlNode *output = NULL;
1041 
1042  rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
1043 
1044  if (output && list_info) {
1045  const char *list_str;
1046 
1047  list_str = crm_element_value(output, "st_output");
1048 
1049  if (list_str) {
1050  *list_info = strdup(list_str);
1051  }
1052  }
1053 
1054  if (output) {
1055  free_xml(output);
1056  }
1057 
1058  return rc;
1059 }
1060 
1061 static int
1062 stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
1063 {
1064  return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
1065 }
1066 
1067 static int
1068 stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
1069  int timeout)
1070 {
1071  return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
1072 }
1073 
1074 static int
1075 stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
1076  const char *action, int timeout, int tolerance, int delay)
1077 {
1078  int rc = 0;
1079  xmlNode *data = NULL;
1080 
1081  data = create_xml_node(NULL, __func__);
1087 
1088  rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
1089  free_xml(data);
1090 
1091  return rc;
1092 }
1093 
1094 static int
1095 stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
1096  int timeout, int tolerance)
1097 {
1098  return stonith_api_fence_with_delay(stonith, call_options, node, action,
1099  timeout, tolerance, 0);
1100 }
1101 
1102 static int
1103 stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
1104 {
1106  return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
1107 }
1108 
1109 static int
1110 stonith_api_history(stonith_t * stonith, int call_options, const char *node,
1111  stonith_history_t ** history, int timeout)
1112 {
1113  int rc = 0;
1114  xmlNode *data = NULL;
1115  xmlNode *output = NULL;
1116  stonith_history_t *last = NULL;
1117 
1118  *history = NULL;
1119 
1120  if (node) {
1121  data = create_xml_node(NULL, __func__);
1123  }
1124 
1125  stonith__set_call_options(call_options, node, st_opt_sync_call);
1126  rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
1127  call_options, timeout);
1128  free_xml(data);
1129 
1130  if (rc == 0) {
1131  xmlNode *op = NULL;
1132  xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
1133  LOG_NEVER);
1134 
1135  for (op = pcmk__xml_first_child(reply); op != NULL;
1136  op = pcmk__xml_next(op)) {
1137  stonith_history_t *kvp;
1138  long long completed;
1139 
1140  kvp = calloc(1, sizeof(stonith_history_t));
1146  crm_element_value_ll(op, F_STONITH_DATE, &completed);
1147  kvp->completed = (time_t) completed;
1149 
1150  if (last) {
1151  last->next = kvp;
1152  } else {
1153  *history = kvp;
1154  }
1155  last = kvp;
1156  }
1157  }
1158 
1159  free_xml(output);
1160 
1161  return rc;
1162 }
1163 
1165 {
1166  stonith_history_t *hp, *hp_old;
1167 
1168  for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
1169  free(hp->target);
1170  free(hp->action);
1171  free(hp->origin);
1172  free(hp->delegate);
1173  free(hp->client);
1174  }
1175 }
1176 
1177 static gint
1178 stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
1179 {
1180  int rc = 0;
1181  const stonith_notify_client_t *a_client = a;
1182  const stonith_notify_client_t *b_client = b;
1183 
1184  if (a_client->delete || b_client->delete) {
1185  /* make entries marked for deletion not findable */
1186  return -1;
1187  }
1188  CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
1189  rc = strcmp(a_client->event, b_client->event);
1190  if (rc == 0) {
1191  if (a_client->notify == NULL || b_client->notify == NULL) {
1192  return 0;
1193 
1194  } else if (a_client->notify == b_client->notify) {
1195  return 0;
1196 
1197  } else if (((long)a_client->notify) < ((long)b_client->notify)) {
1198  crm_err("callbacks for %s are not equal: %p vs. %p",
1199  a_client->event, a_client->notify, b_client->notify);
1200  return -1;
1201  }
1202  crm_err("callbacks for %s are not equal: %p vs. %p",
1203  a_client->event, a_client->notify, b_client->notify);
1204  return 1;
1205  }
1206  return rc;
1207 }
1208 
1209 xmlNode *
1210 stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
1211 {
1212  xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
1213 
1214  CRM_CHECK(op_msg != NULL, return NULL);
1215  CRM_CHECK(token != NULL, return NULL);
1216 
1217  crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
1218 
1219  crm_xml_add(op_msg, F_TYPE, T_STONITH_NG);
1220  crm_xml_add(op_msg, F_STONITH_CALLBACK_TOKEN, token);
1221  crm_xml_add(op_msg, F_STONITH_OPERATION, op);
1222  crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
1223  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
1224  crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
1225 
1226  if (data != NULL) {
1228  }
1229 
1230  return op_msg;
1231 }
1232 
1233 static void
1234 stonith_destroy_op_callback(gpointer data)
1235 {
1237 
1238  if (blob->timer && blob->timer->ref > 0) {
1239  g_source_remove(blob->timer->ref);
1240  }
1241  free(blob->timer);
1242  free(blob);
1243 }
1244 
1245 static int
1246 stonith_api_signoff(stonith_t * stonith)
1247 {
1248  stonith_private_t *native = stonith->st_private;
1249 
1250  crm_debug("Disconnecting from the fencer");
1251 
1252  if (native->source != NULL) {
1253  /* Attached to mainloop */
1254  mainloop_del_ipc_client(native->source);
1255  native->source = NULL;
1256  native->ipc = NULL;
1257 
1258  } else if (native->ipc) {
1259  /* Not attached to mainloop */
1260  crm_ipc_t *ipc = native->ipc;
1261 
1262  native->ipc = NULL;
1263  crm_ipc_close(ipc);
1264  crm_ipc_destroy(ipc);
1265  }
1266 
1267  free(native->token); native->token = NULL;
1268  stonith->state = stonith_disconnected;
1269  return pcmk_ok;
1270 }
1271 
1272 static int
1273 stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
1274 {
1275  stonith_private_t *private = stonith->st_private;
1276 
1277  if (all_callbacks) {
1278  private->op_callback = NULL;
1279  g_hash_table_destroy(private->stonith_op_callback_table);
1280  private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1281  NULL,
1282  stonith_destroy_op_callback);
1283 
1284  } else if (call_id == 0) {
1285  private->op_callback = NULL;
1286 
1287  } else {
1288  g_hash_table_remove(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1289  }
1290  return pcmk_ok;
1291 }
1292 
1293 static void
1294 invoke_callback(stonith_t * st, int call_id, int rc, void *userdata,
1295  void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1296 {
1297  stonith_callback_data_t data = { 0, };
1298 
1299  data.call_id = call_id;
1300  data.rc = rc;
1301  data.userdata = userdata;
1302 
1303  callback(st, &data);
1304 }
1305 
1306 static void
1307 stonith_perform_callback(stonith_t * stonith, xmlNode * msg, int call_id, int rc)
1308 {
1309  stonith_private_t *private = NULL;
1310  stonith_callback_client_t *blob = NULL;
1311  stonith_callback_client_t local_blob;
1312 
1313  CRM_CHECK(stonith != NULL, return);
1314  CRM_CHECK(stonith->st_private != NULL, return);
1315 
1316  private = stonith->st_private;
1317 
1318  local_blob.id = NULL;
1319  local_blob.callback = NULL;
1320  local_blob.user_data = NULL;
1321  local_blob.only_success = FALSE;
1322 
1323  if (msg != NULL) {
1325  crm_element_value_int(msg, F_STONITH_CALLID, &call_id);
1326  }
1327 
1328  CRM_CHECK(call_id > 0, crm_log_xml_err(msg, "Bad result"));
1329 
1330  blob = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1331 
1332  if (blob != NULL) {
1333  local_blob = *blob;
1334  blob = NULL;
1335 
1336  stonith_api_del_callback(stonith, call_id, FALSE);
1337 
1338  } else {
1339  crm_trace("No callback found for call %d", call_id);
1340  local_blob.callback = NULL;
1341  }
1342 
1343  if (local_blob.callback != NULL && (rc == pcmk_ok || local_blob.only_success == FALSE)) {
1344  crm_trace("Invoking callback %s for call %d", crm_str(local_blob.id), call_id);
1345  invoke_callback(stonith, call_id, rc, local_blob.user_data, local_blob.callback);
1346 
1347  } else if (private->op_callback == NULL && rc != pcmk_ok) {
1348  crm_warn("Fencing command failed: %s", pcmk_strerror(rc));
1349  crm_log_xml_debug(msg, "Failed fence update");
1350  }
1351 
1352  if (private->op_callback != NULL) {
1353  crm_trace("Invoking global callback for call %d", call_id);
1354  invoke_callback(stonith, call_id, rc, NULL, private->op_callback);
1355  }
1356  crm_trace("OP callback activated.");
1357 }
1358 
1359 static gboolean
1360 stonith_async_timeout_handler(gpointer data)
1361 {
1362  struct timer_rec_s *timer = data;
1363 
1364  crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
1365  stonith_perform_callback(timer->stonith, NULL, timer->call_id, -ETIME);
1366 
1367  /* Always return TRUE, never remove the handler
1368  * We do that in stonith_del_callback()
1369  */
1370  return TRUE;
1371 }
1372 
1373 static void
1374 set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1375  int timeout)
1376 {
1377  struct timer_rec_s *async_timer = callback->timer;
1378 
1379  if (timeout <= 0) {
1380  return;
1381  }
1382 
1383  if (!async_timer) {
1384  async_timer = calloc(1, sizeof(struct timer_rec_s));
1385  callback->timer = async_timer;
1386  }
1387 
1388  async_timer->stonith = stonith;
1389  async_timer->call_id = call_id;
1390  /* Allow a fair bit of grace to allow the server to tell us of a timeout
1391  * This is only a fallback
1392  */
1393  async_timer->timeout = (timeout + 60) * 1000;
1394  if (async_timer->ref) {
1395  g_source_remove(async_timer->ref);
1396  }
1397  async_timer->ref =
1398  g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1399 }
1400 
1401 static void
1402 update_callback_timeout(int call_id, int timeout, stonith_t * st)
1403 {
1404  stonith_callback_client_t *callback = NULL;
1405  stonith_private_t *private = st->st_private;
1406 
1407  callback = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1408  if (!callback || !callback->allow_timeout_updates) {
1409  return;
1410  }
1411 
1412  set_callback_timeout(callback, st, call_id, timeout);
1413 }
1414 
1415 static int
1416 stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1417 {
1418  const char *type = NULL;
1419  struct notify_blob_s blob;
1420 
1421  stonith_t *st = userdata;
1422  stonith_private_t *private = NULL;
1423 
1424  CRM_ASSERT(st != NULL);
1425  private = st->st_private;
1426 
1427  blob.stonith = st;
1428  blob.xml = string2xml(buffer);
1429  if (blob.xml == NULL) {
1430  crm_warn("Received malformed message from fencer: %s", buffer);
1431  return 0;
1432  }
1433 
1434  /* do callbacks */
1435  type = crm_element_value(blob.xml, F_TYPE);
1436  crm_trace("Activating %s callbacks...", type);
1437 
1438  if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_casei)) {
1439  stonith_perform_callback(st, blob.xml, 0, 0);
1440 
1441  } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_casei)) {
1442  foreach_notify_entry(private, stonith_send_notification, &blob);
1443  } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_casei)) {
1444  int call_id = 0;
1445  int timeout = 0;
1446 
1448  crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1449 
1450  update_callback_timeout(call_id, timeout, st);
1451  } else {
1452  crm_err("Unknown message type: %s", type);
1453  crm_log_xml_warn(blob.xml, "BadReply");
1454  }
1455 
1456  free_xml(blob.xml);
1457  return 1;
1458 }
1459 
1460 static int
1461 stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1462 {
1463  int rc = pcmk_ok;
1464  stonith_private_t *native = NULL;
1465  const char *display_name = name? name : "client";
1466 
1467  struct ipc_client_callbacks st_callbacks = {
1468  .dispatch = stonith_dispatch_internal,
1469  .destroy = stonith_connection_destroy
1470  };
1471 
1472  CRM_CHECK(stonith != NULL, return -EINVAL);
1473 
1474  native = stonith->st_private;
1475  CRM_ASSERT(native != NULL);
1476 
1477  crm_debug("Attempting fencer connection by %s with%s mainloop",
1478  display_name, (stonith_fd? "out" : ""));
1479 
1480  stonith->state = stonith_connected_command;
1481  if (stonith_fd) {
1482  /* No mainloop */
1483  native->ipc = crm_ipc_new("stonith-ng", 0);
1484 
1485  if (native->ipc && crm_ipc_connect(native->ipc)) {
1486  *stonith_fd = crm_ipc_get_fd(native->ipc);
1487  } else if (native->ipc) {
1488  crm_ipc_close(native->ipc);
1489  crm_ipc_destroy(native->ipc);
1490  native->ipc = NULL;
1491  }
1492 
1493  } else {
1494  /* With mainloop */
1495  native->source =
1496  mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1497  native->ipc = mainloop_get_ipc_client(native->source);
1498  }
1499 
1500  if (native->ipc == NULL) {
1501  rc = -ENOTCONN;
1502  } else {
1503  xmlNode *reply = NULL;
1504  xmlNode *hello = create_xml_node(NULL, "stonith_command");
1505 
1506  crm_xml_add(hello, F_TYPE, T_STONITH_NG);
1509  rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1510 
1511  if (rc < 0) {
1512  crm_debug("Couldn't register with the fencer: %s "
1513  CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1514  rc = -ECOMM;
1515 
1516  } else if (reply == NULL) {
1517  crm_debug("Couldn't register with the fencer: no reply");
1518  rc = -EPROTO;
1519 
1520  } else {
1521  const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1522 
1523  native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1524  if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
1525  crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1526  (msg_type? msg_type : "(missing)"));
1527  crm_log_xml_debug(reply, "Invalid fencer reply");
1528  rc = -EPROTO;
1529 
1530  } else if (native->token == NULL) {
1531  crm_debug("Couldn't register with the fencer: no token in reply");
1532  crm_log_xml_debug(reply, "Invalid fencer reply");
1533  rc = -EPROTO;
1534 
1535  } else {
1536 #if HAVE_MSGFROMIPC_TIMEOUT
1537  stonith->call_timeout = MAX_IPC_DELAY;
1538 #endif
1539  crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1540  display_name, native->token);
1541  rc = pcmk_ok;
1542  }
1543  }
1544 
1545  free_xml(reply);
1546  free_xml(hello);
1547  }
1548 
1549  if (rc != pcmk_ok) {
1550  crm_debug("Connection attempt to fencer by %s failed: %s "
1551  CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1552  stonith->cmds->disconnect(stonith);
1553  }
1554  return rc;
1555 }
1556 
1557 static int
1558 stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1559 {
1560  int rc = pcmk_ok;
1561  xmlNode *notify_msg = create_xml_node(NULL, __func__);
1562  stonith_private_t *native = stonith->st_private;
1563 
1564  if (stonith->state != stonith_disconnected) {
1565 
1567  if (enabled) {
1568  crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1569  } else {
1570  crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1571  }
1572 
1573  rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1574  if (rc < 0) {
1575  crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1576  rc = -ECOMM;
1577  } else {
1578  rc = pcmk_ok;
1579  }
1580  }
1581 
1582  free_xml(notify_msg);
1583  return rc;
1584 }
1585 
1586 static int
1587 stonith_api_add_notification(stonith_t * stonith, const char *event,
1588  void (*callback) (stonith_t * stonith, stonith_event_t * e))
1589 {
1590  GList *list_item = NULL;
1591  stonith_notify_client_t *new_client = NULL;
1592  stonith_private_t *private = NULL;
1593 
1594  private = stonith->st_private;
1595  crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1596 
1597  new_client = calloc(1, sizeof(stonith_notify_client_t));
1598  new_client->event = event;
1599  new_client->notify = callback;
1600 
1601  list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1602 
1603  if (list_item != NULL) {
1604  crm_warn("Callback already present");
1605  free(new_client);
1606  return -ENOTUNIQ;
1607 
1608  } else {
1609  private->notify_list = g_list_append(private->notify_list, new_client);
1610 
1611  stonith_set_notification(stonith, event, 1);
1612 
1613  crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1614  }
1615  return pcmk_ok;
1616 }
1617 
1618 static int
1619 stonith_api_del_notification(stonith_t * stonith, const char *event)
1620 {
1621  GList *list_item = NULL;
1622  stonith_notify_client_t *new_client = NULL;
1623  stonith_private_t *private = NULL;
1624 
1625  crm_debug("Removing callback for %s events", event);
1626 
1627  private = stonith->st_private;
1628  new_client = calloc(1, sizeof(stonith_notify_client_t));
1629  new_client->event = event;
1630  new_client->notify = NULL;
1631 
1632  list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1633 
1634  stonith_set_notification(stonith, event, 0);
1635 
1636  if (list_item != NULL) {
1637  stonith_notify_client_t *list_client = list_item->data;
1638 
1639  if (private->notify_refcnt) {
1640  list_client->delete = TRUE;
1641  private->notify_deletes = TRUE;
1642  } else {
1643  private->notify_list = g_list_remove(private->notify_list, list_client);
1644  free(list_client);
1645  }
1646 
1647  crm_trace("Removed callback");
1648 
1649  } else {
1650  crm_trace("Callback not present");
1651  }
1652  free(new_client);
1653  return pcmk_ok;
1654 }
1655 
1656 static int
1657 stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1658  void *user_data, const char *callback_name,
1659  void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1660 {
1661  stonith_callback_client_t *blob = NULL;
1662  stonith_private_t *private = NULL;
1663 
1664  CRM_CHECK(stonith != NULL, return -EINVAL);
1665  CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1666  private = stonith->st_private;
1667 
1668  if (call_id == 0) {
1669  private->op_callback = callback;
1670 
1671  } else if (call_id < 0) {
1672  if (!(options & st_opt_report_only_success)) {
1673  crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1674  invoke_callback(stonith, call_id, call_id, user_data, callback);
1675  } else {
1676  crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1677  }
1678  return FALSE;
1679  }
1680 
1681  blob = calloc(1, sizeof(stonith_callback_client_t));
1682  blob->id = callback_name;
1683  blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1684  blob->user_data = user_data;
1685  blob->callback = callback;
1686  blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1687 
1688  if (timeout > 0) {
1689  set_callback_timeout(blob, stonith, call_id, timeout);
1690  }
1691 
1692  g_hash_table_insert(private->stonith_op_callback_table, GINT_TO_POINTER(call_id), blob);
1693  crm_trace("Added callback to %s for call %d", callback_name, call_id);
1694 
1695  return TRUE;
1696 }
1697 
1698 static void
1699 stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1700 {
1701  int call = GPOINTER_TO_INT(key);
1702  stonith_callback_client_t *blob = value;
1703 
1704  crm_debug("Call %d (%s): pending", call, crm_str(blob->id));
1705 }
1706 
1707 void
1709 {
1710  stonith_private_t *private = stonith->st_private;
1711 
1712  if (private->stonith_op_callback_table == NULL) {
1713  return;
1714  }
1715  return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1716 }
1717 
1718 /*
1719  <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1720  <st_calldata >
1721  <stonith_command t="stonith-ng" st_async_id="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_op="st_device_register" st_callid="2" st_callopt="4096" st_timeout="0" st_clientid="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_clientname="cts-fence-helper" >
1722  <st_calldata >
1723  <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1724  <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1725  </st_device_id>
1726  </st_calldata>
1727  </stonith_command>
1728  </st_calldata>
1729  </notify>
1730 
1731  <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1732  <st_calldata >
1733  <st_notify_fence st_rc="0" st_target="some-host" st_op="st_fence" st_delegate="test-id" st_origin="61dd7759-e229-4be7-b1f8-ef49dd14d9f0" />
1734  </st_calldata>
1735  </notify>
1736 */
1737 static stonith_event_t *
1738 xml_to_event(xmlNode * msg)
1739 {
1740  stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1741  const char *ntype = crm_element_value(msg, F_SUBTYPE);
1742  char *data_addr = crm_strdup_printf("//%s", ntype);
1743  xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1744 
1745  crm_log_xml_trace(msg, "stonith_notify");
1746 
1747  crm_element_value_int(msg, F_STONITH_RC, &(event->result));
1748 
1749  if (pcmk__str_eq(ntype, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
1750  event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1751 
1752  if (data) {
1753  event->origin = crm_element_value_copy(data, F_STONITH_ORIGIN);
1754  event->action = crm_element_value_copy(data, F_STONITH_ACTION);
1755  event->target = crm_element_value_copy(data, F_STONITH_TARGET);
1756  event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1758  event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1759  event->device = crm_element_value_copy(data, F_STONITH_DEVICE);
1760 
1761  } else {
1762  crm_err("No data for %s event", ntype);
1763  crm_log_xml_notice(msg, "BadEvent");
1764  }
1765  }
1766 
1767  free(data_addr);
1768  return event;
1769 }
1770 
1771 static void
1772 event_free(stonith_event_t * event)
1773 {
1774  free(event->id);
1775  free(event->type);
1776  free(event->message);
1777  free(event->operation);
1778  free(event->origin);
1779  free(event->action);
1780  free(event->target);
1781  free(event->executioner);
1782  free(event->device);
1783  free(event->client_origin);
1784  free(event);
1785 }
1786 
1787 static void
1788 stonith_send_notification(gpointer data, gpointer user_data)
1789 {
1790  struct notify_blob_s *blob = user_data;
1791  stonith_notify_client_t *entry = data;
1792  stonith_event_t *st_event = NULL;
1793  const char *event = NULL;
1794 
1795  if (blob->xml == NULL) {
1796  crm_warn("Skipping callback - NULL message");
1797  return;
1798  }
1799 
1800  event = crm_element_value(blob->xml, F_SUBTYPE);
1801 
1802  if (entry == NULL) {
1803  crm_warn("Skipping callback - NULL callback client");
1804  return;
1805 
1806  } else if (entry->delete) {
1807  crm_trace("Skipping callback - marked for deletion");
1808  return;
1809 
1810  } else if (entry->notify == NULL) {
1811  crm_warn("Skipping callback - NULL callback");
1812  return;
1813 
1814  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
1815  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1816  return;
1817  }
1818 
1819  st_event = xml_to_event(blob->xml);
1820 
1821  crm_trace("Invoking callback for %p/%s event...", entry, event);
1822  entry->notify(blob->stonith, st_event);
1823  crm_trace("Callback invoked...");
1824 
1825  event_free(st_event);
1826 }
1827 
1842 static int
1843 stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1844  int call_options, int timeout)
1845 {
1846  int rc = 0;
1847  int reply_id = -1;
1848 
1849  xmlNode *op_msg = NULL;
1850  xmlNode *op_reply = NULL;
1851  stonith_private_t *native = NULL;
1852 
1853  CRM_ASSERT(stonith && stonith->st_private && op);
1854  native = stonith->st_private;
1855 
1856  if (output_data != NULL) {
1857  *output_data = NULL;
1858  }
1859 
1860  if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1861  return -ENOTCONN;
1862  }
1863 
1864  /* Increment the call ID, which must be positive to avoid conflicting with
1865  * error codes. This shouldn't be a problem unless the client mucked with
1866  * it or the counter wrapped around.
1867  */
1868  stonith->call_id++;
1869  if (stonith->call_id < 1) {
1870  stonith->call_id = 1;
1871  }
1872 
1873  op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1874  if (op_msg == NULL) {
1875  return -EINVAL;
1876  }
1877 
1879  crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1880 
1881  if (data) {
1882  const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1883 
1884  if (delay_s) {
1885  crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1886  }
1887  }
1888 
1889  {
1890  enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1891 
1892  if (call_options & st_opt_sync_call) {
1893  pcmk__set_ipc_flags(ipc_flags, "stonith command",
1895  }
1896  rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1897  1000 * (timeout + 60), &op_reply);
1898  }
1899  free_xml(op_msg);
1900 
1901  if (rc < 0) {
1902  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1903  rc = -ECOMM;
1904  goto done;
1905  }
1906 
1907  crm_log_xml_trace(op_reply, "Reply");
1908 
1909  if (!(call_options & st_opt_sync_call)) {
1910  crm_trace("Async call %d, returning", stonith->call_id);
1911  free_xml(op_reply);
1912  return stonith->call_id;
1913  }
1914 
1915  rc = pcmk_ok;
1916  crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1917 
1918  if (reply_id == stonith->call_id) {
1919  crm_trace("Synchronous reply %d received", reply_id);
1920 
1921  if (crm_element_value_int(op_reply, F_STONITH_RC, &rc) != 0) {
1922  rc = -ENOMSG;
1923  }
1924 
1925  if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1926  crm_trace("Discarding reply");
1927 
1928  } else {
1929  *output_data = op_reply;
1930  op_reply = NULL; /* Prevent subsequent free */
1931  }
1932 
1933  } else if (reply_id <= 0) {
1934  crm_err("Received bad reply: No id set");
1935  crm_log_xml_err(op_reply, "Bad reply");
1936  free_xml(op_reply);
1937  rc = -ENOMSG;
1938 
1939  } else {
1940  crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1941  crm_log_xml_err(op_reply, "Old reply");
1942  free_xml(op_reply);
1943  rc = -ENOMSG;
1944  }
1945 
1946  done:
1947  if (crm_ipc_connected(native->ipc) == FALSE) {
1948  crm_err("Fencer disconnected");
1949  free(native->token); native->token = NULL;
1950  stonith->state = stonith_disconnected;
1951  }
1952 
1953  free_xml(op_reply);
1954  return rc;
1955 }
1956 
1957 /* Not used with mainloop */
1958 bool
1960 {
1961  gboolean stay_connected = TRUE;
1962  stonith_private_t *private = NULL;
1963 
1964  CRM_ASSERT(st != NULL);
1965  private = st->st_private;
1966 
1967  while (crm_ipc_ready(private->ipc)) {
1968 
1969  if (crm_ipc_read(private->ipc) > 0) {
1970  const char *msg = crm_ipc_buffer(private->ipc);
1971 
1972  stonith_dispatch_internal(msg, strlen(msg), st);
1973  }
1974 
1975  if (crm_ipc_connected(private->ipc) == FALSE) {
1976  crm_err("Connection closed");
1977  stay_connected = FALSE;
1978  }
1979  }
1980 
1981  return stay_connected;
1982 }
1983 
1984 static int
1985 stonith_api_free(stonith_t * stonith)
1986 {
1987  int rc = pcmk_ok;
1988 
1989  crm_trace("Destroying %p", stonith);
1990 
1991  if (stonith->state != stonith_disconnected) {
1992  crm_trace("Disconnecting %p first", stonith);
1993  rc = stonith->cmds->disconnect(stonith);
1994  }
1995 
1996  if (stonith->state == stonith_disconnected) {
1997  stonith_private_t *private = stonith->st_private;
1998 
1999  crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
2000  g_hash_table_destroy(private->stonith_op_callback_table);
2001 
2002  crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
2003  g_list_free_full(private->notify_list, free);
2004 
2005  free(stonith->st_private);
2006  free(stonith->cmds);
2007  free(stonith);
2008 
2009  } else {
2010  crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
2011  }
2012 
2013  return rc;
2014 }
2015 
2016 void
2018 {
2019  crm_trace("Destroying %p", stonith);
2020  if(stonith) {
2021  stonith->cmds->free(stonith);
2022  }
2023 }
2024 
2025 static int
2026 stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
2027  const char *namespace_s, const char *agent,
2028  stonith_key_value_t *params, int timeout, char **output,
2029  char **error_output)
2030 {
2031  /* Validation should be done directly via the agent, so we can get it from
2032  * stonith_admin when the cluster is not running, which is important for
2033  * higher-level tools.
2034  */
2035 
2036  int rc = pcmk_ok;
2037 
2038  /* Use a dummy node name in case the agent requires a target. We assume the
2039  * actual target doesn't matter for validation purposes (if in practice,
2040  * that is incorrect, we will need to allow the caller to pass the target).
2041  */
2042  const char *target = "node1";
2043  const char *host_arg = NULL;
2044 
2045  GHashTable *params_table = crm_str_table_new();
2046 
2047  // Convert parameter list to a hash table
2048  for (; params; params = params->next) {
2049  if (pcmk__str_eq(params->key, STONITH_ATTR_HOSTARG, pcmk__str_casei)) {
2050  host_arg = params->value;
2051  }
2052 
2053  // Strip out Pacemaker-implemented parameters
2054  if (!pcmk__starts_with(params->key, "pcmk_")
2055  && strcmp(params->key, "provides")
2056  && strcmp(params->key, "stonith-timeout")) {
2057  g_hash_table_insert(params_table, strdup(params->key),
2058  strdup(params->value));
2059  }
2060  }
2061 
2062 #if SUPPORT_CIBSECRETS
2063  rc = pcmk__substitute_secrets(rsc_id, params_table);
2064  if (rc != pcmk_rc_ok) {
2065  crm_warn("Could not replace secret parameters for validation of %s: %s",
2066  agent, pcmk_rc_str(rc));
2067  // rc is standard return value, don't return it in this function
2068  }
2069 #endif
2070 
2071  if (output) {
2072  *output = NULL;
2073  }
2074  if (error_output) {
2075  *error_output = NULL;
2076  }
2077 
2078  switch (stonith_get_namespace(agent, namespace_s)) {
2079  case st_namespace_rhcs:
2080  rc = stonith__rhcs_validate(st, call_options, target, agent,
2081  params_table, host_arg, timeout,
2082  output, error_output);
2083  break;
2084 
2085 #if HAVE_STONITH_STONITH_H
2086  case st_namespace_lha:
2087  rc = stonith__lha_validate(st, call_options, target, agent,
2088  params_table, timeout, output,
2089  error_output);
2090  break;
2091 #endif
2092 
2093  default:
2094  rc = -EINVAL;
2095  errno = EINVAL;
2096  crm_perror(LOG_ERR,
2097  "Agent %s not found or does not support validation",
2098  agent);
2099  break;
2100  }
2101  g_hash_table_destroy(params_table);
2102  return rc;
2103 }
2104 
2105 stonith_t *
2107 {
2108  stonith_t *new_stonith = NULL;
2109  stonith_private_t *private = NULL;
2110 
2111  new_stonith = calloc(1, sizeof(stonith_t));
2112  if (new_stonith == NULL) {
2113  return NULL;
2114  }
2115 
2116  private = calloc(1, sizeof(stonith_private_t));
2117  if (private == NULL) {
2118  free(new_stonith);
2119  return NULL;
2120  }
2121  new_stonith->st_private = private;
2122 
2123  private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2124  NULL, stonith_destroy_op_callback);
2125  private->notify_list = NULL;
2126  private->notify_refcnt = 0;
2127  private->notify_deletes = FALSE;
2128 
2129  new_stonith->call_id = 1;
2130  new_stonith->state = stonith_disconnected;
2131 
2132  new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
2133  if (new_stonith->cmds == NULL) {
2134  free(new_stonith->st_private);
2135  free(new_stonith);
2136  return NULL;
2137  }
2138 
2139 /* *INDENT-OFF* */
2140  new_stonith->cmds->free = stonith_api_free;
2141  new_stonith->cmds->connect = stonith_api_signon;
2142  new_stonith->cmds->disconnect = stonith_api_signoff;
2143 
2144  new_stonith->cmds->list = stonith_api_list;
2145  new_stonith->cmds->monitor = stonith_api_monitor;
2146  new_stonith->cmds->status = stonith_api_status;
2147  new_stonith->cmds->fence = stonith_api_fence;
2148  new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
2149  new_stonith->cmds->confirm = stonith_api_confirm;
2150  new_stonith->cmds->history = stonith_api_history;
2151 
2152  new_stonith->cmds->list_agents = stonith_api_device_list;
2153  new_stonith->cmds->metadata = stonith_api_device_metadata;
2154 
2155  new_stonith->cmds->query = stonith_api_query;
2156  new_stonith->cmds->remove_device = stonith_api_remove_device;
2157  new_stonith->cmds->register_device = stonith_api_register_device;
2158 
2159  new_stonith->cmds->remove_level = stonith_api_remove_level;
2160  new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
2161  new_stonith->cmds->register_level = stonith_api_register_level;
2162  new_stonith->cmds->register_level_full = stonith_api_register_level_full;
2163 
2164  new_stonith->cmds->remove_callback = stonith_api_del_callback;
2165  new_stonith->cmds->register_callback = stonith_api_add_callback;
2166  new_stonith->cmds->remove_notification = stonith_api_del_notification;
2167  new_stonith->cmds->register_notification = stonith_api_add_notification;
2168 
2169  new_stonith->cmds->validate = stonith_api_validate;
2170 /* *INDENT-ON* */
2171 
2172  return new_stonith;
2173 }
2174 
2184 int
2185 stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
2186 {
2187  int rc = -EINVAL; // if max_attempts is not positive
2188 
2189  for (int attempt = 1; attempt <= max_attempts; attempt++) {
2190  rc = st->cmds->connect(st, name, NULL);
2191  if (rc == pcmk_ok) {
2192  return pcmk_ok;
2193  } else if (attempt < max_attempts) {
2194  crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
2195  CRM_XS " rc=%d",
2196  attempt, max_attempts, pcmk_strerror(rc), rc);
2197  sleep(2);
2198  }
2199  }
2200  crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
2201  pcmk_strerror(rc), rc);
2202  return rc;
2203 }
2204 
2206 stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
2207 {
2208  stonith_key_value_t *p, *end;
2209 
2210  p = calloc(1, sizeof(stonith_key_value_t));
2211  if (key) {
2212  p->key = strdup(key);
2213  }
2214  if (value) {
2215  p->value = strdup(value);
2216  }
2217 
2218  end = head;
2219  while (end && end->next) {
2220  end = end->next;
2221  }
2222 
2223  if (end) {
2224  end->next = p;
2225  } else {
2226  head = p;
2227  }
2228 
2229  return head;
2230 }
2231 
2232 void
2233 stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values)
2234 {
2236 
2237  while (head) {
2238  p = head->next;
2239  if (keys) {
2240  free(head->key);
2241  }
2242  if (values) {
2243  free(head->value);
2244  }
2245  free(head);
2246  head = p;
2247  }
2248 }
2249 
2250 #define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
2251 #define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
2252 
2253 int
2254 stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
2255 {
2256  int rc = pcmk_ok;
2258  const char *action = off? "off" : "reboot";
2259 
2260  api_log_open();
2261  if (st == NULL) {
2262  api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
2263  action, nodeid, uname);
2264  return -EPROTO;
2265  }
2266 
2267  rc = st->cmds->connect(st, "stonith-api", NULL);
2268  if (rc != pcmk_ok) {
2269  api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
2270  action, nodeid, uname, pcmk_strerror(rc), rc);
2271  } else {
2272  char *name = (uname == NULL)? crm_itoa(nodeid) : strdup(uname);
2273  int opts = 0;
2274 
2277  if ((uname == NULL) && (nodeid > 0)) {
2279  }
2280  rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2281  free(name);
2282 
2283  if (rc != pcmk_ok) {
2284  api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2285  action, nodeid, uname, pcmk_strerror(rc), rc);
2286  } else {
2287  api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2288  }
2289  }
2290 
2292  return rc;
2293 }
2294 
2295 time_t
2296 stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2297 {
2298  int rc = pcmk_ok;
2299  time_t when = 0;
2301  stonith_history_t *history = NULL, *hp = NULL;
2302 
2303  if (st == NULL) {
2304  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2305  "API initialization failed", nodeid, uname);
2306  return when;
2307  }
2308 
2309  rc = st->cmds->connect(st, "stonith-api", NULL);
2310  if (rc != pcmk_ok) {
2311  api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2312  } else {
2313  int entries = 0;
2314  int progress = 0;
2315  int completed = 0;
2316  int opts = 0;
2317  char *name = (uname == NULL)? crm_itoa(nodeid) : strdup(uname);
2318 
2320  if ((uname == NULL) && (nodeid > 0)) {
2322  }
2323  rc = st->cmds->history(st, opts, name, &history, 120);
2324  free(name);
2325 
2326  for (hp = history; hp; hp = hp->next) {
2327  entries++;
2328  if (in_progress) {
2329  progress++;
2330  if (hp->state != st_done && hp->state != st_failed) {
2331  when = time(NULL);
2332  }
2333 
2334  } else if (hp->state == st_done) {
2335  completed++;
2336  if (hp->completed > when) {
2337  when = hp->completed;
2338  }
2339  }
2340  }
2341 
2342  stonith_history_free(history);
2343 
2344  if(rc == pcmk_ok) {
2345  api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2346  } else {
2347  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2348  }
2349  }
2350 
2352 
2353  if(when) {
2354  api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2355  }
2356  return when;
2357 }
2358 
2359 bool
2360 stonith_agent_exists(const char *agent, int timeout)
2361 {
2362  stonith_t *st = NULL;
2363  stonith_key_value_t *devices = NULL;
2364  stonith_key_value_t *dIter = NULL;
2365  bool rc = FALSE;
2366 
2367  if (agent == NULL) {
2368  return rc;
2369  }
2370 
2371  st = stonith_api_new();
2372  if (st == NULL) {
2373  crm_err("Could not list fence agents: API memory allocation failed");
2374  return FALSE;
2375  }
2376  st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2377 
2378  for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2379  if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2380  rc = TRUE;
2381  break;
2382  }
2383  }
2384 
2385  stonith_key_value_freeall(devices, 1, 1);
2387  return rc;
2388 }
2389 
2390 const char *
2392 {
2393  if (action == NULL) {
2394  return "fencing";
2395  } else if (!strcmp(action, "on")) {
2396  return "unfencing";
2397  } else if (!strcmp(action, "off")) {
2398  return "turning off";
2399  } else {
2400  return action;
2401  }
2402 }
2403 
2412 static void
2413 parse_list_line(const char *line, int len, GList **output)
2414 {
2415  size_t i = 0;
2416  size_t entry_start = 0;
2417 
2418  /* Skip complaints about additional parameters device doesn't understand
2419  *
2420  * @TODO Document or eliminate the implied restriction of target names
2421  */
2422  if (strstr(line, "invalid") || strstr(line, "variable")) {
2423  crm_debug("Skipping list output line: %s", line);
2424  return;
2425  }
2426 
2427  // Process line content, character by character
2428  for (i = 0; i <= len; i++) {
2429 
2430  if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2431  || (line[i] == '\0')) {
2432  // We've found a separator (i.e. the end of an entry)
2433 
2434  int rc = 0;
2435  char *entry = NULL;
2436 
2437  if (i == entry_start) {
2438  // Skip leading and sequential separators
2439  entry_start = i + 1;
2440  continue;
2441  }
2442 
2443  entry = calloc(i - entry_start + 1, sizeof(char));
2444  CRM_ASSERT(entry != NULL);
2445 
2446  /* Read entry, stopping at first separator
2447  *
2448  * @TODO Document or eliminate these character restrictions
2449  */
2450  rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2451  if (rc != 1) {
2452  crm_warn("Could not parse list output entry: %s "
2453  CRM_XS " entry_start=%d position=%d",
2454  line + entry_start, entry_start, i);
2455  free(entry);
2456 
2457  } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2458  /* Some agents print the target status in the list output,
2459  * though none are known now (the separate list-status command
2460  * is used for this, but it can also print "UNKNOWN"). To handle
2461  * this possibility, skip such entries.
2462  *
2463  * @TODO Document or eliminate the implied restriction of target
2464  * names.
2465  */
2466  free(entry);
2467 
2468  } else {
2469  // We have a valid entry
2470  *output = g_list_append(*output, entry);
2471  }
2472  entry_start = i + 1;
2473  }
2474  }
2475 }
2476 
2498 GList *
2499 stonith__parse_targets(const char *target_spec)
2500 {
2501  GList *targets = NULL;
2502 
2503  if (target_spec != NULL) {
2504  size_t out_len = strlen(target_spec);
2505  size_t line_start = 0; // Starting index of line being processed
2506 
2507  for (size_t i = 0; i <= out_len; ++i) {
2508  if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2509  || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2510  // We've reached the end of one line of output
2511 
2512  int len = i - line_start;
2513 
2514  if (len > 0) {
2515  char *line = strndup(target_spec + line_start, len);
2516 
2517  line[len] = '\0'; // Because it might be a newline
2518  parse_list_line(line, len, &targets);
2519  free(line);
2520  }
2521  if (target_spec[i] == '\\') {
2522  ++i; // backslash-n takes up two positions
2523  }
2524  line_start = i + 1;
2525  }
2526  }
2527  }
2528  return targets;
2529 }
2530 
2538 gboolean
2540 {
2541  gboolean ret = FALSE;
2542 
2543  for (stonith_history_t *prev_hp = top_history; prev_hp; prev_hp = prev_hp->next) {
2544  if (prev_hp == event) {
2545  break;
2546  }
2547 
2548  if ((prev_hp->state == st_done) &&
2549  pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2550  pcmk__str_eq(event->action, prev_hp->action, pcmk__str_casei) &&
2551  pcmk__str_eq(event->delegate, prev_hp->delegate, pcmk__str_casei) &&
2552  (event->completed < prev_hp->completed)) {
2553  ret = TRUE;
2554  break;
2555  }
2556  }
2557  return ret;
2558 }
2559 
2571 {
2572  stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2573 
2574  for (hp = history; hp; ) {
2575  tmp = hp->next;
2576  if ((hp->state == st_done) || (hp->state == st_failed)) {
2577  /* sort into new */
2578  if ((!new) || (hp->completed > new->completed)) {
2579  hp->next = new;
2580  new = hp;
2581  } else {
2582  np = new;
2583  do {
2584  if ((!np->next) || (hp->completed > np->next->completed)) {
2585  hp->next = np->next;
2586  np->next = hp;
2587  break;
2588  }
2589  np = np->next;
2590  } while (1);
2591  }
2592  } else {
2593  /* put into pending */
2594  hp->next = pending;
2595  pending = hp;
2596  }
2597  hp = tmp;
2598  }
2599 
2600  /* pending actions don't have a completed-stamp so make them go front */
2601  if (pending) {
2602  stonith_history_t *last_pending = pending;
2603 
2604  while (last_pending->next) {
2605  last_pending = last_pending->next;
2606  }
2607 
2608  last_pending->next = new;
2609  new = pending;
2610  }
2611  return new;
2612 }
2613 
2616  bool (*matching_fn)(stonith_history_t *, void *),
2617  void *user_data)
2618 {
2619  for (stonith_history_t *hp = history; hp; hp = hp->next) {
2620  if (matching_fn(hp, user_data)) {
2621  return hp;
2622  }
2623  }
2624 
2625  return NULL;
2626 }
2627 
2628 bool
2630 {
2631  return history->state != st_failed && history->state != st_done;
2632 }
2633 
2634 bool
2635 stonith__event_state_eq(stonith_history_t *history, void *user_data)
2636 {
2637  return history->state == GPOINTER_TO_INT(user_data);
2638 }
2639 
2640 bool
2642 {
2643  return history->state != GPOINTER_TO_INT(user_data);
2644 }
2645 
2646 // Deprecated functions kept only for backward API compatibility
2647 const char *get_stonith_provider(const char *agent, const char *provider);
2648 
2652 const char *
2653 get_stonith_provider(const char *agent, const char *provider)
2654 {
2655  return stonith_namespace2text(stonith_get_namespace(agent, provider));
2656 }
2657 
2658 void
2659 stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2660  xmlNode *metadata)
2661 {
2662  xmlXPathObjectPtr xpath = NULL;
2663  int max = 0;
2664  int lpc = 0;
2665 
2666  CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2667 
2668  xpath = xpath_search(metadata, "//parameter");
2669  max = numXpathResults(xpath);
2670 
2671  if (max <= 0) {
2672  freeXpathObject(xpath);
2673  return;
2674  }
2675 
2676  for (lpc = 0; lpc < max; lpc++) {
2677  const char *parameter = NULL;
2678  xmlNode *match = getXpathResult(xpath, lpc);
2679 
2680  CRM_LOG_ASSERT(match != NULL);
2681  if (match == NULL) {
2682  continue;
2683  }
2684 
2685  parameter = crm_element_value(match, "name");
2686 
2687  if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2688  stonith__set_device_flags(*device_flags, device_name,
2690 
2691  } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2692  stonith__set_device_flags(*device_flags, device_name,
2694  }
2695  }
2696 
2697  freeXpathObject(xpath);
2698 }
F_STONITH_RC
#define F_STONITH_RC
Definition: internal.h:105
stonith__sort_history
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2570
services_action_free
void services_action_free(svc_action_t *op)
Definition: services.c:472
pcmk__str_casei
@ pcmk__str_casei
Definition: strings_internal.h:26
stonith_api_operations_s::register_notification
int(* register_notification)(stonith_t *st, const char *event, void(*notify)(stonith_t *st, stonith_event_t *e))
Definition: stonith-ng.h:297
crm_element_value_ll
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: nvpair.c:587
create_device_registration_xml
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, stonith_key_value_t *params, const char *rsc_provides)
Definition: st_client.c:274
st_failed
@ st_failed
Definition: stonith-ng.h:71
stonith_api_operations_s::remove_level
int(* remove_level)(stonith_t *st, int options, const char *node, int level)
Remove a fencing level for a specific node.
Definition: stonith-ng.h:190
crm_ipc_connect
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:790
st
stonith_t * st
Definition: pcmk_fence.c:28
pcmk_err_generic
#define pcmk_err_generic
Definition: results.h:70
STONITH_OP_DEVICE_DEL
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:171
rc
int rc
Definition: pcmk_fence.c:35
stonith_text2namespace
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition: st_client.c:130
st_opt_manual_ack
@ st_opt_manual_ack
Definition: stonith-ng.h:46
stonith__rhcs_validate
int stonith__rhcs_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, const char *host_arg, int timeout, char **output, char **error_output)
Definition: st_rhcs.c:242
msg_xml.h
stonith_api_operations_s::metadata
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition: stonith-ng.h:211
stonith_event_s::executioner
char * executioner
Definition: stonith-ng.h:122
T_STONITH_NOTIFY
#define T_STONITH_NOTIFY
Definition: internal.h:153
data
char data[0]
Definition: internal.h:10
stonith_agent_exists
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2360
LOG_TRACE
#define LOG_TRACE
Definition: logging.h:36
stonith_disconnected
@ stonith_disconnected
Definition: stonith-ng.h:38
svc_action_s::flags
enum svc_action_flags flags
Definition: services.h:145
crm_element_value_int
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:559
st_namespace_rhcs
@ st_namespace_rhcs
Definition: stonith-ng.h:83
crm_ipc_close
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:857
stonith_event_s::id
char * id
Definition: stonith-ng.h:113
PCMK_RESOURCE_CLASS_STONITH
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:52
mainloop_get_ipc_client
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:906
create_xml_node
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
pcmk__starts_with
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:452
api_log_open
#define api_log_open()
Definition: st_client.c:2250
st_namespace_any
@ st_namespace_any
Definition: stonith-ng.h:77
timeout
unsigned int timeout
Definition: pcmk_fence.c:32
STONITH_ATTR_ACTION_OP
#define STONITH_ATTR_ACTION_OP
Definition: internal.h:163
F_STONITH_STATE
#define F_STONITH_STATE
Definition: internal.h:138
get_xpath_object
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:213
stonith_api_operations_s::disconnect
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:159
F_STONITH_ORIGIN
#define F_STONITH_ORIGIN
Definition: internal.h:135
st_opt_report_only_success
@ st_opt_report_only_success
Definition: stonith-ng.h:57
STONITH_OP_LEVEL_DEL
#define STONITH_OP_LEVEL_DEL
Definition: internal.h:174
stonith__device_parameter_flags
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2659
pcmk_strerror
const char * pcmk_strerror(int rc)
Definition: results.c:58
crm_log_output
#define crm_log_output(level, prefix, output)
Definition: logging.h:112
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
stonith_api_operations_s::confirm
int(* confirm)(stonith_t *st, int options, const char *node)
Manually confirm that a node is down.
Definition: stonith-ng.h:287
stonith__lha_validate
int stonith__lha_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, int timeout, char **output, char **error_output)
Definition: st_lha.c:274
stonith_api_operations_s::list
int(* list)(stonith_t *st, int options, const char *id, char **list_output, int timeout)
Retrieve string listing hosts and port assignments from a local stonith device.
Definition: stonith-ng.h:233
st_done
@ st_done
Definition: stonith-ng.h:69
stonith_event_s::type
char * type
Definition: stonith-ng.h:114
PCMK_OCF_TIMEOUT
@ PCMK_OCF_TIMEOUT
Definition: results.h:175
stonith_api_operations_s::connect
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition: stonith-ng.h:151
crm_notice
#define crm_notice(fmt, args...)
Definition: logging.h:349
stonith_dump_pending_callbacks
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1708
stonith_op_t
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: st_client.c:107
SVC_ACTION_NON_BLOCKED
@ SVC_ACTION_NON_BLOCKED
Definition: services.h:118
crm_ipc_ready
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:939
type
enum crm_ais_msg_types type
Definition: internal.h:3
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:347
stonith__parse_targets
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2499
stonith_api_kick
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:2254
crm_ipc_send
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1139
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:353
stonith_event_s::message
char * message
Definition: stonith-ng.h:115
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:348
crm_ipc_flags
crm_ipc_flags
Definition: ipc.h:144
stonith__list_lha_agents
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:106
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:790
stonith_key_value_s
Definition: stonith-ng.h:92
stonith__event_state_pending
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2629
STONITH_ATTR_HOSTARG
#define STONITH_ATTR_HOSTARG
Definition: internal.h:155
action
const char * action
Definition: pcmk_fence.c:30
stonith_api_operations_s::remove_device
int(* remove_device)(stonith_t *st, int options, const char *name)
Remove a registered stonith device with the local stonith daemon.
Definition: stonith-ng.h:169
F_STONITH_HISTORY_LIST
#define F_STONITH_HISTORY_LIST
Definition: internal.h:136
stonith__lha_metadata
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:175
crm_ipc_buffer
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1046
crm_ipc_destroy
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:870
xpath_search
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:138
internal.h
stonith_key_value_s::value
char * value
Definition: stonith-ng.h:94
stonith_history_s::action
char * action
Definition: stonith-ng.h:100
create_level_registration_xml
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Definition: st_client.c:394
stonith_history_s::state
int state
Definition: stonith-ng.h:104
stonith_api_operations_s::register_level_full
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Register fencing level for specific node, node regex or attribute.
Definition: stonith-ng.h:367
svc_action_s::id
char * id
Definition: services.h:123
xml.h
Wrappers for and extensions to libxml2.
stonith_history_s::target
char * target
Definition: stonith-ng.h:99
svc_action_s::stderr_data
char * stderr_data
Definition: services.h:147
crm_ipc_flags_none
@ crm_ipc_flags_none
Definition: ipc.h:145
stonith_api_operations_s::history
int(* history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout)
Retrieve a list of fencing operations that have occurred for a specific node.
Definition: stonith-ng.h:295
crm_ipc_get_fd
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:893
stonith_api_operations_s::fence_with_delay
int(* fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance, int delay)
Issue a fencing action against a node with requested fencing delay.
Definition: stonith-ng.h:412
stonith_key_value_s::next
struct stonith_key_value_s * next
Definition: stonith-ng.h:95
pcmk__add_separated_word
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition: strings.c:617
stonith_api_operations_s::validate
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition: stonith-ng.h:390
svc_action_s::cb_data
void * cb_data
Definition: services.h:156
stonith_api_operations_s::remove_notification
int(* remove_notification)(stonith_t *st, const char *event)
Definition: stonith-ng.h:300
stonith_event_s
Definition: stonith-ng.h:112
mainloop.h
Wrappers for and extensions to glib mainloop.
XML_ATTR_STONITH_DEVICES
#define XML_ATTR_STONITH_DEVICES
Definition: msg_xml.h:409
add_message_xml
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:162
T_STONITH_TIMEOUT_VALUE
#define T_STONITH_TIMEOUT_VALUE
Definition: internal.h:152
pcmk__strcase_any_of
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:842
svc_action_s::params
GHashTable * params
Definition: services.h:133
pcmk__str_null_matches
@ pcmk__str_null_matches
Definition: strings_internal.h:27
CRM_OP_REGISTER
#define CRM_OP_REGISTER
Definition: crm.h:142
stonith_history_s::next
struct stonith_history_s * next
Definition: stonith-ng.h:106
XML_ATTR_ID
#define XML_ATTR_ID
Definition: msg_xml.h:96
st_opt_cs_nodeid
@ st_opt_cs_nodeid
Definition: stonith-ng.h:51
stonith_history_free
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:1164
ENOTUNIQ
#define ENOTUNIQ
Definition: portability.h:137
STONITH_OP_DEVICE_ADD
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:170
stonith_s::state
enum stonith_state state
Definition: stonith-ng.h:419
stonith_history_s::delegate
char * delegate
Definition: stonith-ng.h:102
stonith_api_operations_s::remove_level_full
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Remove fencing level for specific node, node regex or attribute.
Definition: stonith-ng.h:347
st_namespace_internal
@ st_namespace_internal
Definition: stonith-ng.h:78
CRM_META
#define CRM_META
Definition: crm.h:71
svc_action_s
Definition: services.h:122
stonith__event_state_neq
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2641
stonith_connected_command
@ stonith_connected_command
Definition: stonith-ng.h:36
st_opt_allow_suicide
@ st_opt_allow_suicide
Definition: stonith-ng.h:44
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:350
ECOMM
#define ECOMM
Definition: portability.h:141
F_STONITH_CALLDATA
#define F_STONITH_CALLDATA
Definition: internal.h:100
CRM_LOG_ASSERT
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:199
stonith_event_s::target
char * target
Definition: stonith-ng.h:120
stonith_key_value_add
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:2206
timer_rec_s
Definition: internal.h:94
svc_action_s::timeout
int timeout
Definition: services.h:132
timer_rec_s::stonith
stonith_t * stonith
Definition: st_client.c:104
CRM_XS
#define CRM_XS
Definition: logging.h:54
pcmk_rc_str
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:420
uname
char uname[MAX_NAME]
Definition: internal.h:5
id
uint32_t id
Definition: internal.h:0
stonith_action_str
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition: st_client.c:2391
ENODATA
#define ENODATA
Definition: portability.h:161
crm_ipc_connected
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:907
crm_ipc_new
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition: ipc_client.c:745
XML_ATTR_STONITH_TARGET_PATTERN
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition: msg_xml.h:407
stonith_history_s
Definition: stonith-ng.h:98
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
STONITH_OP_LEVEL_ADD
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:173
svc_action_s::stdout_data
char * stdout_data
Definition: services.h:148
stonith_api_operations_s::query
int(* query)(stonith_t *st, int options, const char *node, stonith_key_value_t **devices, int timeout)
Retrieve a list of registered stonith devices.
Definition: stonith-ng.h:260
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:352
stonith_history_s::completed
time_t completed
Definition: stonith-ng.h:105
XML_TAG_ATTRS
#define XML_TAG_ATTRS
Definition: msg_xml.h:172
STONITH_OP_FENCE_HISTORY
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:172
stonith__destroy_action
void stonith__destroy_action(stonith_action_t *action)
Definition: st_client.c:582
FAILURE_MAX_RETRIES
#define FAILURE_MAX_RETRIES
Definition: st_client.c:640
pid
uint32_t pid
Definition: internal.h:1
string2xml
xmlNode * string2xml(const char *input)
Definition: xml.c:835
F_STONITH_NOTIFY_DEACTIVATE
#define F_STONITH_NOTIFY_DEACTIVATE
Definition: internal.h:129
stonith__later_succeeded
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2539
stonith_api_time
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition: st_client.c:2296
ipc_client_callbacks
Definition: mainloop.h:73
F_STONITH_NOTIFY_ACTIVATE
#define F_STONITH_NOTIFY_ACTIVATE
Definition: internal.h:128
stonith_history_s::origin
char * origin
Definition: stonith-ng.h:101
svc_action_s::pid
int pid
Definition: services.h:139
F_STONITH_OPERATION
#define F_STONITH_OPERATION
Definition: internal.h:101
crm_log_xml_trace
#define crm_log_xml_trace(xml, text)
Definition: logging.h:361
crm_xml_add
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:317
services_action_async_fork_notify
gboolean services_action_async_fork_notify(svc_action_t *op, void(*action_callback)(svc_action_t *), void(*action_fork_callback)(svc_action_t *))
Definition: services.c:740
MAX_IPC_DELAY
#define MAX_IPC_DELAY
Definition: crm.h:78
st_opt_discard_reply
@ st_opt_discard_reply
Definition: stonith-ng.h:47
getXpathResult
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:57
XML_ATTR_STONITH_INDEX
#define XML_ATTR_STONITH_INDEX
Definition: msg_xml.h:404
stonith_callback_data_s
Definition: stonith-ng.h:132
stonith__list_rhcs_agents
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:31
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
crm_log_xml_warn
#define crm_log_xml_warn(xml, text)
Definition: logging.h:357
stonith_api_delete
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:2017
stonith_dispatch
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1959
stonith_api_operations_s
Definition: stonith-ng.h:139
stonith_key_value_freeall
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition: st_client.c:2233
services_action_sync
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:877
F_SUBTYPE
#define F_SUBTYPE
Definition: msg_xml.h:26
xml_internal.h
stonith_api_operations_s::free
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:143
stonith_event_s::operation
char * operation
Definition: stonith-ng.h:116
tolerance
unsigned int tolerance
Definition: pcmk_fence.c:33
crm_log_xml_debug
#define crm_log_xml_debug(xml, text)
Definition: logging.h:360
F_STONITH_TOLERANCE
#define F_STONITH_TOLERANCE
Definition: internal.h:108
RH_STONITH_DIR
#define RH_STONITH_DIR
Definition: config.h:547
stonith__agent_is_rhcs
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:231
T_STONITH_NOTIFY_FENCE
#define T_STONITH_NOTIFY_FENCE
Definition: stonith-ng.h:30
stonith_get_namespace
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition: st_client.c:177
F_STONITH_REMOTE_OP_ID
#define F_STONITH_REMOTE_OP_ID
Definition: internal.h:103
target
const char * target
Definition: pcmk_fence.c:29
timer_rec_s::call_id
int call_id
Definition: internal.h:95
T_STONITH_NOTIFY_DISCONNECT
#define T_STONITH_NOTIFY_DISCONNECT
Definition: stonith-ng.h:29
F_STONITH_DELAY
#define F_STONITH_DELAY
Definition: internal.h:109
stonith_action_create
stonith_action_t * stonith_action_create(const char *agent, const char *_action, const char *victim, uint32_t victim_nodeid, int timeout, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition: st_client.c:642
crm_perror
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:298
stonith__execute
int stonith__execute(stonith_action_t *action)
Definition: st_client.c:896
F_STONITH_CLIENTID
#define F_STONITH_CLIENTID
Definition: internal.h:97
stonith_create_op
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition: st_client.c:1210
stonith_s::cmds
stonith_api_operations_t * cmds
Definition: stonith-ng.h:425
XML_TAG_FENCING_LEVEL
#define XML_TAG_FENCING_LEVEL
Definition: msg_xml.h:403
STONITH_OP_QUERY
#define STONITH_OP_QUERY
Definition: internal.h:167
F_STONITH_DELEGATE
#define F_STONITH_DELEGATE
Definition: internal.h:130
stonith_event_s::action
char * action
Definition: stonith-ng.h:121
F_STONITH_CALLOPTS
#define F_STONITH_CALLOPTS
Definition: internal.h:98
st_namespace_lha
@ st_namespace_lha
Definition: stonith-ng.h:84
mainloop_io_t
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:32
mainloop_del_ipc_client
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:900
services_action_create_generic
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:311
st_namespace_invalid
@ st_namespace_invalid
Definition: stonith-ng.h:76
crm_log_xml_err
#define crm_log_xml_err(xml, text)
Definition: logging.h:356
stonith-ng.h
Fencing aka. STONITH.
F_STONITH_CLIENTNAME
#define F_STONITH_CLIENTNAME
Definition: internal.h:126
F_STONITH_TIMEOUT
#define F_STONITH_TIMEOUT
Definition: internal.h:107
crm_str
#define crm_str(x)
Definition: logging.h:373
F_STONITH_CALLID
#define F_STONITH_CALLID
Definition: internal.h:99
crm_xml_add_int
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:425
st_device_supports_parameter_port
@ st_device_supports_parameter_port
Definition: internal.h:25
F_TYPE
#define F_TYPE
Definition: msg_xml.h:30
log_action
void log_action(unsigned int log_level, const char *pre_text, pe_action_t *action, gboolean details)
Definition: pcmk_sched_utils.c:353
ETIME
#define ETIME
Definition: portability.h:165
stonith_api_operations_s::status
int(* status)(stonith_t *st, int options, const char *id, const char *port, int timeout)
Check to see if a local stonith device's port is reachable.
Definition: stonith-ng.h:249
stonith_key_value_s::key
char * key
Definition: stonith-ng.h:93
crm_log_xml_notice
#define crm_log_xml_notice(xml, text)
Definition: logging.h:358
stonith_api_operations_s::register_callback
int(* register_callback)(stonith_t *st, int call_id, int timeout, int options, void *userdata, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback to receive the result of an asynchronous call.
Definition: stonith-ng.h:319
stonith_event_s::device
char * device
Definition: stonith-ng.h:124
stonith__event_state_eq
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2635
stonith_notify_client_t
struct stonith_notify_client_s stonith_notify_client_t
stonith__rhcs_metadata
int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Execute RHCS-compatible agent's meta-data action.
Definition: st_rhcs.c:205
LOG_NEVER
#define LOG_NEVER
Definition: logging.h:46
stonith_s::call_timeout
int call_timeout
Definition: stonith-ng.h:422
crm_element_value_copy
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:726
st_device_supports_parameter_plug
@ st_device_supports_parameter_plug
Definition: internal.h:24
stonith_namespace2text
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition: st_client.c:156
G_PRIORITY_MEDIUM
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:153
stonith_event_s::origin
char * origin
Definition: stonith-ng.h:119
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
svc_action_s::sequence
int sequence
Definition: services.h:142
F_STONITH_CALLBACK_TOKEN
#define F_STONITH_CALLBACK_TOKEN
Definition: internal.h:125
pcmk_rc_ok
@ pcmk_rc_ok
Definition: results.h:142
F_STONITH_DATE
#define F_STONITH_DATE
Definition: internal.h:137
T_STONITH_NG
#define T_STONITH_NG
Definition: internal.h:147
pcmk__substitute_secrets
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
stonith_s::st_private
void * st_private
Definition: stonith-ng.h:423
CRM_TRACE_INIT_DATA
CRM_TRACE_INIT_DATA(stonith)
F_XML_TAGNAME
#define F_XML_TAGNAME
Definition: msg_xml.h:38
stonith_api_operations_s::register_device
int(* register_device)(stonith_t *st, int options, const char *id, const char *provider, const char *agent, stonith_key_value_t *params)
Register a stonith device with the local stonith daemon.
Definition: stonith-ng.h:180
STONITH_OP_EXEC
#define STONITH_OP_EXEC
Definition: internal.h:165
STONITH_OP_FENCE
#define STONITH_OP_FENCE
Definition: internal.h:168
XML_ATTR_STONITH_TARGET
#define XML_ATTR_STONITH_TARGET
Definition: msg_xml.h:405
api_log
#define api_log(level, fmt, args...)
Definition: st_client.c:2251
stonith_history_s::client
char * client
Definition: stonith-ng.h:103
ipc_client_callbacks::dispatch
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:74
stonith_api_connect_retry
int stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
Make a blocking connection attempt to the fencer.
Definition: st_client.c:2185
timer_rec_s::ref
guint ref
Definition: internal.h:97
stonith_api_operations_s::fence
int(* fence)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance)
Issue a fencing action against a node.
Definition: stonith-ng.h:278
F_STONITH_ACTION
#define F_STONITH_ACTION
Definition: internal.h:143
stonith__agent_is_lha
bool stonith__agent_is_lha(const char *agent)
Determine namespace of a fence agent.
Definition: st_lha.c:79
stonith_api_new
stonith_t * stonith_api_new(void)
Definition: st_client.c:2106
XML_ATTR_STONITH_TARGET_VALUE
#define XML_ATTR_STONITH_TARGET_VALUE
Definition: msg_xml.h:406
stonith__set_device_flags
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:28
pcmk__str_none
@ pcmk__str_none
Definition: strings_internal.h:25
pcmk__set_ipc_flags
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:176
get_stonith_provider
const char * get_stonith_provider(const char *agent, const char *provider)
Deprecated (use stonith_get_namespace() instead)
Definition: st_client.c:2653
svc_action_s::agent
char * agent
Definition: services.h:130
st_opt_sync_call
@ st_opt_sync_call
Definition: stonith-ng.h:52
stonith_s::call_id
int call_id
Definition: stonith-ng.h:421
hash2field
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:785
crm_ipc_client_response
@ crm_ipc_client_response
Definition: ipc.h:150
svc_action_s::rc
int rc
Definition: services.h:138
strndup
char * strndup(const char *str, size_t len)
crm_ipc_t
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:162
stonith_api_operations_s::list_agents
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition: stonith-ng.h:224
stonith_private_t
struct stonith_private_s stonith_private_t
F_STONITH_TARGET
#define F_STONITH_TARGET
Definition: internal.h:102
stonith__first_matching_event
stonith_history_t * stonith__first_matching_event(stonith_history_t *history, bool(*matching_fn)(stonith_history_t *, void *), void *user_data)
Definition: st_client.c:2615
stonith__action_result
void stonith__action_result(stonith_action_t *action, int *rc, char **output, char **error_output)
Definition: st_client.c:613
mainloop_add_ipc_client
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition: mainloop.c:880
stonith_callback_client_t
struct stonith_callback_client_s stonith_callback_client_t
stonith_api_operations_s::monitor
int(* monitor)(stonith_t *st, int options, const char *id, int timeout)
Check to see if a local stonith device is reachable.
Definition: stonith-ng.h:241
svc_action_s::standard
char * standard
Definition: services.h:128
stonith_api_operations_s::remove_callback
int(* remove_callback)(stonith_t *st, int call_id, bool all_callbacks)
Remove a registered callback for a given call id.
Definition: stonith-ng.h:330
crm_internal.h
name
char * name
Definition: pcmk_fence.c:31
stonith_action_t
struct stonith_action_s stonith_action_t
Definition: internal.h:50
st_opt_timeout_updates
@ st_opt_timeout_updates
Definition: stonith-ng.h:55
stonith_api_operations_s::register_level
int(* register_level)(stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list)
Register a fencing level containing the fencing devices to be used at that level for a specific node.
Definition: stonith-ng.h:200
F_STONITH_DEVICE
#define F_STONITH_DEVICE
Definition: internal.h:142
freeXpathObject
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:38
XML_ATTR_STONITH_TARGET_ATTRIBUTE
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition: msg_xml.h:408
crm.h
A dumping ground.
stonith_s
Definition: stonith-ng.h:418
stonith_action_execute_async
int stonith_action_execute_async(stonith_action_t *action, void *userdata, void(*done)(GPid pid, int rc, const char *output, gpointer user_data), void(*fork_cb)(GPid pid, gpointer user_data))
Definition: st_client.c:869
pcmk_ok
#define pcmk_ok
Definition: results.h:67
timer_rec_s::timeout
int timeout
Definition: internal.h:96
stonith_event_s::client_origin
char * client_origin
Definition: stonith-ng.h:127
delay
int delay
Definition: pcmk_fence.c:34
stonith__set_call_options
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition: internal.h:35
stonith_namespace
stonith_namespace
Definition: stonith-ng.h:75
crm_ipc_read
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1003