expand GNUNET_OS_ProjectData API to also enable de-duplcation of logic for --help
[oweals/gnunet.git] / src / util / os_priority.c
index cabce94f1cce81d5dc8d41660cba9a4c81e849c4..52e2f6d0e88d7106c19d03787c246ab554904dcc 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet
 /*
      This file is part of GNUnet
-     (C) 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
  */
 
 #include "platform.h"
  */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_os_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_strings_lib.h"
-#include "gnunet_crypto_lib.h"
+#include "gnunet_util_lib.h"
 #include "disk.h"
 #include "disk.h"
+#include <unistr.h>
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
@@ -40,6 +37,7 @@
 
 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
 
 
 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
 
+
 struct GNUNET_OS_Process
 {
   /**
 struct GNUNET_OS_Process
 {
   /**
@@ -55,14 +53,10 @@ struct GNUNET_OS_Process
 #endif
 
   /**
 #endif
 
   /**
-   * Pipe we use to signal the process (if used).
+   * Pipe we use to signal the process.
+   * NULL if unused, or if process was deemed uncontrollable.
    */
   struct GNUNET_DISK_FileHandle *control_pipe;
    */
   struct GNUNET_DISK_FileHandle *control_pipe;
-
-  /**
-   * Name of the pipe, NULL for none.
-   */
-  char *childpipename;
 };
 
 
 };
 
 
@@ -72,248 +66,6 @@ struct GNUNET_OS_Process
 static struct GNUNET_OS_Process current_process;
 
 
 static struct GNUNET_OS_Process current_process;
 
 
-/* MinGW version of named pipe API */
-#ifdef MINGW
-/**
- * Creates a named pipe/FIFO and opens it
- *
- * @param fn pointer to the name of the named pipe or to NULL
- * @param flags open flags
- * @param perm access permissions
- * @return pipe handle on success, NULL on error
- */
-static struct GNUNET_DISK_FileHandle *
-npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
-             enum GNUNET_DISK_AccessPermissions perm)
-{
-  struct GNUNET_DISK_FileHandle *ret;
-  HANDLE h = NULL;
-  DWORD openMode;
-  char *name;
-
-  openMode = 0;
-  if (flags & GNUNET_DISK_OPEN_READWRITE)
-    openMode = PIPE_ACCESS_DUPLEX;
-  else if (flags & GNUNET_DISK_OPEN_READ)
-    openMode = PIPE_ACCESS_INBOUND;
-  else if (flags & GNUNET_DISK_OPEN_WRITE)
-    openMode = PIPE_ACCESS_OUTBOUND;
-  if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
-    openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
-
-  while (h == NULL)
-  {
-    DWORD error_code;
-
-    name = NULL;
-    if (*fn != NULL)
-    {
-      GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Trying to create an instance of named pipe `%s'\n", name);
-      /* 1) This might work just fine with UTF-8 strings as it is.
-       * 2) This is only used by GNUnet itself, and only with latin names.
-       */
-      h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
-                           PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
-                           NULL);
-    }
-    else
-    {
-      GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu",
-                       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                                 UINT64_MAX));
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n",
-           *fn);
-      h = CreateNamedPipe (*fn,
-                           openMode | FILE_FLAG_OVERLAPPED |
-                           FILE_FLAG_FIRST_PIPE_INSTANCE,
-                           PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
-                           NULL);
-    }
-    error_code = GetLastError ();
-    if (name)
-      GNUNET_free (name);
-    /* don't re-set name to NULL yet */
-    if (h == INVALID_HANDLE_VALUE)
-    {
-      SetErrnoFromWinError (error_code);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Pipe creation have failed because of %d, errno is %d\n", error_code,
-           errno);
-      if (name == NULL)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Pipe was to be unique, considering re-creation\n");
-        GNUNET_free (*fn);
-        *fn = NULL;
-        if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY)
-        {
-          return NULL;
-        }
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Pipe name was not unique, trying again\n");
-        h = NULL;
-      }
-      else
-        return NULL;
-    }
-  }
-  errno = 0;
-
-  ret = GNUNET_malloc (sizeof (*ret));
-  ret->h = h;
-  ret->type = GNUNET_PIPE;
-  ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
-  ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
-  ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
-  ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
-  return ret;
-}
-
-
-/**
- * Opens already existing named pipe/FIFO
- *
- * @param fn name of an existing named pipe
- * @param flags open flags
- * @return pipe handle on success, NULL on error
- */
-static struct GNUNET_DISK_FileHandle *
-npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags)
-{
-  struct GNUNET_DISK_FileHandle *ret;
-  HANDLE h;
-  DWORD openMode;
-
-  openMode = 0;
-  if (flags & GNUNET_DISK_OPEN_READWRITE)
-    openMode = GENERIC_WRITE | GENERIC_READ;
-  else if (flags & GNUNET_DISK_OPEN_READ)
-    openMode = GENERIC_READ;
-  else if (flags & GNUNET_DISK_OPEN_WRITE)
-    openMode = GENERIC_WRITE;
-
-  h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
-                  FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
-  if (h == INVALID_HANDLE_VALUE)
-  {
-    SetErrnoFromWinError (GetLastError ());
-    return NULL;
-  }
-
-  ret = GNUNET_malloc (sizeof (*ret));
-  ret->h = h;
-  ret->type = GNUNET_PIPE;
-  ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
-  ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
-  ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
-  ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
-
-  return ret;
-}
-
-#else
-/* UNIX version of named-pipe API */
-
-/**
- * Clean up a named pipe and the directory it was placed in.
- *
- * @param fn name of the pipe
- */
-static void
-cleanup_npipe (const char *fn)
-{
-  char *dn;
-  char *dp;
-
-  if (0 != unlink (fn))
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
-  dn = GNUNET_strdup (fn);
-  dp = dirname (dn);
-  if (0 != rmdir (dp))
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp);
-  GNUNET_free (dn);  
-}
-
-
-/**
- * Setup a named pipe.
- *
- * @param fn where to store the name of the new pipe,
- *           if *fn is non-null, the name of the pipe to setup
- * @return GNUNET_OK on success
- */
-static int
-npipe_setup (char **fn)
-{
-  if (NULL == *fn)
-  {
-    /* FIXME: hardwired '/tmp' path... is bad */
-    char dir[] = "/tmp/gnunet-pipe-XXXXXX"; 
-
-    if (NULL == mkdtemp (dir))
-    {
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp");
-      return GNUNET_SYSERR;
-    }
-    GNUNET_asprintf (fn, "%s/child-control", dir);
-  }
-  if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR))
-    return GNUNET_SYSERR;  
-  return GNUNET_OK;
-}
-
-
-/**
- * Open an existing named pipe.
- *
- * @param fn name of the file
- * @param flags flags to use
- * @return NULL on error
- */
-static struct GNUNET_DISK_FileHandle *
-npipe_open (const char *fn,
-           enum GNUNET_DISK_OpenFlags flags)
-{
-  struct GNUNET_DISK_FileHandle *ret;
-  int fd;
-  struct timespec req;
-  int i;
-
-  /* 200 * 5ms = 1s at most */
-  for (i=0;i<200;i++) 
-  {
-    fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONLY : O_WRONLY));
-    if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ)) 
-      break;
-    /* as this is for killing a child process via pipe and it is conceivable that
-       the child process simply didn't finish starting yet, we do some sleeping
-       (which is obviously usually not allowed).  We can't select on the FD as
-       'open' fails, and we probably shouldn't just "ignore" the error, so wait
-       and retry a few times is likely the best method; our process API doesn't 
-       support continuations, so we need to sleep directly... */
-    req.tv_sec = 0;
-    req.tv_nsec = 5000000; /* 5ms */
-    (void) nanosleep (&req, NULL);
-  } 
-  if (-1 == fd)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               (flags == GNUNET_DISK_OPEN_READ) 
-               ? _("Failed to open named pipe `%s' for reading: %s\n")
-               : _("Failed to open named pipe `%s' for writing: %s\n"),
-               fn,
-               STRERROR (errno));
-    return NULL;
-  }
-  ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
-  ret->fd = fd;
-  return ret;
-}
-#endif
-
-
 /**
  * This handler is called when there are control data to be read on the pipe
  *
 /**
  * This handler is called when there are control data to be read on the pipe
  *
@@ -326,8 +78,9 @@ parent_control_handler (void *cls,
 {
   struct GNUNET_DISK_FileHandle *control_pipe = cls;
   char sig;
 {
   struct GNUNET_DISK_FileHandle *control_pipe = cls;
   char sig;
+  char *pipe_fd;
   ssize_t ret;
   ssize_t ret;
-  
+
   LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
        tc->reason);
   if (0 != (tc->reason &
   LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
        tc->reason);
   if (0 != (tc->reason &
@@ -342,15 +95,19 @@ parent_control_handler (void *cls,
   {
     if (-1 == ret)
       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
   {
     if (-1 == ret)
       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
     GNUNET_DISK_file_close (control_pipe);
     control_pipe = NULL;
     return;
   }
     GNUNET_DISK_file_close (control_pipe);
     control_pipe = NULL;
     return;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig);
+  pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
+  GNUNET_assert ( (NULL == pipe_fd) || (strlen (pipe_fd) <= 0) );
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got control code %d from parent via pipe %s\n", sig, pipe_fd);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                  control_pipe, &parent_control_handler,
                                  control_pipe);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                  control_pipe, &parent_control_handler,
                                  control_pipe);
-  raise ((int) sig);
+  GNUNET_SIGNAL_raise ((int) sig);
 }
 
 
 }
 
 
@@ -369,30 +126,55 @@ GNUNET_OS_install_parent_control_handler (void *cls,
                                           GNUNET_SCHEDULER_TaskContext *tc)
 {
   const char *env_buf;
                                           GNUNET_SCHEDULER_TaskContext *tc)
 {
   const char *env_buf;
+  char *env_buf_end;
   struct GNUNET_DISK_FileHandle *control_pipe;
   struct GNUNET_DISK_FileHandle *control_pipe;
+  uint64_t pipe_fd;
 
   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
 
   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
-  if ( (env_buf == NULL) || (strlen (env_buf) <= 0) )
+  if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Not installing a handler because $%s is empty\n",
          GNUNET_OS_CONTROL_PIPE);
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Not installing a handler because $%s is empty\n",
          GNUNET_OS_CONTROL_PIPE);
-    putenv ("GNUNET_OS_CONTROL_PIPE=");
+    putenv (GNUNET_OS_CONTROL_PIPE "=");
+    return;
+  }
+  errno = 0;
+  pipe_fd = strtoull (env_buf, &env_buf_end, 16);
+  if ((0 != errno) || (env_buf == env_buf_end))
+  {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
+    putenv (GNUNET_OS_CONTROL_PIPE "=");
+    return;
+  }
+#if !defined (WINDOWS)
+  if (pipe_fd >= FD_SETSIZE)
+#else
+  if ((FILE_TYPE_UNKNOWN == GetFileType ((HANDLE) (uintptr_t) pipe_fd))
+      && (0 != GetLastError ()))
+#endif
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n", env_buf);
+    putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
     return;
   }
-  control_pipe =
-    npipe_open (env_buf, GNUNET_DISK_OPEN_READ);
+#if WINDOWS
+  control_pipe = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) (uintptr_t) pipe_fd);
+#else
+  control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
+#endif
   if (NULL == control_pipe)
   {
     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
   if (NULL == control_pipe)
   {
     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
-    putenv ("GNUNET_OS_CONTROL_PIPE=");
+    putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
                                   &parent_control_handler, control_pipe);
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
                                   &parent_control_handler, control_pipe);
-  putenv ("GNUNET_OS_CONTROL_PIPE=");
+  putenv (GNUNET_OS_CONTROL_PIPE "=");
 }
 
 
 }
 
 
@@ -431,44 +213,75 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   char csig;
 
   csig = (char) sig;
   char csig;
 
   csig = (char) sig;
-#if !WINDOWS
-  if ( (NULL == proc->control_pipe) &&
-       (NULL != proc->childpipename) )
-    proc->control_pipe = npipe_open (proc->childpipename,
-                                    GNUNET_DISK_OPEN_WRITE);
-#endif
   if (NULL != proc->control_pipe)
   {
   if (NULL != proc->control_pipe)
   {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via pipe\n", sig, proc->pid);
     ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
     ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
-    if (ret == sizeof (csig))  
+    if (sizeof (csig) == ret)
       return 0;
   }
   /* pipe failed or non-existent, try other methods */
   switch (sig)
   {
       return 0;
   }
   /* pipe failed or non-existent, try other methods */
   switch (sig)
   {
-#if !WINDOWS
+#if !defined (WINDOWS)
   case SIGHUP:
 #endif
   case SIGINT:
   case SIGKILL:
   case SIGTERM:
   case SIGHUP:
 #endif
   case SIGINT:
   case SIGKILL:
   case SIGTERM:
-#if WINDOWS && !defined(__CYGWIN__)
-    if (0 == TerminateProcess (proc->handle, 0))
+#if (SIGTERM != GNUNET_TERM_SIG)
+  case GNUNET_TERM_SIG:
+#endif
+#if defined(WINDOWS) && !defined(__CYGWIN__)
     {
     {
-      /* FIXME: set 'errno' */
-      return -1;
+      DWORD exitcode;
+      int must_kill = GNUNET_YES;
+      if (0 != GetExitCodeProcess (proc->handle, &exitcode))
+        must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
+      if (GNUNET_YES == must_kill)
+        if (0 == SafeTerminateProcess (proc->handle, 0, 0))
+        {
+          DWORD error_code = GetLastError ();
+          if ((error_code != WAIT_TIMEOUT) && (error_code != ERROR_PROCESS_ABORTED))
+          {
+            LOG ((error_code == ERROR_ACCESS_DENIED) ?
+                GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
+                "SafeTermiateProcess failed with code %lu\n", error_code);
+            /* The problem here is that a process that is already dying
+             * might cause SafeTerminateProcess to fail with
+             * ERROR_ACCESS_DENIED, but the process WILL die eventually.
+             * If we really had a permissions problem, hanging up (which
+             * is what will happen in process_wait() in that case) is
+             * a valid option.
+             */
+            if (ERROR_ACCESS_DENIED == error_code)
+            {
+              errno = 0;
+            }
+            else
+            {
+              SetErrnoFromWinError (error_code);
+              return -1;
+            }
+          }
+        }
     }
     return 0;
 #else
     }
     return 0;
 #else
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Sending signal %d to pid: %u via system call\n",
+         sig,
+         proc->pid);
     return PLIBC_KILL (proc->pid, sig);
 #endif
   default:
     return PLIBC_KILL (proc->pid, sig);
 #endif
   default:
