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