apr_proc_spawn.diff   [plain text]


--- threadproc/unix/proc.c.orig	2007-10-14 11:00:37.000000000 -0700
+++ threadproc/unix/proc.c	2009-04-06 12:34:57.000000000 -0700
@@ -20,6 +20,9 @@
 #include "apr_signal.h"
 #include "apr_random.h"
 
+#include <crt_externs.h>
+#include <spawn.h>
+
 /* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
  * requested for a specific child handle;
  */
@@ -599,6 +602,84 @@
     return APR_SUCCESS;
 }
 
+APR_DECLARE(apr_status_t) apr_proc_spawn(apr_proc_t *new,
+                                          const char *progname,
+                                          const char * const *args,
+                                          const char * const *env,
+                                          apr_procattr_t *attr,
+                                          apr_pool_t *pool)
+{
+    posix_spawn_file_actions_t file_actions;
+    int status = APR_EGENERAL;
+
+    new->in = attr->parent_in;
+    new->err = attr->parent_err;
+    new->out = attr->parent_out;
+
+    // XXX: attr->errchk
+
+    // XXX: Are those apr_pool_cleanup_* calls needed?
+
+    posix_spawn_file_actions_init(&file_actions);
+
+    if ((attr->child_in) && (attr->child_in->filedes == -1)) {
+        posix_spawn_file_actions_addclose(&file_actions, STDIN_FILENO);
+    }
+    else if (attr->child_in) {
+        posix_spawn_file_actions_adddup2(&file_actions, attr->child_in->filedes, STDIN_FILENO);
+        posix_spawn_file_actions_addclose(&file_actions, attr->child_in->filedes);
+    }
+
+    if ((attr->child_out) && (attr->child_out->filedes == -1)) {
+        posix_spawn_file_actions_addclose(&file_actions, STDOUT_FILENO);
+    }
+    else if (attr->child_out) {
+        posix_spawn_file_actions_adddup2(&file_actions, attr->child_out->filedes, STDOUT_FILENO);
+        posix_spawn_file_actions_addclose(&file_actions, attr->child_out->filedes);
+    }
+
+    if ((attr->child_err) && (attr->child_err->filedes == -1)) {
+        posix_spawn_file_actions_addclose(&file_actions, STDERR_FILENO);
+    }
+    else if (attr->child_err) {
+        posix_spawn_file_actions_adddup2(&file_actions, attr->child_err->filedes, STDERR_FILENO);
+        posix_spawn_file_actions_addclose(&file_actions, attr->child_err->filedes);
+    }
+
+    // XXX: signal
+    // XXX: currdir, gid, uid, limit_proc
+
+    /* Only support APR_PROGRAM_PATH for now. */
+    if (attr->cmdtype == APR_PROGRAM_PATH) {
+        /* Pass existing environment; as documented, APR_PROGRAM_PATH ignores the env argument. */
+        status = posix_spawnp(&new->pid, progname, &file_actions, NULL, args, (const char **)*_NSGetEnviron());
+        if (status != 0) {
+            if (attr->errfn) {
+                char *desc;
+
+                desc = apr_psprintf(pool, "posix_spawn of '%s' failed", progname);
+                attr->errfn(pool, status, desc);
+            }
+        }
+    }
+
+    posix_spawn_file_actions_destroy(&file_actions);
+
+    if (attr->child_in && (attr->child_in->filedes != -1)) {
+        apr_file_close(attr->child_in);
+    }
+
+    if (attr->child_out && (attr->child_out->filedes != -1)) {
+        apr_file_close(attr->child_out);
+    }
+
+    if (attr->child_err && (attr->child_err->filedes != -1)) {
+        apr_file_close(attr->child_err);
+    }
+
+    return status;
+}
+
 APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
                                                   int *exitcode,
                                                   apr_exit_why_e *exitwhy,