-#if WINDOWS
+#if defined (WINDOWS)
     errno = EINVAL;
     return -1;
 #else
     errno = EINVAL;
     return -1;
 #else
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
     return PLIBC_KILL (proc->pid, sig);
     return PLIBC_KILL (proc->pid, sig);
-#endif    
+#endif
   }
 }
 
   }
 }
 
@@ -492,26 +305,17 @@ GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
  * @param proc pointer to process structure
  */
 void
  * @param proc pointer to process structure
  */
 void
-GNUNET_OS_process_close (struct GNUNET_OS_Process *proc)
+GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
 {
   if (NULL != proc->control_pipe)
     GNUNET_DISK_file_close (proc->control_pipe);
 {
   if (NULL != proc->control_pipe)
     GNUNET_DISK_file_close (proc->control_pipe);
-// FIXME NILS
-#ifdef WINDOWS
-  if (proc->handle != NULL)
+#if defined (WINDOWS)
+  if (NULL != proc->handle)
     CloseHandle (proc->handle);
 #endif
     CloseHandle (proc->handle);
 #endif
-  if (NULL != proc->childpipename)
-  {
-#if !WINDOWS
-    cleanup_npipe (proc->childpipename);
-#endif
-    GNUNET_free (proc->childpipename);
-  }
   GNUNET_free (proc);
 }
 
   GNUNET_free (proc);
 }
 
-// FIXME NILS
 #if WINDOWS
 #include "gnunet_signal_lib.h"
 
 #if WINDOWS
 #include "gnunet_signal_lib.h"
 
@@ -540,119 +344,20 @@ child_wait_thread (void *arg)
 }
 #endif
 
 }
 #endif
 
