Blame SOURCES/003-fence-output.patch

c54a00
From 06ef8406cf224af6b94dc4672c9b6caa15133f89 Mon Sep 17 00:00:00 2001
c54a00
From: Klaus Wenninger <klaus.wenninger@aon.at>
c54a00
Date: Thu, 14 Feb 2019 13:27:46 +0100
c54a00
Subject: [PATCH] use common service interface for fence-agents and RAs
c54a00
c54a00
---
c54a00
 include/crm/services.h          |   5 +-
c54a00
 lib/Makefile.am                 |   3 +-
c54a00
 lib/fencing/Makefile.am         |   1 +
c54a00
 lib/fencing/st_client.c         | 459 +++++++++-------------------------------
c54a00
 lib/services/services_linux.c   |  93 ++++++++
c54a00
 lib/services/services_private.h |   2 +
c54a00
 6 files changed, 203 insertions(+), 360 deletions(-)
c54a00
c54a00
diff --git a/include/crm/services.h b/include/crm/services.h
c54a00
index 0186e66..eddafc3 100644
c54a00
--- a/include/crm/services.h
c54a00
+++ b/include/crm/services.h
c54a00
@@ -170,7 +170,10 @@ typedef struct svc_action_s {
c54a00
     char *agent;
c54a00
 
c54a00
     int timeout;
c54a00
-    GHashTable *params; /* used by OCF agents and alert agents */
c54a00
+    GHashTable *params; /* used for setting up environment for ocf-ra &
c54a00
+                           alert agents
c54a00
+                           and to be sent via stdin for fence-agents
c54a00
+                         */
c54a00
 
c54a00
     int rc;
c54a00
     int pid;
c54a00
diff --git a/lib/Makefile.am b/lib/Makefile.am
c54a00
index 5563819..d73bf2e 100644
c54a00
--- a/lib/Makefile.am
c54a00
+++ b/lib/Makefile.am
c54a00
@@ -39,11 +39,10 @@ clean-local:
c54a00
 	rm -f *.pc
c54a00
 
c54a00
 ## Subdirectories...
c54a00
-SUBDIRS	= gnu common pengine transition cib fencing services lrmd cluster
c54a00
+SUBDIRS	= gnu common pengine transition cib services fencing lrmd cluster
c54a00
 DIST_SUBDIRS =  $(SUBDIRS) ais
c54a00
 
c54a00
 if BUILD_CS_PLUGIN
c54a00
 SUBDIRS			+= ais
c54a00
 endif
c54a00
 
c54a00
-
c54a00
diff --git a/lib/fencing/Makefile.am b/lib/fencing/Makefile.am
c54a00
index c3f4ea2..e447627 100644
c54a00
--- a/lib/fencing/Makefile.am
c54a00
+++ b/lib/fencing/Makefile.am
c54a00
@@ -15,6 +15,7 @@ libstonithd_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
c54a00
 libstonithd_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
c54a00
 
c54a00
 libstonithd_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la
c54a00
+libstonithd_la_LIBADD   += $(top_builddir)/lib/services/libcrmservice.la
c54a00
 
c54a00
 libstonithd_la_SOURCES	= st_client.c st_rhcs.c
c54a00
 if BUILD_LHA_SUPPORT
c54a00
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
c54a00
index 3898d45..1c56cf4 100644
c54a00
--- a/lib/fencing/st_client.c
c54a00
+++ b/lib/fencing/st_client.c
c54a00
@@ -22,6 +22,7 @@
c54a00
 #include <stdio.h>
c54a00
 #include <string.h>
c54a00
 #include <ctype.h>
c54a00
+#include <libgen.h>
c54a00
 
c54a00
 #include <sys/stat.h>
c54a00
 #include <sys/types.h>
c54a00
@@ -48,23 +49,18 @@ struct stonith_action_s {
c54a00
     char *agent;
c54a00
     char *action;
c54a00
     char *victim;
c54a00
-    char *args;
c54a00
+    GHashTable *args;
c54a00
     int timeout;
c54a00
     int async;
c54a00
     void *userdata;
c54a00
     void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data);
c54a00
 
c54a00
-    /*! internal async track data */
c54a00
-    int fd_stdout;
c54a00
-    int fd_stderr;
c54a00
-    int last_timeout_signo;
c54a00
+    svc_action_t *svc_action;
c54a00
 
c54a00
     /*! internal timing information */
c54a00
     time_t initial_start_time;
c54a00
     int tries;
c54a00
     int remaining_timeout;
c54a00
-    guint timer_sigterm;
c54a00
-    guint timer_sigkill;
c54a00
     int max_retries;
c54a00
 
c54a00
     /* device output data */
c54a00
@@ -448,13 +444,11 @@ stonith_api_register_level(stonith_t * st, int options, const char *node, int le
c54a00
 }
c54a00
 
c54a00
 static void
c54a00
-append_arg(const char *key, const char *value, char **args)
c54a00
+append_arg(const char *key, const char *value, GHashTable **args)
c54a00
 {
c54a00
-    int len = 3;                /* =, \n, \0 */
c54a00
-    int last = 0;
c54a00
-
c54a00
     CRM_CHECK(key != NULL, return);
c54a00
     CRM_CHECK(value != NULL, return);
c54a00
+    CRM_CHECK(args != NULL, return);
c54a00
 
c54a00
     if (strstr(key, "pcmk_")) {
c54a00
         return;
c54a00
@@ -464,15 +458,13 @@ append_arg(const char *key, const char *value, char **args)
c54a00
         return;
c54a00
     }
c54a00
 
c54a00
-    len += strlen(key);
c54a00
-    len += strlen(value);
c54a00
-    if (*args != NULL) {
c54a00
-        last = strlen(*args);
c54a00
+    if (!*args) {
c54a00
+        *args = crm_str_table_new();
c54a00
     }
c54a00
 
c54a00
-    *args = realloc_safe(*args, last + len);
c54a00
+    CRM_CHECK(*args != NULL, return);
c54a00
     crm_trace("Appending: %s=%s", key, value);
c54a00
-    sprintf((*args) + last, "%s=%s\n", key, value);
c54a00
+    g_hash_table_replace(*args, strdup(key), strdup(value));
c54a00
 }
c54a00
 
c54a00
 static void
c54a00
@@ -489,7 +481,7 @@ append_config_arg(gpointer key, gpointer value, gpointer user_data)
c54a00
 }
c54a00
 
c54a00
 static void
c54a00
-append_host_specific_args(const char *victim, const char *map, GHashTable * params, char **arg_list)
c54a00
+append_host_specific_args(const char *victim, const char *map, GHashTable * params, GHashTable **args)
c54a00
 {
c54a00
     char *name = NULL;
c54a00
     int last = 0, lpc = 0, max = 0;
c54a00
@@ -497,7 +489,7 @@ append_host_specific_args(const char *victim, const char *map, GHashTable * para
c54a00
     if (map == NULL) {
c54a00
         /* The best default there is for now... */
c54a00
         crm_debug("Using default arg map: port=uname");
c54a00
-        append_arg("port", victim, arg_list);
c54a00
+        append_arg("port", victim, args);
c54a00
         return;
c54a00
     }
c54a00
 
c54a00
@@ -540,7 +532,7 @@ append_host_specific_args(const char *victim, const char *map, GHashTable * para
c54a00
 
c54a00
             if (value) {
c54a00
                 crm_debug("Setting '%s'='%s' (%s) for %s", name, value, param, victim);
c54a00
-                append_arg(name, value, arg_list);
c54a00
+                append_arg(name, value, args);
c54a00
 
c54a00
             } else {
c54a00
                 crm_err("No node attribute '%s' for '%s'", name, victim);
c54a00
@@ -560,12 +552,12 @@ append_host_specific_args(const char *victim, const char *map, GHashTable * para
c54a00
     free(name);
c54a00
 }
c54a00
 
c54a00
-static char *
c54a00
+static GHashTable *
c54a00
 make_args(const char *agent, const char *action, const char *victim, uint32_t victim_nodeid, GHashTable * device_args,
c54a00
           GHashTable * port_map)
c54a00
 {
c54a00
     char buffer[512];
c54a00
-    char *arg_list = NULL;
c54a00
+    GHashTable *arg_list = NULL;
c54a00
     const char *value = NULL;
c54a00
 
c54a00
     CRM_CHECK(action != NULL, return NULL);
c54a00
@@ -653,66 +645,6 @@ make_args(const char *agent, const char *action, const char *victim, uint32_t vi
c54a00
     return arg_list;
c54a00
 }
c54a00
 
c54a00
-static gboolean
c54a00
-st_child_term(gpointer data)
c54a00
-{
c54a00
-    int rc = 0;
c54a00
-    stonith_action_t *track = data;
c54a00
-
c54a00
-    crm_info("Child %d timed out, sending SIGTERM", track->pid);
c54a00
-    track->timer_sigterm = 0;
c54a00
-    track->last_timeout_signo = SIGTERM;
c54a00
-    rc = kill(-track->pid, SIGTERM);
c54a00
-    if (rc < 0) {
c54a00
-        crm_perror(LOG_ERR, "Couldn't send SIGTERM to %d", track->pid);
c54a00
-    }
c54a00
-    return FALSE;
c54a00
-}
c54a00
-
c54a00
-static gboolean
c54a00
-st_child_kill(gpointer data)
c54a00
-{
c54a00
-    int rc = 0;
c54a00
-    stonith_action_t *track = data;
c54a00
-
c54a00
-    crm_info("Child %d timed out, sending SIGKILL", track->pid);
c54a00
-    track->timer_sigkill = 0;
c54a00
-    track->last_timeout_signo = SIGKILL;
c54a00
-    rc = kill(-track->pid, SIGKILL);
c54a00
-    if (rc < 0) {
c54a00
-        crm_perror(LOG_ERR, "Couldn't send SIGKILL to %d", track->pid);
c54a00
-    }
c54a00
-    return FALSE;
c54a00
-}
c54a00
-
c54a00
-static void
c54a00
-stonith_action_clear_tracking_data(stonith_action_t * action)
c54a00
-{
c54a00
-    if (action->timer_sigterm > 0) {
c54a00
-        g_source_remove(action->timer_sigterm);
c54a00
-        action->timer_sigterm = 0;
c54a00
-    }
c54a00
-    if (action->timer_sigkill > 0) {
c54a00
-        g_source_remove(action->timer_sigkill);
c54a00
-        action->timer_sigkill = 0;
c54a00
-    }
c54a00
-    if (action->fd_stdout) {
c54a00
-        close(action->fd_stdout);
c54a00
-        action->fd_stdout = 0;
c54a00
-    }
c54a00
-    if (action->fd_stderr) {
c54a00
-        close(action->fd_stderr);
c54a00
-        action->fd_stderr = 0;
c54a00
-    }
c54a00
-    free(action->output);
c54a00
-    action->output = NULL;
c54a00
-    free(action->error);
c54a00
-    action->error = NULL;
c54a00
-    action->rc = 0;
c54a00
-    action->pid = 0;
c54a00
-    action->last_timeout_signo = 0;
c54a00
-}
c54a00
-
c54a00
 /*!
c54a00
  * \internal
c54a00
  * \brief Free all memory used by a stonith action
c54a00
@@ -723,11 +655,17 @@ void
c54a00
 stonith__destroy_action(stonith_action_t *action)
c54a00
 {
c54a00
     if (action) {
c54a00
-        stonith_action_clear_tracking_data(action);
c54a00
         free(action->agent);
c54a00
-        free(action->args);
c54a00
+        if (action->args) {
c54a00
+            g_hash_table_destroy(action->args);
c54a00
+        }
c54a00
         free(action->action);
c54a00
         free(action->victim);
c54a00
+        if (action->svc_action) {
c54a00
+            services_action_free(action->svc_action);
c54a00
+        }
c54a00
+        free(action->output);
c54a00
+        free(action->error);
c54a00
         free(action);
c54a00
     }
c54a00
 }
c54a00
@@ -809,38 +747,6 @@ stonith_action_create(const char *agent,
c54a00
     return action;
c54a00
 }
c54a00
 
c54a00
-#define READ_MAX 500
c54a00
-static char *
c54a00
-read_output(int fd)
c54a00
-{
c54a00
-    char buffer[READ_MAX];
c54a00
-    char *output = NULL;
c54a00
-    int len = 0;
c54a00
-    int more = 0;
c54a00
-
c54a00
-    if (!fd) {
c54a00
-        return NULL;
c54a00
-    }
c54a00
-
c54a00
-    do {
c54a00
-        errno = 0;
c54a00
-        memset(&buffer, 0, READ_MAX);
c54a00
-        more = read(fd, buffer, READ_MAX - 1);
c54a00
-
c54a00
-        if (more > 0) {
c54a00
-            buffer[more] = 0; /* Make sure it's nul-terminated for logging
c54a00
-                              * 'more' is always less than our buffer size
c54a00
-                              */
c54a00
-            output = realloc_safe(output, len + more + 1);
c54a00
-            snprintf(output + len, more + 1, "%s", buffer);
c54a00
-            len += more;
c54a00
-        }
c54a00
-
c54a00
-    } while (more == (READ_MAX - 1) || (more < 0 && errno == EINTR));
c54a00
-
c54a00
-    return output;
c54a00
-}
c54a00
-
c54a00
 static gboolean
c54a00
 update_remaining_timeout(stonith_action_t * action)
c54a00
 {
c54a00
@@ -860,58 +766,51 @@ update_remaining_timeout(stonith_action_t * action)
c54a00
     return action->remaining_timeout ? TRUE : FALSE;
c54a00
 }
c54a00
 
c54a00
-static void
c54a00
-stonith_action_async_done(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
c54a00
-{
c54a00
-    stonith_action_t *action = mainloop_child_userdata(p);
c54a00
-
c54a00
-    if (action->timer_sigterm > 0) {
c54a00
-        g_source_remove(action->timer_sigterm);
c54a00
-        action->timer_sigterm = 0;
c54a00
-    }
c54a00
-    if (action->timer_sigkill > 0) {
c54a00
-        g_source_remove(action->timer_sigkill);
c54a00
-        action->timer_sigkill = 0;
c54a00
-    }
c54a00
+static int
c54a00
+svc_action_to_errno(svc_action_t *svc_action) {
c54a00
+    int rv = pcmk_ok;
c54a00
 
c54a00
-    action->output = read_output(action->fd_stdout);
c54a00
-    action->error = read_output(action->fd_stderr);
c54a00
+    if (svc_action->rc > 0) {
c54a00
+        /* Try to provide a useful error code based on the fence agent's
c54a00
+            * error output.
c54a00
+            */
c54a00
+        if (svc_action->rc == PCMK_OCF_TIMEOUT) {
c54a00
+            rv = -ETIME;
c54a00
 
c54a00
-    if (action->last_timeout_signo) {
c54a00
-        action->rc = -ETIME;
c54a00
-        crm_notice("Child process %d performing action '%s' timed out with signal %d",
c54a00
-                   pid, action->action, action->last_timeout_signo);
c54a00
+        } else if (svc_action->stderr_data == NULL) {
c54a00
+            rv = -ENODATA;
c54a00
 
c54a00
-    } else if (signo) {
c54a00
-        action->rc = -ECONNABORTED;
c54a00
-        crm_notice("Child process %d performing action '%s' timed out with signal %d",
c54a00
-                   pid, action->action, signo);
c54a00
+        } else if (strstr(svc_action->stderr_data, "imed out")) {
c54a00
+            /* Some agents have their own internal timeouts */
c54a00
+            rv = -ETIME;
c54a00
 
c54a00
-    } else {
c54a00
-        crm_debug("Child process %d performing action '%s' exited with rc %d",
c54a00
-                  pid, action->action, exitcode);
c54a00
-        if (exitcode > 0) {
c54a00
-            /* Try to provide a useful error code based on the fence agent's
c54a00
-             * error output.
c54a00
-             */
c54a00
-            if (action->error == NULL) {
c54a00
-                exitcode = -ENODATA;
c54a00
-
c54a00
-            } else if (strstr(action->error, "imed out")) {
c54a00
-                /* Some agents have their own internal timeouts */
c54a00
-                exitcode = -ETIMEDOUT;
c54a00
-
c54a00
-            } else if (strstr(action->error, "Unrecognised action")) {
c54a00
-                exitcode = -EOPNOTSUPP;
c54a00
+        } else if (strstr(svc_action->stderr_data, "Unrecognised action")) {
c54a00
+            rv = -EOPNOTSUPP;
c54a00
 
c54a00
-            } else {
c54a00
-                exitcode = -pcmk_err_generic;
c54a00
-            }
c54a00
+        } else {
c54a00
+            rv = -pcmk_err_generic;
c54a00
         }
c54a00
-        action->rc = exitcode;
c54a00
     }
c54a00
+    return rv;
c54a00
+}
c54a00
 
c54a00
-    log_action(action, pid);
c54a00
+static void
c54a00
+stonith_action_async_done(svc_action_t *svc_action)
c54a00
+{
c54a00
+    stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
c54a00
+
c54a00
+    action->rc = svc_action_to_errno(svc_action);
c54a00
+    action->output = svc_action->stdout_data;
c54a00
+    svc_action->stdout_data = NULL;
c54a00
+    action->error = svc_action->stderr_data;
c54a00
+    svc_action->stderr_data = NULL;
c54a00
+
c54a00
+    svc_action->params = NULL;
c54a00
+
c54a00
+    crm_debug("Child process %d performing action '%s' exited with rc %d",
c54a00
+                action->pid, action->action, svc_action->rc);
c54a00
+
c54a00
+    log_action(action, action->pid);
c54a00
 
c54a00
     if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
c54a00
         int rc = internal_stonith_action_execute(action);
c54a00
@@ -921,28 +820,21 @@ stonith_action_async_done(mainloop_child_t * p, pid_t pid, int core, int signo,
c54a00
     }
c54a00
 
c54a00
     if (action->done_cb) {
c54a00
-        action->done_cb(pid, action->rc, action->output, action->userdata);
c54a00
+        action->done_cb(action->pid, action->rc, action->output, action->userdata);
c54a00
     }
c54a00
 
c54a00
+    action->svc_action = NULL; // don't remove our caller
c54a00
     stonith__destroy_action(action);
c54a00
 }
c54a00
 
c54a00
 static int
c54a00
 internal_stonith_action_execute(stonith_action_t * action)
c54a00
 {
c54a00
-    int pid, status = 0, len, rc = -EPROTO;
c54a00
-    int ret;
c54a00
-    int total = 0;
c54a00
-    int p_read_fd, p_write_fd;  /* parent read/write file descriptors */
c54a00
-    int c_read_fd, c_write_fd;  /* child read/write file descriptors */
c54a00
-    int c_stderr_fd, p_stderr_fd; /* parent/child side file descriptors for stderr */
c54a00
-    int fd1[2];
c54a00
-    int fd2[2];
c54a00
-    int fd3[2];
c54a00
+    int rc = -EPROTO;
c54a00
     int is_retry = 0;
c54a00
-
c54a00
-    /* clear any previous tracking data */
c54a00
-    stonith_action_clear_tracking_data(action);
c54a00
+    svc_action_t *svc_action = NULL;
c54a00
+    static int stonith_sequence = 0;
c54a00
+    char *buffer = NULL;
c54a00
 
c54a00
     if (!action->tries) {
c54a00
         action->initial_start_time = time(NULL);
c54a00
@@ -955,207 +847,60 @@ internal_stonith_action_execute(stonith_action_t * action)
c54a00
         is_retry = 1;
c54a00
     }
c54a00
 
c54a00
-    c_read_fd = c_write_fd = p_read_fd = p_write_fd = c_stderr_fd = p_stderr_fd = -1;
c54a00
-
c54a00
     if (action->args == NULL || action->agent == NULL)
c54a00
         goto fail;
c54a00
-    len = strlen(action->args);
c54a00
-
c54a00
-    if (pipe(fd1))
c54a00
-        goto fail;
c54a00
-    p_read_fd = fd1[0];
c54a00
-    c_write_fd = fd1[1];
c54a00
-
c54a00
-    if (pipe(fd2))
c54a00
-        goto fail;
c54a00
-    c_read_fd = fd2[0];
c54a00
-    p_write_fd = fd2[1];
c54a00
-
c54a00
-    if (pipe(fd3))
c54a00
-        goto fail;
c54a00
-    p_stderr_fd = fd3[0];
c54a00
-    c_stderr_fd = fd3[1];
c54a00
-
c54a00
-    crm_debug("forking");
c54a00
-    pid = fork();
c54a00
-    if (pid < 0) {
c54a00
-        rc = -ECHILD;
c54a00
-        goto fail;
c54a00
-    }
c54a00
-
c54a00
-    if (!pid) {
c54a00
-        /* child */
c54a00
-        setpgid(0, 0);
c54a00
-
c54a00
-        close(1);
c54a00
-        /* coverity[leaked_handle] False positive */
c54a00
-        if (dup(c_write_fd) < 0)
c54a00
-            goto fail;
c54a00
-        close(2);
c54a00
-        /* coverity[leaked_handle] False positive */
c54a00
-        if (dup(c_stderr_fd) < 0)
c54a00
-            goto fail;
c54a00
-        close(0);
c54a00
-        /* coverity[leaked_handle] False positive */
c54a00
-        if (dup(c_read_fd) < 0)
c54a00
-            goto fail;
c54a00
-
c54a00
-        /* keep c_stderr_fd open so parent can report all errors. */
c54a00
-        /* keep c_write_fd open so hostlist can be sent to parent. */
c54a00
-        close(c_read_fd);
c54a00
-        close(p_read_fd);
c54a00
-        close(p_write_fd);
c54a00
-        close(p_stderr_fd);
c54a00
-
c54a00
-        /* keep retries from executing out of control */
c54a00
-        if (is_retry) {
c54a00
-            sleep(1);
c54a00
-        }
c54a00
-        execlp(action->agent, action->agent, NULL);
c54a00
-        exit(EXIT_FAILURE);
c54a00
-    }
c54a00
 
c54a00
-    /* parent */
c54a00
-    action->pid = pid;
c54a00
-    ret = crm_set_nonblocking(p_read_fd);
c54a00
-    if (ret < 0) {
c54a00
-        crm_notice("Could not set output of %s to be non-blocking: %s "
c54a00
-                   CRM_XS " rc=%d",
c54a00
-                   action->agent, pcmk_strerror(rc), rc);
c54a00
+    buffer = crm_strdup_printf(RH_STONITH_DIR "/%s", basename(action->agent));
c54a00
+    svc_action = services_action_create_generic(buffer, NULL);
c54a00
+    free(buffer);
c54a00
+    svc_action->timeout = 1000 * action->remaining_timeout;
c54a00
+    svc_action->standard = strdup(PCMK_RESOURCE_CLASS_STONITH);
c54a00
+    svc_action->id = crm_strdup_printf("%s_%s_%d", basename(action->agent),
c54a00
+                                       action->action, action->tries);
c54a00
+    svc_action->agent = strdup(action->agent);
c54a00
+    svc_action->sequence = stonith_sequence++;
c54a00
+    svc_action->params = action->args;
c54a00
+    svc_action->cb_data = (void *) action;
c54a00
+
c54a00
+    /* keep retries from executing out of control and free previous results */
c54a00
+    if (is_retry) {
c54a00
+        free(action->output);
c54a00
+        action->output = NULL;
c54a00
+        free(action->error);
c54a00
+        action->error = NULL;
c54a00
+        sleep(1);
c54a00
     }
c54a00
-    ret = crm_set_nonblocking(p_stderr_fd);
c54a00
-    if (ret < 0) {
c54a00
-        crm_notice("Could not set error output of %s to be non-blocking: %s "
c54a00
-                   CRM_XS " rc=%d",
c54a00
-                   action->agent, pcmk_strerror(rc), rc);
c54a00
-    }
c54a00
-
c54a00
-    errno = 0;
c54a00
-    do {
c54a00
-        crm_debug("sending args");
c54a00
-        ret = write(p_write_fd, action->args + total, len - total);
c54a00
-        if (ret > 0) {
c54a00
-            total += ret;
c54a00
-        }
c54a00
-
c54a00
-    } while (errno == EINTR && total < len);
c54a00
-
c54a00
-    if (total != len) {
c54a00
-        crm_perror(LOG_ERR, "Sent %d not %d bytes", total, len);
c54a00
-        if (ret >= 0) {
c54a00
-            rc = -ECOMM;
c54a00
-        }
c54a00
-        goto fail;
c54a00
-    }
c54a00
-
c54a00
-    close(p_write_fd); p_write_fd = -1;
c54a00
 
c54a00
-    /* async */
c54a00
     if (action->async) {
c54a00
-        action->fd_stdout = p_read_fd;
c54a00
-        action->fd_stderr = p_stderr_fd;
c54a00
-        mainloop_child_add(pid, 0/* Move the timeout here? */, action->action, action, stonith_action_async_done);
c54a00
-        crm_trace("Op: %s on %s, pid: %d, timeout: %ds", action->action, action->agent, pid,
c54a00
-                  action->remaining_timeout);
c54a00
-        action->last_timeout_signo = 0;
c54a00
-        if (action->remaining_timeout) {
c54a00
-            action->timer_sigterm =
c54a00
-                g_timeout_add(1000 * action->remaining_timeout, st_child_term, action);
c54a00
-            action->timer_sigkill =
c54a00
-                g_timeout_add(1000 * (action->remaining_timeout + 5), st_child_kill, action);
c54a00
+        /* async */
c54a00
+        if(services_action_async(svc_action, &stonith_action_async_done) == FALSE) {
c54a00
+            services_action_free(svc_action);
c54a00
+            svc_action = NULL;
c54a00
         } else {
c54a00
-            crm_err("No timeout set for stonith operation %s with device %s",
c54a00
-                    action->action, action->agent);
c54a00
+            action->pid = svc_action->pid;
c54a00
+            action->svc_action = svc_action;
c54a00
+            rc = 0;
c54a00
         }
c54a00
 
c54a00
-        close(c_write_fd);
c54a00
-        close(c_read_fd);
c54a00
-        close(c_stderr_fd);
c54a00
-        return 0;
c54a00
-
c54a00
     } else {
c54a00
         /* sync */
c54a00
-        int timeout = action->remaining_timeout + 1;
c54a00
-        pid_t p = 0;
c54a00
-
c54a00
-        while (action->remaining_timeout < 0 || timeout > 0) {
c54a00
-            p = waitpid(pid, &status, WNOHANG);
c54a00
-            if (p > 0) {
c54a00
-                break;
c54a00
-            }
c54a00
-            sleep(1);
c54a00
-            timeout--;
c54a00
-        }
c54a00
-
c54a00
-        if (timeout == 0) {
c54a00
-            int killrc = kill(-pid, SIGKILL);
c54a00
-
c54a00
-            if (killrc && errno != ESRCH) {
c54a00
-                crm_err("kill(%d, KILL) failed: %s (%d)", pid, pcmk_strerror(errno), errno);
c54a00
-            }
c54a00
-            /*
c54a00
-             * From sigprocmask(2):
c54a00
-             * It is not possible to block SIGKILL or SIGSTOP.  Attempts to do so are silently ignored.
c54a00
-             *
c54a00
-             * This makes it safe to skip WNOHANG here
c54a00
-             */
c54a00
-            p = waitpid(pid, &status, 0);
c54a00
-        }
c54a00
-
c54a00
-        if (p <= 0) {
c54a00
-            crm_perror(LOG_ERR, "waitpid(%d)", pid);
c54a00
-
c54a00
-        } else if (p != pid) {
c54a00
-            crm_err("Waited for %d, got %d", pid, p);
c54a00
-        }
c54a00
-
c54a00
-        action->output = read_output(p_read_fd);
c54a00
-        action->error = read_output(p_stderr_fd);
c54a00
-
c54a00
-        action->rc = -ECONNABORTED;
c54a00
-
c54a00
-        log_action(action, pid);
c54a00
-
c54a00
-        rc = action->rc;
c54a00
-        if (timeout == 0) {
c54a00
-            action->rc = -ETIME;
c54a00
-        } else if (WIFEXITED(status)) {
c54a00
-            crm_debug("result = %d", WEXITSTATUS(status));
c54a00
-            action->rc = -WEXITSTATUS(status);
c54a00
+        if (services_action_sync(svc_action)) {
c54a00
             rc = 0;
c54a00
-
c54a00
-        } else if (WIFSIGNALED(status)) {
c54a00
-            crm_err("call %s for %s exited due to signal %d", action->action, action->agent,
c54a00
-                    WTERMSIG(status));
c54a00
-
c54a00
+            action->rc = svc_action_to_errno(svc_action);
c54a00
+            action->output = svc_action->stdout_data;
c54a00
+            svc_action->stdout_data = NULL;
c54a00
+            action->error = svc_action->stderr_data;
c54a00
+            svc_action->stderr_data = NULL;
c54a00
         } else {
c54a00
-            crm_err("call %s for %s returned unexpected status %#x",
c54a00
-                    action->action, action->agent, status);
c54a00
+            action->rc = -ECONNABORTED;
c54a00
+            rc = action->rc;
c54a00
         }
c54a00
-    }
c54a00
 
c54a00
-  fail:
c54a00
-
c54a00
-    if (p_read_fd >= 0) {
c54a00
-        close(p_read_fd);
c54a00
-    }
c54a00
-    if (p_write_fd >= 0) {
c54a00
-        close(p_write_fd);
c54a00
-    }
c54a00
-    if (p_stderr_fd >= 0) {
c54a00
-        close(p_stderr_fd);
c54a00
-    }
c54a00
-
c54a00
-    if (c_read_fd >= 0) {
c54a00
-        close(c_read_fd);
c54a00
-    }
c54a00
-    if (c_write_fd >= 0) {
c54a00
-        close(c_write_fd);
c54a00
-    }
c54a00
-    if (c_stderr_fd >= 0) {
c54a00
-        close(c_stderr_fd);
c54a00
+        svc_action->params = NULL;
c54a00
+        services_action_free(svc_action);
c54a00
     }
c54a00
 
c54a00
+  fail:
c54a00
     return rc;
c54a00
 }
c54a00
 
c54a00
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
c54a00
index a413484..d79c16d 100644
c54a00
--- a/lib/services/services_linux.c
c54a00
+++ b/lib/services/services_linux.c
c54a00
@@ -195,6 +195,39 @@ add_action_env_vars(const svc_action_t *op)
c54a00
     }
c54a00
 }
c54a00
 
c54a00
+static void
c54a00
+pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
c54a00
+{
c54a00
+    svc_action_t *op = user_data;
c54a00
+    char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value);
c54a00
+    int ret, total = 0, len = strlen(buffer);
c54a00
+
c54a00
+    do {
c54a00
+        errno = 0;
c54a00
+        ret = write(op->opaque->stdin_fd, buffer + total, len - total);
c54a00
+        if (ret > 0) {
c54a00
+            total += ret;
c54a00
+        }
c54a00
+
c54a00
+    } while ((errno == EINTR) && (total < len));
c54a00
+    free(buffer);
c54a00
+}
c54a00
+
c54a00
+/*!
c54a00
+ * \internal
c54a00
+ * \brief Pipe parameters in via stdin for action
c54a00
+ *
c54a00
+ * \param[in] op  Action to use
c54a00
+ */
c54a00
+static void
c54a00
+pipe_in_action_stdin_parameters(const svc_action_t *op)
c54a00
+{
c54a00
+    crm_debug("sending args");
c54a00
+    if (op->params) {
c54a00
+        g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op);
c54a00
+    }
c54a00
+}
c54a00
+
c54a00
 gboolean
c54a00
 recurring_action_timer(gpointer data)
c54a00
 {
c54a00
@@ -284,6 +317,10 @@ operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exi
c54a00
         op->opaque->stdout_gsource = NULL;
c54a00
     }
c54a00
 
c54a00
+    if (op->opaque->stdin_fd >= 0) {
c54a00
+        close(op->opaque->stdin_fd);
c54a00
+    }
c54a00
+
c54a00
     if (signo) {
c54a00
         if (mainloop_child_timeout(p)) {
c54a00
             crm_warn("%s - timed out after %dms", prefix, op->timeout);
c54a00
@@ -605,6 +642,9 @@ action_synced_wait(svc_action_t * op, sigset_t *mask)
c54a00
 
c54a00
     close(op->opaque->stdout_fd);
c54a00
     close(op->opaque->stderr_fd);
c54a00
+    if (op->opaque->stdin_fd >= 0) {
c54a00
+        close(op->opaque->stdin_fd);
c54a00
+    }
c54a00
 
c54a00
 #ifdef HAVE_SYS_SIGNALFD_H
c54a00
     close(sfd);
c54a00
@@ -618,6 +658,7 @@ services_os_action_execute(svc_action_t * op)
c54a00
 {
c54a00
     int stdout_fd[2];
c54a00
     int stderr_fd[2];
c54a00
+    int stdin_fd[2] = {-1, -1};
c54a00
     int rc;
c54a00
     struct stat st;
c54a00
     sigset_t *pmask;
c54a00
@@ -683,6 +724,25 @@ services_os_action_execute(svc_action_t * op)
c54a00
         return FALSE;
c54a00
     }
c54a00
 
c54a00
+    if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_STONITH)) {
c54a00
+        if (pipe(stdin_fd) < 0) {
c54a00
+            rc = errno;
c54a00
+
c54a00
+            close(stdout_fd[0]);
c54a00
+            close(stdout_fd[1]);
c54a00
+            close(stderr_fd[0]);
c54a00
+            close(stderr_fd[1]);
c54a00
+
c54a00
+            crm_err("pipe(stdin_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
c54a00
+
c54a00
+            services_handle_exec_error(op, rc);
c54a00
+            if (!op->synchronous) {
c54a00
+                return operation_finalize(op);
c54a00
+            }
c54a00
+            return FALSE;
c54a00
+        }
c54a00
+    }
c54a00
+
c54a00
     if (op->synchronous) {
c54a00
 #ifdef HAVE_SYS_SIGNALFD_H
c54a00
         sigemptyset(&mask);
c54a00
@@ -730,6 +790,10 @@ services_os_action_execute(svc_action_t * op)
c54a00
             close(stdout_fd[1]);
c54a00
             close(stderr_fd[0]);
c54a00
             close(stderr_fd[1]);
c54a00
+            if (stdin_fd[0] >= 0) {
c54a00
+                close(stdin_fd[0]);
c54a00
+                close(stdin_fd[1]);
c54a00
+            }
c54a00
 
c54a00
             crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
c54a00
             services_handle_exec_error(op, rc);
c54a00
@@ -743,6 +807,9 @@ services_os_action_execute(svc_action_t * op)
c54a00
         case 0:                /* Child */
c54a00
             close(stdout_fd[0]);
c54a00
             close(stderr_fd[0]);
c54a00
+            if (stdin_fd[1] >= 0) {
c54a00
+                close(stdin_fd[1]);
c54a00
+            }
c54a00
             if (STDOUT_FILENO != stdout_fd[1]) {
c54a00
                 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
c54a00
                     crm_err("dup2() failed (stdout)");
c54a00
@@ -755,6 +822,13 @@ services_os_action_execute(svc_action_t * op)
c54a00
                 }
c54a00
                 close(stderr_fd[1]);
c54a00
             }
c54a00
+            if ((stdin_fd[0] >= 0) &&
c54a00
+                (STDIN_FILENO != stdin_fd[0])) {
c54a00
+                if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
c54a00
+                    crm_err("dup2() failed (stdin)");
c54a00
+                }
c54a00
+                close(stdin_fd[0]);
c54a00
+            }
c54a00
 
c54a00
             if (op->synchronous) {
c54a00
                 sigchld_cleanup();
c54a00
@@ -767,6 +841,9 @@ services_os_action_execute(svc_action_t * op)
c54a00
     /* Only the parent reaches here */
c54a00
     close(stdout_fd[1]);
c54a00
     close(stderr_fd[1]);
c54a00
+    if (stdin_fd[0] >= 0) {
c54a00
+        close(stdin_fd[0]);
c54a00
+    }
c54a00
 
c54a00
     op->opaque->stdout_fd = stdout_fd[0];
c54a00
     rc = crm_set_nonblocking(op->opaque->stdout_fd);
c54a00
@@ -784,6 +861,22 @@ services_os_action_execute(svc_action_t * op)
c54a00
                  pcmk_strerror(rc), rc);
c54a00
     }
c54a00
 
c54a00
+    op->opaque->stdin_fd = stdin_fd[1];
c54a00
+    if (op->opaque->stdin_fd >= 0) {
c54a00
+        // using buffer behind non-blocking-fd here - that could be improved
c54a00
+        // as long as no other standard uses stdin_fd assume stonith
c54a00
+        rc = crm_set_nonblocking(op->opaque->stdin_fd);
c54a00
+        if (rc < 0) {
c54a00
+            crm_warn("Could not set child input non-blocking: %s "
c54a00
+                    CRM_XS " fd=%d,rc=%d",
c54a00
+                    pcmk_strerror(rc), op->opaque->stdin_fd, rc);
c54a00
+        }
c54a00
+        pipe_in_action_stdin_parameters(op);
c54a00
+        // as long as we are handling parameters directly in here just close
c54a00
+        close(op->opaque->stdin_fd);
c54a00
+        op->opaque->stdin_fd = -1;
c54a00
+    }
c54a00
+
c54a00
     if (op->synchronous) {
c54a00
         action_synced_wait(op, pmask);
c54a00
         sigchld_cleanup();
c54a00
diff --git a/lib/services/services_private.h b/lib/services/services_private.h
c54a00
index 0676c6f..9735da7 100644
c54a00
--- a/lib/services/services_private.h
c54a00
+++ b/lib/services/services_private.h
c54a00
@@ -42,6 +42,8 @@ struct svc_action_private_s {
c54a00
 
c54a00
     int stdout_fd;
c54a00
     mainloop_io_t *stdout_gsource;
c54a00
+
c54a00
+    int stdin_fd;
c54a00
 #if SUPPORT_DBUS
c54a00
     DBusPendingCall* pending;
c54a00
     unsigned timerid;
c54a00
-- 
c54a00
1.8.3.1
c54a00