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