-/**
- * Set process priority
- *
- * @param proc pointer to process structure
- * @param prio priority value
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
- */
-int
-GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
-                                enum GNUNET_SCHEDULER_Priority prio)
-{
-  int rprio;
-
-  GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
-  if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
-    return GNUNET_OK;
-
-  /* convert to MINGW/Unix values */
-  switch (prio)
-  {
-  case GNUNET_SCHEDULER_PRIORITY_UI:
-  case GNUNET_SCHEDULER_PRIORITY_URGENT:
-#ifdef MINGW
-    rprio = HIGH_PRIORITY_CLASS;
-#else
-    rprio = 0;
-#endif
-    break;
-
-  case GNUNET_SCHEDULER_PRIORITY_HIGH:
-#ifdef MINGW
-    rprio = ABOVE_NORMAL_PRIORITY_CLASS;
-#else
-    rprio = 5;
-#endif
-    break;
-
-  case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
-#ifdef MINGW
-    rprio = NORMAL_PRIORITY_CLASS;
-#else
-    rprio = 7;
-#endif
-    break;
-
-  case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
-#ifdef MINGW
-    rprio = BELOW_NORMAL_PRIORITY_CLASS;
-#else
-    rprio = 10;
-#endif
-    break;
-
-  case GNUNET_SCHEDULER_PRIORITY_IDLE:
-#ifdef MINGW
-    rprio = IDLE_PRIORITY_CLASS;
-#else
-    rprio = 19;
-#endif
-    break;
-  default:
-    GNUNET_assert (0);
-    return GNUNET_SYSERR;
-  }
-
-  /* Set process priority */
-#ifdef MINGW
-  {
-    HANDLE h = proc->handle;
-
-    GNUNET_assert (h != NULL);
-    SetPriorityClass (h, rprio);
-  }
-#elif LINUX
-  pid_t pid;
-
-  pid = proc->pid;
-  if ((0 == pid) || (pid == getpid ()))
-  {
-    int have = nice (0);
-    int delta = rprio - have;
-
-    errno = 0;
-    if ((delta != 0) && (rprio == nice (delta)) && (errno != 0))
-    {
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice");
-      return GNUNET_SYSERR;
-    }
-  }
-  else
-  {
-    if (0 != setpriority (PRIO_PROCESS, pid, rprio))
-    {
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
-                    "setpriority");
-      return GNUNET_SYSERR;
-    }
-  }
-#else
-  LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-       "Priority management not availabe for this platform\n");
-#endif
-  return GNUNET_OK;
-}
 
 #if MINGW
 static char *
 CreateCustomEnvTable (char **vars)
 {
 
 #if MINGW
 static char *
 CreateCustomEnvTable (char **vars)
 {
-  char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr;
+  char *win32_env_table;
+  char *ptr;
+  char **var_ptr;
+  char *result;
+  char *result_ptr;
   size_t tablesize = 0;
   size_t items_count = 0;
   size_t tablesize = 0;
   size_t items_count = 0;
-  size_t n_found = 0, n_var;
+  size_t n_found = 0;
+  size_t n_var;
   char *index = NULL;
   size_t c;
   size_t var_len;
   char *index = NULL;
   size_t c;
   size_t var_len;
@@ -660,7 +365,7 @@ CreateCustomEnvTable (char **vars)
   char *val;
 
   win32_env_table = GetEnvironmentStringsA ();
   char *val;
 
   win32_env_table = GetEnvironmentStringsA ();
-  if (win32_env_table == NULL)
+  if (NULL == win32_env_table)
     return NULL;
   for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
   n_var = c;
     return NULL;
   for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
   n_var = c;
@@ -745,6 +450,38 @@ CreateCustomEnvTable (char **vars)
   *result_ptr = 0;
   return result;
 }
   *result_ptr = 0;
   return result;
 }
+
+#else
+
+/**
+ * Open '/dev/null' and make the result the given
+ * file descriptor.
+ *
+ * @param target_fd desired FD to point to /dev/null
+ * @param flags open flags (O_RDONLY, O_WRONLY)
+ */
+static void
+open_dev_null (int target_fd,
+              int flags)
+{
+  int fd;
+
+  fd = open ("/dev/null", flags);
+  if (-1 == fd)
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
+    return;
+  }
+  if (fd == target_fd)
+    return;
+  if (-1 == dup2 (fd, target_fd))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    (void) close (fd);
+    return;
+  }
+  GNUNET_break (0 == close (fd));
+}
 #endif
 
 
 #endif
 
 
@@ -752,33 +489,96 @@ CreateCustomEnvTable (char **vars)
  * Start a process.
  *
  * @param pipe_control should a pipe be used to send signals to the child?
  * Start a process.
  *
  * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
+ *        std handles of the parent are inherited by the child.
+ *        pipe_stdin and pipe_stdout take priority over std_inheritance
+ *        (when they are non-NULL).
  * @param pipe_stdin pipe to use to send input to child process (or NULL)
  * @param pipe_stdout pipe to use to get output from child process (or NULL)
  * @param pipe_stdin pipe to use to send input to child process (or NULL)
  * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param pipe_stderr pipe to use for stderr for child process (or NULL)
+ * @param lsocks array of listen sockets to dup systemd-style (or NULL);
+ *         must be NULL on platforms where dup is not supported
  * @param filename name of the binary
  * @param filename name of the binary
- * @param argv NULL-terminated array of arguments to the process
- * @return pointer to process structure of the new process, NULL on error
+ * @param argv NULL-terminated list of arguments to the process
+ * @return process ID of the new process, -1 on error
  */
  */
-struct GNUNET_OS_Process *
-GNUNET_OS_start_process_vap (int pipe_control,
-                            struct GNUNET_DISK_PipeHandle *pipe_stdin,
-                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                            const char *filename, 
-                            char *const argv[])
+static struct GNUNET_OS_Process *
+start_process (int pipe_control,
+               enum GNUNET_OS_InheritStdioFlags std_inheritance,
+              struct GNUNET_DISK_PipeHandle *pipe_stdin,
+              struct GNUNET_DISK_PipeHandle *pipe_stdout,
+              struct GNUNET_DISK_PipeHandle *pipe_stderr,
+              const SOCKTYPE *lsocks,
+              const char *filename,
+              char *const argv[])
 {
 #ifndef MINGW
 {
 #ifndef MINGW
-  char *childpipename = NULL;
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
   pid_t ret;
   pid_t ret;
+  char fds[16];
+  struct GNUNET_OS_Process *gnunet_proc;
+  struct GNUNET_DISK_FileHandle *childpipe_read;
+  struct GNUNET_DISK_FileHandle *childpipe_write;
+  int childpipe_read_fd;
+  int i;
+  int j;
+  int k;
+  int tgt;
+  int flags;
+  int *lscp;
+  unsigned int ls;
   int fd_stdout_write;
   int fd_stdout_read;
   int fd_stdout_write;
   int fd_stdout_read;
+  int fd_stderr_write;
+  int fd_stderr_read;
   int fd_stdin_read;
   int fd_stdin_write;
 
   int fd_stdin_read;
   int fd_stdin_write;
 
-  if ( (GNUNET_YES == pipe_control) &&
-       (GNUNET_OK != 
-       npipe_setup (&childpipename)) )
-    return NULL;  
-  if (pipe_stdout != NULL)
+  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
+    return NULL; /* not executable */
+  if (GNUNET_YES == pipe_control)
+  {
+    struct GNUNET_DISK_PipeHandle *childpipe;
+    int dup_childpipe_read_fd = -1;
+
+    childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
+    if (NULL == childpipe)
+      return NULL;
+    childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
+    childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
+    GNUNET_DISK_pipe_close (childpipe);
+    if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
+        (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
+        &childpipe_read_fd, sizeof (int))) ||
+        (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
+    {
+      if (NULL != childpipe_read)
+        GNUNET_DISK_file_close (childpipe_read);
+      if (NULL != childpipe_write)
+        GNUNET_DISK_file_close (childpipe_write);
+      if (0 <= dup_childpipe_read_fd)
+        close (dup_childpipe_read_fd);
+      return NULL;
+    }
+    childpipe_read_fd = dup_childpipe_read_fd;
+    GNUNET_DISK_file_close (childpipe_read);
+  }
+  else
+  {
+    childpipe_write = NULL;
+    childpipe_read_fd = -1;
+  }
+  if (NULL != pipe_stdin)
+  {
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
+                                                     &fd_stdin_read, sizeof (int)));
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
+                                                     &fd_stdin_write, sizeof (int)));
+  }
+  if (NULL != pipe_stdout)
   {
     GNUNET_assert (GNUNET_OK ==
                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
   {
     GNUNET_assert (GNUNET_OK ==
                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
@@ -790,378 +590,110 @@ GNUNET_OS_start_process_vap (int pipe_control,
                                                      (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
                                                      &fd_stdout_read, sizeof (int)));
   }
                                                      (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
                                                      &fd_stdout_read, sizeof (int)));
   }
-  if (pipe_stdin != NULL)
+  if (NULL != pipe_stderr)
   {
     GNUNET_assert (GNUNET_OK ==
   {
     GNUNET_assert (GNUNET_OK ==
-                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
-                                                     &fd_stdin_read, sizeof (int)));
+                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                      (pipe_stderr,
+                                                       GNUNET_DISK_PIPE_END_READ),
+                                                      &fd_stderr_read, sizeof (int)));
     GNUNET_assert (GNUNET_OK ==
     GNUNET_assert (GNUNET_OK ==
-                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
-                                                     &fd_stdin_write, sizeof (int)));
+                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                      (pipe_stderr,
+                                                       GNUNET_DISK_PIPE_END_WRITE),
+                                                      &fd_stderr_write, sizeof (int)));
   }
   }
-
+  lscp = NULL;
+  ls = 0;
+  if (NULL != lsocks)
+  {
+    i = 0;
+    while (-1 != (k = lsocks[i++]))
+      GNUNET_array_append (lscp, ls, k);
+    GNUNET_array_append (lscp, ls, -1);
+  }
+#if DARWIN
+  /* see https://gnunet.org/vfork */
+  ret = vfork ();
+#else
   ret = fork ();
   ret = fork ();
+#endif
   if (-1 == ret)
   {
   if (-1 == ret)
   {
+    int eno = errno;
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
-    GNUNET_free_non_null (childpipename);
+    GNUNET_array_grow (lscp, ls, 0);
+    if (NULL != childpipe_write)
+      GNUNET_DISK_file_close (childpipe_write);
+    if (0 <= childpipe_read_fd)
+      close (childpipe_read_fd);
+    errno = eno;
     return NULL;
   }
   if (0 != ret)
   {
     return NULL;
   }
   if (0 != ret)
   {
-    gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
+    unsetenv (GNUNET_OS_CONTROL_PIPE);
+    gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
     gnunet_proc->pid = ret;
     gnunet_proc->pid = ret;
-    gnunet_proc->childpipename = childpipename;
+    gnunet_proc->control_pipe = childpipe_write;
+    if (GNUNET_YES == pipe_control)
+    {
+      close (childpipe_read_fd);
+    }
+    GNUNET_array_grow (lscp, ls, 0);
     return gnunet_proc;
   }
     return gnunet_proc;
   }
-  if (NULL != childpipename)
-  {
-    setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
-    GNUNET_free (childpipename);
-  }
-  if (pipe_stdout != NULL)
+  if (0 <= childpipe_read_fd)
   {
   {
-    GNUNET_break (0 == close (fd_stdout_read));
-    if (-1 == dup2 (fd_stdout_write, 1))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
-    GNUNET_break (0 == close (fd_stdout_write));
+    char fdbuf[100];
+#ifndef DARWIN
+    /* due to vfork, we must NOT free memory on DARWIN! */
+    GNUNET_DISK_file_close (childpipe_write);
+#endif
+    snprintf (fdbuf, 100, "%x", childpipe_read_fd);
+    setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
   }
   }
-
-  if (pipe_stdin != NULL)
+  else
+    unsetenv (GNUNET_OS_CONTROL_PIPE);
+  if (NULL != pipe_stdin)
   {
   {
-
     GNUNET_break (0 == close (fd_stdin_write));
     if (-1 == dup2 (fd_stdin_read, 0))
       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
     GNUNET_break (0 == close (fd_stdin_read));
   }
     GNUNET_break (0 == close (fd_stdin_write));
     if (-1 == dup2 (fd_stdin_read, 0))
       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
     GNUNET_break (0 == close (fd_stdin_read));
   }
-  execvp (filename, argv);
-  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
-  _exit (1);
-#else
-  char *childpipename = NULL;
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
-  char *arg;
-  unsigned int cmdlen;
-  char *cmd, *idx;
-  STARTUPINFOW start;
-  PROCESS_INFORMATION proc;
-  int argc, arg_count;
-  HANDLE stdin_handle;
-  HANDLE stdout_handle;
-  struct GNUNET_DISK_FileHandle *control_pipe;
-
-  char path[MAX_PATH + 1];
-
-  char *our_env[3] = { NULL, NULL, NULL };
-  char *env_block = NULL;
-  char *pathbuf;
-  DWORD pathbuf_len, alloc_len;
-  char *self_prefix;
-  char *bindir;
-  char *libdir;
-  char *ptr;
-  char *non_const_filename;
-  wchar_t wpath[MAX_PATH + 1], wcmd[32768];
-
-  /* Search in prefix dir (hopefully - the directory from which
-   * the current module was loaded), bindir and libdir, then in PATH
-   */
-  self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
-  bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
-  libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
-
-  pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
-
-  alloc_len =
-      pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
-      strlen (libdir);
-
-  pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
-
-  ptr = pathbuf;
-  ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
-  GNUNET_free (self_prefix);
-  GNUNET_free (bindir);
-  GNUNET_free (libdir);
-
-  alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
-  GNUNET_assert (alloc_len == (pathbuf_len - 1));
-
-  cmdlen = strlen (filename);
-  if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
-    GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
-  else
-    GNUNET_asprintf (&non_const_filename, "%s", filename);
-
-  /* Check that this is the full path. If it isn't, search. */
-  if (non_const_filename[1] == ':')
-    snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
-  else if (!SearchPathA
-           (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
-            path, NULL))
-  {
-    SetErrnoFromWinError (GetLastError ());
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
-                       non_const_filename);
-    GNUNET_free (non_const_filename);
-    GNUNET_free (pathbuf);
-    return NULL;
-  }
-  GNUNET_free (pathbuf);
-  GNUNET_free (non_const_filename);
-
-  cmdlen = 0;
-  argc = 0;
-  while (NULL != (arg = argv[argc++]))
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
   {
   {
-    if (cmdlen == 0)
-      cmdlen = cmdlen + strlen (path) + 4;
-    else
-      cmdlen = cmdlen + strlen (arg) + 4;
+    GNUNET_break (0 == close (0));
+    open_dev_null (0, O_RDONLY);
   }
   }
-  arg_count = argc;
-
-  cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
-  argc = 0;
-  while (NULL != (arg = argv[argc++]))
-  {
-    /* This is to escape trailing slash */
-    char arg_lastchar = arg[strlen (arg) - 1];
-    if (idx == cmd)
-      idx += sprintf (idx, "\"%s%s\"%s", path,
-          arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " ");
-    else
-      idx += sprintf (idx, "\"%s%s\"%s", arg,
-          arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " ");
-  }
-
-  memset (&start, 0, sizeof (start));
-  start.cb = sizeof (start);
-
-  if ((pipe_stdin != NULL) || (pipe_stdout != NULL))
-    start.dwFlags |= STARTF_USESTDHANDLES;
-
-  if (pipe_stdin != NULL)
-  {
-    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                       (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
-                                       &stdin_handle, sizeof (HANDLE));
-    start.hStdInput = stdin_handle;
-  }
-
-  if (pipe_stdout != NULL)
-  {
-    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                       (pipe_stdout,
-                                        GNUNET_DISK_PIPE_END_WRITE),
-                                       &stdout_handle, sizeof (HANDLE));
-    start.hStdOutput = stdout_handle;
-  }
-  if (GNUNET_YES == pipe_control)
-  {
-    control_pipe =
-      npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
-                   GNUNET_DISK_PERM_USER_READ |
-                   GNUNET_DISK_PERM_USER_WRITE);
-    if (control_pipe == NULL)
-    {
-      GNUNET_free (cmd);
-      GNUNET_free (path);
-      return NULL;
-    }
-  }
-  else
-    control_pipe = NULL;
-  if (NULL != childpipename)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
-        childpipename);
-    GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
-    GNUNET_asprintf (&our_env[1], "%s", childpipename);
-    our_env[2] = NULL;
-  }
-  else
-  {
-    our_env[0] = NULL;
-  }
-  env_block = CreateCustomEnvTable (our_env);
-  GNUNET_free_non_null (our_env[0]);
-  GNUNET_free_non_null (our_env[1]);
-
-  if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)
-      || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd)
-      || !CreateProcessW
-      (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
-       env_block, NULL, &start, &proc))
-  {
-    SetErrnoFromWinError (GetLastError ());
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-    GNUNET_free (env_block);
-    GNUNET_free (cmd);
-    return NULL;
-  }
-
-  GNUNET_free (env_block);
-
-  gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
-  gnunet_proc->pid = proc.dwProcessId;
-  gnunet_proc->handle = proc.hProcess;
-  gnunet_proc->control_pipe = control_pipe;
-
-  CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
-
-  ResumeThread (proc.hThread);
-  CloseHandle (proc.hThread);
-
-  GNUNET_free (cmd);
-
-  return gnunet_proc;
-#endif
-}
-
-
-/**
- * Start a process.
- *
- * @param pipe_control should a pipe be used to send signals to the child?
- * @param pipe_stdin pipe to use to send input to child process (or NULL)
- * @param pipe_stdout pipe to use to get output from child process (or NULL)
- * @param filename name of the binary
- * @param va NULL-terminated list of arguments to the process
- * @return pointer to process structure of the new process, NULL on error
- */
-struct GNUNET_OS_Process *
-GNUNET_OS_start_process_va (int pipe_control,
-                           struct GNUNET_DISK_PipeHandle *pipe_stdin,
-                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                            const char *filename, va_list va)
-{
-  struct GNUNET_OS_Process *ret;
-  va_list ap;
-  char **argv;
-  int argc;
-
-  argc = 0;
-  va_copy (ap, va);
-  while (NULL != va_arg (ap, char *))
-    argc++;
-  va_end (ap);
-  argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
-  argc = 0;
-  va_copy (ap, va);
-  while (NULL != (argv[argc] = va_arg (ap, char *)))
-    argc++;
-  va_end (ap);
-  ret = GNUNET_OS_start_process_vap (pipe_control,
-                                    pipe_stdin,
-                                    pipe_stdout,
-                                    filename,
-                                    argv);
-  GNUNET_free (argv);
-  return ret;
-}
-
-
-
-/**
- * Start a process.
- *
- * @param pipe_control should a pipe be used to send signals to the child?
- * @param pipe_stdin pipe to use to send input to child process (or NULL)
- * @param pipe_stdout pipe to use to get output from child process (or NULL)
- * @param filename name of the binary
- * @param ... NULL-terminated list of arguments to the process
- *
- * @return pointer to process structure of the new process, NULL on error
- *
- */
-struct GNUNET_OS_Process *
-GNUNET_OS_start_process (int pipe_control,
-                        struct GNUNET_DISK_PipeHandle *pipe_stdin,
-                         struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                         const char *filename, ...)
-{
-  struct GNUNET_OS_Process *ret;
-  va_list ap;
-
-  va_start (ap, filename);
-  ret = GNUNET_OS_start_process_va (pipe_control, pipe_stdin, pipe_stdout, filename, ap);
-  va_end (ap);
-  return ret;
-}
-
-
-/**
- * Start a process.
- *
- * @param pipe_control should a pipe be used to send signals to the child?
- * @param lsocks array of listen sockets to dup systemd-style (or NULL);
- *         must be NULL on platforms where dup is not supported
- * @param filename name of the binary
- * @param argv NULL-terminated list of arguments to the process
- * @return process ID of the new process, -1 on error
- */
-struct GNUNET_OS_Process *
-GNUNET_OS_start_process_v (int pipe_control,
-                          const SOCKTYPE *lsocks,
-                           const char *filename,
-                           char *const argv[])
-{
-#ifndef MINGW
-  pid_t ret;
-  char lpid[16];
-  char fds[16];
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
-  char *childpipename = NULL;
-  int i;
-  int j;
-  int k;
-  int tgt;
-  int flags;
-  int *lscp;
-  unsigned int ls;
-
-  if ( (GNUNET_YES == pipe_control) &&
-       (GNUNET_OK != npipe_setup (&childpipename)) )
-    return NULL;  
-  lscp = NULL;
-  ls = 0;
-  if (lsocks != NULL)
+  if (NULL != pipe_stdout)
   {
   {
-    i = 0;
-    while (-1 != (k = lsocks[i++]))
-      GNUNET_array_append (lscp, ls, k);
-    GNUNET_array_append (lscp, ls, -1);
+    GNUNET_break (0 == close (fd_stdout_read));
+    if (-1 == dup2 (fd_stdout_write, 1))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    GNUNET_break (0 == close (fd_stdout_write));
   }
   }
-  ret = fork ();
-  if (-1 == ret)
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
   {
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
-    GNUNET_free_non_null (childpipename);
-    GNUNET_array_grow (lscp, ls, 0);
-    return NULL;
+    GNUNET_break (0 == close (1));
+    open_dev_null (1, O_WRONLY);
   }
   }
-  if (0 != ret)
+  if (NULL != pipe_stderr)
   {
   {
-    gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
-    gnunet_proc->pid = ret;
-    gnunet_proc->childpipename = childpipename;  
-    GNUNET_array_grow (lscp, ls, 0);
-    return gnunet_proc;
+    GNUNET_break (0 == close (fd_stderr_read));
+    if (-1 == dup2 (fd_stderr_write, 2))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    GNUNET_break (0 == close (fd_stderr_write));
   }
   }
-  if (NULL != childpipename)
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
   {
   {
-    setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
-    GNUNET_free (childpipename);
+    GNUNET_break (0 == close (2));
+    open_dev_null (2, O_WRONLY);
   }
   }
-  if (lscp != NULL)
+  if (NULL != lscp)
   {
     /* read systemd documentation... */
   {
     /* read systemd documentation... */
-    GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
-    setenv ("LISTEN_PID", lpid, 1);
     i = 0;
     tgt = 3;
     while (-1 != lscp[i])
     i = 0;
     tgt = 3;
     while (-1 != lscp[i])
@@ -1199,37 +731,59 @@ GNUNET_OS_start_process_v (int pipe_control,
     GNUNET_snprintf (fds, sizeof (fds), "%u", i);
     setenv ("LISTEN_FDS", fds, 1);
   }
     GNUNET_snprintf (fds, sizeof (fds), "%u", i);
     setenv ("LISTEN_FDS", fds, 1);
   }
+#ifndef DARWIN
+  /* due to vfork, we must NOT free memory on DARWIN! */
   GNUNET_array_grow (lscp, ls, 0);
   GNUNET_array_grow (lscp, ls, 0);
+#endif
   execvp (filename, argv);
   LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
   _exit (1);
 #else
   execvp (filename, argv);
   LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
   _exit (1);
 #else
-  struct GNUNET_DISK_FileHandle *control_pipe = NULL;
-  char *childpipename = NULL;
-  char **arg, **non_const_argv;
+  struct GNUNET_DISK_FileHandle *childpipe_read;
+  struct GNUNET_DISK_FileHandle *childpipe_write;
+  HANDLE childpipe_read_handle;
+  char **arg;
+  char **non_const_argv;
   unsigned int cmdlen;
   unsigned int cmdlen;
-  char *cmd, *idx;
+  char *cmd;
+  char *idx;
   STARTUPINFOW start;
   PROCESS_INFORMATION proc;
   int argcount = 0;
   STARTUPINFOW start;
   PROCESS_INFORMATION proc;
   int argcount = 0;
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_OS_Process *gnunet_proc;
   char path[MAX_PATH + 1];
   char path[MAX_PATH + 1];
-  char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
+  char *our_env[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
   char *env_block = NULL;
   char *pathbuf;
   char *env_block = NULL;
   char *pathbuf;
-  DWORD pathbuf_len, alloc_len;
+  DWORD pathbuf_len;
+  DWORD alloc_len;
   char *self_prefix;
   char *bindir;
   char *libdir;
   char *ptr;
   char *non_const_filename;
   char *self_prefix;
   char *bindir;
   char *libdir;
   char *ptr;
   char *non_const_filename;
+  char win_path[MAX_PATH + 1];
   struct GNUNET_DISK_PipeHandle *lsocks_pipe;
   const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
   HANDLE lsocks_read;
   HANDLE lsocks_write;
   struct GNUNET_DISK_PipeHandle *lsocks_pipe;
   const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
   HANDLE lsocks_read;
   HANDLE lsocks_write;
-  wchar_t wpath[MAX_PATH + 1], wcmd[32768];
+  wchar_t *wpath;
+  wchar_t *wcmd;
+  size_t wpath_len;
+  size_t wcmd_len;
   int env_off;
   int fail;
   int env_off;
   int fail;
+  long lRet;
+  HANDLE stdin_handle;
+  HANDLE stdout_handle;
+  HANDLE stdih, stdoh, stdeh;
+  DWORD stdif, stdof, stdef;
+  BOOL bresult;
+  DWORD error_code;
+  DWORD create_no_window;
+
+  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
+    return NULL; /* not executable */
 
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
 
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
@@ -1261,14 +815,33 @@ GNUNET_OS_start_process_v (int pipe_control,
   }
 
   cmdlen = strlen (filename);
   }
 
   cmdlen = strlen (filename);
-  if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
+  if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
     GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
   else
     GNUNET_asprintf (&non_const_filename, "%s", filename);
 
     GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
   else
     GNUNET_asprintf (&non_const_filename, "%s", filename);
 
-  /* Check that this is the full path. If it isn't, search. */
+  /* It could be in POSIX form, convert it to a DOS path early on */
+  if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
+  {
+    SetErrnoFromWinError (lRet);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
+                       non_const_filename);
+    GNUNET_free (non_const_filename);
+    GNUNET_free (pathbuf);
+    return NULL;
+  }
+  GNUNET_free (non_const_filename);
+  non_const_filename = GNUNET_strdup (win_path);
+   /* Check that this is the full path. If it isn't, search. */
+  /* FIXME: convert it to wchar_t and use SearchPathW?
+   * Remember: arguments to _start_process() are technically in UTF-8...
+   */
   if (non_const_filename[1] == ':')
   if (non_const_filename[1] == ':')
+  {
     snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
     snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Using path `%s' as-is. PATH is %s\n", path, ptr);
+  }
   else if (!SearchPathA
            (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
             path, NULL))
   else if (!SearchPathA
            (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
             path, NULL))
@@ -1280,6 +853,9 @@ GNUNET_OS_start_process_v (int pipe_control,
     GNUNET_free (pathbuf);
     return NULL;
   }
     GNUNET_free (pathbuf);
     return NULL;
   }
+  else
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Found `%s' in PATH `%s'\n", path, pathbuf);
   GNUNET_free (pathbuf);
   GNUNET_free (non_const_filename);
 
   GNUNET_free (pathbuf);
   GNUNET_free (non_const_filename);
 
@@ -1334,22 +910,97 @@ GNUNET_OS_start_process_v (int pipe_control,
 
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
+  if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
+    start.dwFlags |= STARTF_USESTDHANDLES;
+
+  stdih = GetStdHandle (STD_INPUT_HANDLE);
+  GetHandleInformation (stdih, &stdif);
+  if (pipe_stdin != NULL)
+  {
+    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                       (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
+                                       &stdin_handle, sizeof (HANDLE));
+    start.hStdInput = stdin_handle;
+  }
+  else if (stdih)
+  {
+    if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
+    {
+      SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
+      if (pipe_stdin == NULL)
+        start.hStdInput = stdih;
+    }
+    else
+      SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
+  }
+
+
+  stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
+  GetHandleInformation (stdoh, &stdof);
+  if (NULL != pipe_stdout)
+  {
+    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                       (pipe_stdout,
+                                        GNUNET_DISK_PIPE_END_WRITE),
+                                       &stdout_handle, sizeof (HANDLE));
+    start.hStdOutput = stdout_handle;
+  }
+  else if (stdoh)
+  {
+    if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
+    {
+      SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
+      if (pipe_stdout == NULL)
+        start.hStdOutput = stdoh;
+    }
+    else
+      SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
+  }
+
+  stdeh = GetStdHandle (STD_ERROR_HANDLE);
+  GetHandleInformation (stdeh, &stdef);
+  if (stdeh)
+  {
+    if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
+    {
+      SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
+      start.hStdError = stdeh;
+    }
+    else
+      SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
+  }
 
   if (GNUNET_YES == pipe_control)
   {
 
   if (GNUNET_YES == pipe_control)
   {
-    control_pipe =
-      npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
-                   GNUNET_DISK_PERM_USER_READ |
-                   GNUNET_DISK_PERM_USER_WRITE);
-    if (control_pipe == NULL)
+    struct GNUNET_DISK_PipeHandle *childpipe;
+    childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
+    if (NULL == childpipe)
+      return NULL;
+    childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
+    childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
+    GNUNET_DISK_pipe_close (childpipe);
+    if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
+        (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
+        &childpipe_read_handle, sizeof (HANDLE))))
     {
     {
+      if (childpipe_read)
+        GNUNET_DISK_file_close (childpipe_read);
+      if (childpipe_write)
+        GNUNET_DISK_file_close (childpipe_write);
       GNUNET_free (cmd);
       GNUNET_free (cmd);
-      GNUNET_free (path);
       return NULL;
     }
       return NULL;
     }
+    /* Unlike *nix variant, we don't dup the handle, so can't close
+     * filehandle right now.
+     */
+    SetHandleInformation (childpipe_read_handle, HANDLE_FLAG_INHERIT, 1);
   }
   else
   }
   else
-    control_pipe = NULL;
+  {
+    childpipe_read = NULL;
+    childpipe_write = NULL;
+  }
+
   if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
   {
     lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
   if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
   {
     lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
@@ -1357,8 +1008,12 @@ GNUNET_OS_start_process_v (int pipe_control,
     if (lsocks_pipe == NULL)
     {
       GNUNET_free (cmd);
     if (lsocks_pipe == NULL)
     {
       GNUNET_free (cmd);
-      GNUNET_free (path);
       GNUNET_DISK_pipe_close (lsocks_pipe);
       GNUNET_DISK_pipe_close (lsocks_pipe);
+      if (GNUNET_YES == pipe_control)
+      {
+        GNUNET_DISK_file_close (childpipe_write);
+        GNUNET_DISK_file_close (childpipe_read);
+      }
       return NULL;
     }
     lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
       return NULL;
     }
     lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
@@ -1369,15 +1024,14 @@ GNUNET_OS_start_process_v (int pipe_control,
                                        (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
                                        &lsocks_read, sizeof (HANDLE));
   }
                                        (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
                                        &lsocks_read, sizeof (HANDLE));
   }
+  else
+    lsocks_pipe = NULL;
 
   env_off = 0;
 
   env_off = 0;
-  if (NULL != childpipename)
+  if (GNUNET_YES == pipe_control)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
-        childpipename);
     GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
     GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
-    GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
-    GNUNET_free (childpipename);
+    GNUNET_asprintf (&our_env[env_off++], "%p", childpipe_read_handle);
   }
   if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
   {
   }
   if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
   {
@@ -1389,37 +1043,106 @@ GNUNET_OS_start_process_v (int pipe_control,
   env_block = CreateCustomEnvTable (our_env);
   while (0 > env_off)
     GNUNET_free_non_null (our_env[--env_off]);
   env_block = CreateCustomEnvTable (our_env);
   while (0 > env_off)
     GNUNET_free_non_null (our_env[--env_off]);
-  if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)
-      || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd)
-      || !CreateProcessW
-      (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
-       env_block, NULL, &start, &proc))
+
+  wpath_len = 0;
+  if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
   {
   {
-    SetErrnoFromWinError (GetLastError ());
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
-    if (NULL != control_pipe)
-      GNUNET_DISK_file_close (control_pipe);
-    if (NULL != lsocks)
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
+    GNUNET_free (env_block);
+    GNUNET_free (cmd);
+    if (lsocks_pipe)
       GNUNET_DISK_pipe_close (lsocks_pipe);
       GNUNET_DISK_pipe_close (lsocks_pipe);
+    if (GNUNET_YES == pipe_control)
+    {
+      GNUNET_DISK_file_close (childpipe_write);
+      GNUNET_DISK_file_close (childpipe_read);
+    }
+    return NULL;
+  }
+
+  wcmd_len = 0;
+  if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n",
+         cmd,
+         errno);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
+    free (wpath);
+    if (lsocks_pipe)
+      GNUNET_DISK_pipe_close (lsocks_pipe);
+    if (GNUNET_YES == pipe_control)
+    {
+      GNUNET_DISK_file_close (childpipe_write);
+      GNUNET_DISK_file_close (childpipe_read);
+    }
     return NULL;
   }
 
     return NULL;
   }
 
+  create_no_window = 0;
+  {
+    HANDLE console_input = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+    if (INVALID_HANDLE_VALUE == console_input)
+      create_no_window = CREATE_NO_WINDOW;
+    else
+      CloseHandle (console_input);
+  }
+
+  bresult = CreateProcessW (wpath, wcmd, NULL, NULL, GNUNET_YES,
+       create_no_window | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
+  error_code = GetLastError ();
+
+  if ((NULL == pipe_stdin) && (stdih))
+    SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
+
+
+  if ((NULL == pipe_stdout) && (stdoh))
+    SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
+
+  if (stdeh)
+    SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
+
+  if (!bresult)
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "CreateProcess(%s, %s) failed: %lu\n",
+         path,
+         cmd,
+         error_code);
+
   GNUNET_free (env_block);
   GNUNET_free (env_block);
+  GNUNET_free (cmd);
+  free (wpath);
+  free (wcmd);
+  if (GNUNET_YES == pipe_control)
+  {
+    GNUNET_DISK_file_close (childpipe_read);
+  }
+
+  if (!bresult)
+  {
+    if (GNUNET_YES == pipe_control)
+    {
+      GNUNET_DISK_file_close (childpipe_write);
+    }
+    if (NULL != lsocks)
+      GNUNET_DISK_pipe_close (lsocks_pipe);
+    SetErrnoFromWinError (error_code);
+    return NULL;
+  }
 
 
-  gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
+  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
-  gnunet_proc->control_pipe = control_pipe;
+  gnunet_proc->control_pipe = childpipe_write;
 
   CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
 
   ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
 
   CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
 
   ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
-  GNUNET_free (cmd);
 
 
-  if (lsocks == NULL || lsocks[0] == INVALID_SOCKET)
+  if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
     return gnunet_proc;
 
   GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
     return gnunet_proc;
 
   GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
@@ -1428,16 +1151,20 @@ GNUNET_OS_start_process_v (int pipe_control,
   fail = 1;
   do
   {
   fail = 1;
   do
   {
-    int wrote;
-    uint64_t size, count, i;
+    ssize_t wrote;
+    uint64_t size;
+    uint64_t count;
+    unsigned int i;
 
     /* Tell the number of sockets */
     for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
 
     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
 
     /* Tell the number of sockets */
     for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
 
     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
-    if (wrote != sizeof (count))
+    if (sizeof (count) != wrote)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ());
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 "Failed to write %u count bytes to the child: %u\n",
+                 sizeof (count), GetLastError ());
       break;
     }
     for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
       break;
     }
     for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
@@ -1446,8 +1173,9 @@ GNUNET_OS_start_process_v (int pipe_control,
       /* Get a socket duplication info */
       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
       {
       /* Get a socket duplication info */
       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ());
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to duplicate an socket[%llu]: %u\n", i,
+                   GetLastError ());
         break;
       }
       /* Synchronous I/O is not nice, but we can't schedule this:
         break;
       }
       /* Synchronous I/O is not nice, but we can't schedule this:
@@ -1460,16 +1188,20 @@ GNUNET_OS_start_process_v (int pipe_control,
        */
       size = sizeof (pi);
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
        */
       size = sizeof (pi);
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
-      if (wrote != sizeof (size))
+      if (sizeof (size) != wrote)
       {
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ());
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u size[%llu] bytes to the child: %u\n",
+                   sizeof (size), i, GetLastError ());
         break;
       }
       /* Finally! Send the data */
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
         break;
       }
       /* Finally! Send the data */
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
-      if (wrote != sizeof (pi))
+      if (sizeof (pi) != wrote)
       {
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ());
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u socket[%llu] bytes to the child: %u\n",
+                   sizeof (pi), i, GetLastError ());
         break;
       }
     }
         break;
       }
     }
@@ -1491,7 +1223,7 @@ GNUNET_OS_start_process_v (int pipe_control,
     /* If we can't pass on the socket(s), the child will block forever,
      * better put it out of its misery.
      */
     /* If we can't pass on the socket(s), the child will block forever,
      * better put it out of its misery.
      */
-    TerminateProcess (gnunet_proc->handle, 0);
+    SafeTerminateProcess (gnunet_proc->handle, 0, 0);
     CloseHandle (gnunet_proc->handle);
     if (NULL != gnunet_proc->control_pipe)
       GNUNET_DISK_file_close (gnunet_proc->control_pipe);
     CloseHandle (gnunet_proc->handle);
     if (NULL != gnunet_proc->control_pipe)
       GNUNET_DISK_file_close (gnunet_proc->control_pipe);
@@ -1503,14 +1235,298 @@ GNUNET_OS_start_process_v (int pipe_control,
 }
 
 
 }
 
 
+/**
+ * Start a process.
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
+ * @param pipe_stdin pipe to use to send input to child process (or NULL)
+ * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param pipe_stderr pipe to use to get output from child process (or NULL)
+ * @param filename name of the binary
+ * @param argv NULL-terminated array of arguments to the process
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_vap (int pipe_control,
+                             enum GNUNET_OS_InheritStdioFlags std_inheritance,
+                            struct GNUNET_DISK_PipeHandle *pipe_stdin,
+                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                             struct GNUNET_DISK_PipeHandle *pipe_stderr,
+                            const char *filename,
+                            char *const argv[])
+{
+  return start_process (pipe_control,
+                        std_inheritance,
+                       pipe_stdin,
+                       pipe_stdout,
+                        pipe_stderr,
+                       NULL,
+                       filename,
+                       argv);
+}
+
+
+/**
+ * Start a process.
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
+ * @param pipe_stdin pipe to use to send input to child process (or NULL)
+ * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param pipe_stderr pipe to use to get output from child process (or NULL)
+ * @param filename name of the binary
+ * @param va NULL-terminated list of arguments to the process
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_va (int pipe_control,
+                            enum GNUNET_OS_InheritStdioFlags std_inheritance,
+                           struct GNUNET_DISK_PipeHandle *pipe_stdin,
+                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                            struct GNUNET_DISK_PipeHandle *pipe_stderr,
+                            const char *filename, va_list va)
+{
+  struct GNUNET_OS_Process *ret;
+  va_list ap;
+  char **argv;
+  int argc;
+
+  argc = 0;
+  va_copy (ap, va);
+  while (NULL != va_arg (ap, char *))
+    argc++;
+  va_end (ap);
+  argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
+  argc = 0;
+  va_copy (ap, va);
+  while (NULL != (argv[argc] = va_arg (ap, char *)))
+    argc++;
+  va_end (ap);
+  ret = GNUNET_OS_start_process_vap (pipe_control,
+                                     std_inheritance,
+                                    pipe_stdin,
+                                    pipe_stdout,
+                                     pipe_stderr,
+                                    filename,
+                                    argv);
+  GNUNET_free (argv);
+  return ret;
+}
+
+
+/**
+ * Start a process.
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
+ * @param pipe_stdin pipe to use to send input to child process (or NULL)
+ * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param filename name of the binary
+ * @param ... NULL-terminated list of arguments to the process
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process (int pipe_control,
+                         enum GNUNET_OS_InheritStdioFlags std_inheritance,
+                        struct GNUNET_DISK_PipeHandle *pipe_stdin,
+                         struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                         struct GNUNET_DISK_PipeHandle *pipe_stderr,
+                         const char *filename, ...)
+{
+  struct GNUNET_OS_Process *ret;
+  va_list ap;
+
+  va_start (ap, filename);
+  ret = GNUNET_OS_start_process_va (pipe_control,
+                                    std_inheritance,
+                                    pipe_stdin,
+                                   pipe_stdout,
+                                    pipe_stderr,
+                                    filename,
+                                    ap);
+  va_end (ap);
+  return ret;
+}
+
+
+/**
+ * Start a process.
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
+ *        std handles of the parent are inherited by the child.
+ *        pipe_stdin and pipe_stdout take priority over std_inheritance
+ *        (when they are non-NULL).
+ * @param lsocks array of listen sockets to dup systemd-style (or NULL);
+ *         must be NULL on platforms where dup is not supported
+ * @param filename name of the binary
+ * @param argv NULL-terminated list of arguments to the process
+ * @return process ID of the new process, -1 on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_v (int pipe_control,
+                           enum GNUNET_OS_InheritStdioFlags std_inheritance,
+                          const SOCKTYPE *lsocks,
+                           const char *filename,
+                           char *const argv[])
+{
+  return start_process (pipe_control,
+                        std_inheritance,
+                       NULL,
+                       NULL,
+                        NULL,
+                       lsocks,
+                       filename,
+                       argv);
+}
+
+
+/**
+ * Start a process.  This function is similar to the GNUNET_OS_start_process_*
+ * except that the filename and arguments can have whole strings which contain
+ * the arguments.  These arguments are to be separated by spaces and are parsed
+ * in the order they appear.  Arguments containing spaces can be used by
+ * quoting them with @em ".
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
+ * @param lsocks array of listen sockets to dup systemd-style (or NULL);
+ *         must be NULL on platforms where dup is not supported
+ * @param filename name of the binary.  It is valid to have the arguments
+ *         in this string when they are separated by spaces.
+ * @param ... more arguments.  Should be of type `char *`.  It is valid
+ *         to have the arguments in these strings when they are separated by
+ *         spaces.  The last argument MUST be NULL.
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_s (int pipe_control,
+                           unsigned int std_inheritance,
+                           const SOCKTYPE * lsocks,
+                           const char *filename, ...)
+{
+  va_list ap;
+  char **argv;
+  unsigned int argv_size;
+  const char *arg;
+  const char *rpos;
+  char *pos;
+  char *cp;
+  const char *last;
+  struct GNUNET_OS_Process *proc;
+  char *binary_path;
+  int quote_on;
+  unsigned int i;
+  size_t len;
+
+  argv_size = 1;
+  va_start (ap, filename);
+  arg = filename;
+  last = NULL;
+  do
+  {
+    rpos = arg;
+    quote_on = 0;
+    while ('\0' != *rpos)
+    {
+      if ('"' == *rpos)
+      {
+       if (1 == quote_on)
+         quote_on = 0;
+       else
+         quote_on = 1;
+      }
+      if ( (' ' == *rpos) && (0 == quote_on) )
+      {
+       if (NULL != last)
+         argv_size++;
+       last = NULL;
+       rpos++;
+       while (' ' == *rpos)
+         rpos++;
+      }
+      if ( (NULL == last) && ('\0' != *rpos) ) // FIXME: == or !=?
+       last = rpos;
+      if ('\0' != *rpos)
+       rpos++;
+    }
+    if (NULL != last)
+      argv_size++;
+  }
+  while (NULL != (arg = (va_arg (ap, const char*))));
+  va_end (ap);
+
+  argv = GNUNET_malloc (argv_size * sizeof (char *));
+  argv_size = 0;
+  va_start (ap, filename);
+  arg = filename;
+  last = NULL;
+  do
+  {
+    cp = GNUNET_strdup (arg);
+    quote_on = 0;
+    pos = cp;
+    while ('\0' != *pos)
+    {
+      if ('"' == *pos)
+      {
+       if (1 == quote_on)
+         quote_on = 0;
+       else
+         quote_on = 1;
+      }
+      if ( (' ' == *pos) && (0 == quote_on) )
+      {
+       *pos = '\0';
+       if (NULL != last)
+         argv[argv_size++] = GNUNET_strdup (last);
+       last = NULL;
+       pos++;
+       while (' ' == *pos)
+         pos++;
+      }
+      if ( (NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
+       last = pos;
+      if ('\0' != *pos)
+       pos++;
+    }
+    if (NULL != last)
+      argv[argv_size++] = GNUNET_strdup (last);
+    last = NULL;
+    GNUNET_free (cp);
+  }
+  while (NULL != (arg = (va_arg (ap, const char*))));
+  va_end (ap);
+  argv[argv_size] = NULL;
+
+  for(i = 0; i < argv_size; i++)
+  {
+    len = strlen (argv[i]);
+    if ( (argv[i][0] == '"') && (argv[i][len-1] == '"'))
+    {
+      memmove (&argv[i][0], &argv[i][1], len - 2);
+      argv[i][len-2] = '\0';
+    }
+  }
+  binary_path = argv[0];
+  proc = GNUNET_OS_start_process_v (pipe_control, std_inheritance, lsocks,
+                                   binary_path, argv);
+  while (argv_size > 0)
+    GNUNET_free (argv[--argv_size]);
+  GNUNET_free (argv);
+  return proc;
+}
+
+
 /**
  * Retrieve the status of a process, waiting on him if dead.
  * Nonblocking version.
 /**
  * Retrieve the status of a process, waiting on him if dead.
  * Nonblocking version.
- * 
+ *
  * @param proc process ID
  * @param type status type
  * @param code return code/signal number
  * @param proc process ID
  * @param type status type
  * @param code return code/signal number
- * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
+ * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
  */
 int
 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
  */
 int
 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
@@ -1525,7 +1541,8 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   ret = waitpid (proc->pid, &status, WNOHANG);
   if (ret < 0)
   {
   ret = waitpid (proc->pid, &status, WNOHANG);
   if (ret < 0)
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                  "waitpid");
     return GNUNET_SYSERR;
   }
   if (0 == ret)
     return GNUNET_SYSERR;
   }
   if (0 == ret)
@@ -1574,7 +1591,8 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   ret = proc->pid;
   if (h == NULL || ret == 0)
   {
   ret = proc->pid;
   if (h == NULL || ret == 0)
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Invalid process information {%d, %08X}\n",
          ret, h);
     return GNUNET_SYSERR;
   }
          ret, h);
     return GNUNET_SYSERR;
   }
@@ -1605,49 +1623,51 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 
 
 /**
 
 
 /**
- * Wait for a process
+ * Wait for a process to terminate. The return code is discarded.
+ * You must not use #GNUNET_OS_process_status() on the same process
+ * after calling this function!  This function is blocking and should
+ * thus only be used if the child process is known to have terminated
+ * or to terminate very soon.
+ *
  * @param proc pointer to process structure
  * @param proc pointer to process structure
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
  */
 int
 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 {
  */
 int
 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 {
-
 #ifndef MINGW
   pid_t pid = proc->pid;
   pid_t ret;
 
   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
          (EINTR == errno) ) ;
 #ifndef MINGW
   pid_t pid = proc->pid;
   pid_t ret;
 
   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
          (EINTR == errno) ) ;
-  if (pid != ret) 
+  if (pid != ret)
   {
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                  "waitpid");
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 #else
   HANDLE h;
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 #else
   HANDLE h;
-  int ret;
 
   h = proc->handle;
   if (NULL == h)
   {
 
   h = proc->handle;
   if (NULL == h)
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Invalid process information {%d, %08X}\n",
          proc->pid, h);
     return GNUNET_SYSERR;
   }
          proc->pid, h);
     return GNUNET_SYSERR;
   }
-  if (h == NULL)
+  if (NULL == h)
     h = GetCurrentProcess ();
 
   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
   {
     SetErrnoFromWinError (GetLastError ());
     h = GetCurrentProcess ();
 
   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
   {
     SetErrnoFromWinError (GetLastError ());
-    ret = GNUNET_SYSERR;
+    return GNUNET_SYSERR;
   }
   }
-  else
-    ret = GNUNET_OK;
-
-  return ret;
+  return GNUNET_OK;
 #endif
 }
 
 #endif
 }
 
@@ -1679,7 +1699,7 @@ struct GNUNET_OS_CommandHandle
   GNUNET_OS_LineProcessor proc;
 
   /**
   GNUNET_OS_LineProcessor proc;
 
   /**
-   * Closure for 'proc'.
+   * Closure for @e proc.
    */
   void *proc_cls;
 
    */
   void *proc_cls;
 
@@ -1691,7 +1711,7 @@ struct GNUNET_OS_CommandHandle
   /**
    * Task reading from pipe.
    */
   /**
    * Task reading from pipe.
    */
-  GNUNET_SCHEDULER_TaskIdentifier rtask;
+  struct GNUNET_SCHEDULER_Task *rtask;
 
   /**
    * When to time out.
 
   /**
    * When to time out.
@@ -1715,15 +1735,14 @@ struct GNUNET_OS_CommandHandle
 void
 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
 {
 void
 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
 {
-
-  if (cmd->proc != NULL)
+  if (NULL != cmd->proc)
   {
   {
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
+    GNUNET_assert (NULL != cmd->rtask);
     GNUNET_SCHEDULER_cancel (cmd->rtask);
   }
   (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
   GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
     GNUNET_SCHEDULER_cancel (cmd->rtask);
   }
   (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
   GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
-  GNUNET_OS_process_close (cmd->eip);
+  GNUNET_OS_process_destroy (cmd->eip);
   GNUNET_DISK_pipe_close (cmd->opipe);
   GNUNET_free (cmd);
 }
   GNUNET_DISK_pipe_close (cmd->opipe);
   GNUNET_free (cmd);
 }
@@ -1743,7 +1762,7 @@ cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   char *end;
   ssize_t ret;
 
   char *end;
   ssize_t ret;
 
-  cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
+  cmd->rtask = NULL;
   if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
   {
     /* timeout, shutdown, etc. */
   if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
   {
     /* timeout, shutdown, etc. */
@@ -1769,7 +1788,7 @@ cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   }
   end = memchr (&cmd->buf[cmd->off], '\n', ret);
   cmd->off += ret;
   }
   end = memchr (&cmd->buf[cmd->off], '\n', ret);
   cmd->off += ret;
-  while (end != NULL)
+  while (NULL != end)
   {
     *end = '\0';
     cmd->proc (cmd->proc_cls, cmd->buf);
   {
     *end = '\0';
     cmd->proc (cmd->proc_cls, cmd->buf);
@@ -1788,15 +1807,17 @@ cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * for each line of the output.
  *
  * @param proc function to call for each line of the output
  * for each line of the output.
  *
  * @param proc function to call for each line of the output
- * @param proc_cls closure for proc
+ * @param proc_cls closure for @a proc
  * @param timeout when to time out
  * @param binary command to run
  * @param ... arguments to command
  * @return NULL on error
  */
 struct GNUNET_OS_CommandHandle *
  * @param timeout when to time out
  * @param binary command to run
  * @param ... arguments to command
  * @return NULL on error
  */
 struct GNUNET_OS_CommandHandle *
-GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
-                       struct GNUNET_TIME_Relative timeout, const char *binary,
+GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
+                       void *proc_cls,
+                       struct GNUNET_TIME_Relative timeout,
+                       const char *binary,
                        ...)
 {
   struct GNUNET_OS_CommandHandle *cmd;
                        ...)
 {
   struct GNUNET_OS_CommandHandle *cmd;
@@ -1808,7 +1829,8 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);
-  eip = GNUNET_OS_start_process_va (GNUNET_NO, NULL, opipe, binary, ap);
+  /* redirect stdout, don't inherit stderr/stdin */
+  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, NULL, binary, ap);
   va_end (ap);
   if (NULL == eip)
   {
   va_end (ap);
   if (NULL == eip)
   {
@@ -1816,7 +1838,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
     return NULL;
   }
   GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
     return NULL;
   }
   GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
-  cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
+  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
   cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   cmd->eip = eip;
   cmd->opipe = opipe;
   cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   cmd->eip = eip;
   cmd->opipe = opipe;
@@ -1828,6 +1850,4 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
 }
 
 
 }
 
 
-
-
 /* end of os_priority.c */
 /* end of os_priority.c */