expand GNUNET_OS_ProjectData API to also enable de-duplcation of logic for --help
[oweals/gnunet.git] / src / util / os_priority.c
index 12dba6a6bd92a8337eec8be7d95c90679309fb8e..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 <unistr.h>
 
 #include "disk.h"
 #include <unistr.h>
 
@@ -84,7 +80,7 @@ parent_control_handler (void *cls,
   char sig;
   char *pipe_fd;
   ssize_t ret;
   char sig;
   char *pipe_fd;
   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 &
@@ -99,7 +95,7 @@ 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_WARNING, "Closing control pipe\n");
+    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;
@@ -111,7 +107,7 @@ parent_control_handler (void *cls,
   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);
 }
 
 
 }
 
 
@@ -233,6 +229,9 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   case SIGINT:
   case SIGKILL:
   case SIGTERM:
   case SIGINT:
   case SIGKILL:
   case SIGTERM:
+#if (SIGTERM != GNUNET_TERM_SIG)
+  case GNUNET_TERM_SIG:
+#endif
 #if defined(WINDOWS) && !defined(__CYGWIN__)
     {
       DWORD exitcode;
 #if defined(WINDOWS) && !defined(__CYGWIN__)
     {
       DWORD exitcode;
@@ -269,7 +268,10 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
     }
     return 0;
 #else
     }
     return 0;
 #else
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
+    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:
@@ -279,7 +281,7 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 #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);
 #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    
+#endif
   }
 }
 
   }
 }
 
@@ -308,7 +310,7 @@ GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
   if (NULL != proc->control_pipe)
     GNUNET_DISK_file_close (proc->control_pipe);
 #if defined (WINDOWS)
   if (NULL != proc->control_pipe)
     GNUNET_DISK_file_close (proc->control_pipe);
 #if defined (WINDOWS)
-  if (proc->handle != NULL)
+  if (NULL != proc->handle)
     CloseHandle (proc->handle);
 #endif
   GNUNET_free (proc);
     CloseHandle (proc->handle);
 #endif
   GNUNET_free (proc);
@@ -343,112 +345,6 @@ 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 (GNUNET_SCHEDULER_PRIORITY_KEEP == prio)
-    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)
@@ -599,6 +495,7 @@ open_dev_null (int target_fd,
  *        (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)
  *        (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_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 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
@@ -610,13 +507,13 @@ start_process (int pipe_control,
                enum GNUNET_OS_InheritStdioFlags std_inheritance,
               struct GNUNET_DISK_PipeHandle *pipe_stdin,
               struct GNUNET_DISK_PipeHandle *pipe_stdout,
                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
   pid_t ret;
               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;
   struct GNUNET_DISK_FileHandle *childpipe_read;
   char fds[16];
   struct GNUNET_OS_Process *gnunet_proc;
   struct GNUNET_DISK_FileHandle *childpipe_read;
@@ -631,6 +528,8 @@ start_process (int pipe_control,
   unsigned int ls;
   int fd_stdout_write;
   int fd_stdout_read;
   unsigned int ls;
   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;
 
@@ -640,6 +539,7 @@ start_process (int pipe_control,
   {
     struct GNUNET_DISK_PipeHandle *childpipe;
     int dup_childpipe_read_fd = -1;
   {
     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 = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
     if (NULL == childpipe)
       return NULL;
@@ -651,9 +551,9 @@ start_process (int pipe_control,
         &childpipe_read_fd, sizeof (int))) ||
         (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
     {
         &childpipe_read_fd, sizeof (int))) ||
         (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
     {
-      if (childpipe_read)
+      if (NULL != childpipe_read)
         GNUNET_DISK_file_close (childpipe_read);
         GNUNET_DISK_file_close (childpipe_read);
-      if (childpipe_write)
+      if (NULL != childpipe_write)
         GNUNET_DISK_file_close (childpipe_write);
       if (0 <= dup_childpipe_read_fd)
         close (dup_childpipe_read_fd);
         GNUNET_DISK_file_close (childpipe_write);
       if (0 <= dup_childpipe_read_fd)
         close (dup_childpipe_read_fd);
@@ -664,10 +564,20 @@ start_process (int pipe_control,
   }
   else
   {
   }
   else
   {
-    childpipe_read = NULL;
     childpipe_write = NULL;
     childpipe_read_fd = -1;
   }
     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 ==
   if (NULL != pipe_stdout)
   {
     GNUNET_assert (GNUNET_OK ==
@@ -680,16 +590,18 @@ start_process (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 (NULL != pipe_stdin)
+  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;
   }
   lscp = NULL;
   ls = 0;
@@ -711,9 +623,7 @@ start_process (int pipe_control,
     int eno = errno;
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
     GNUNET_array_grow (lscp, ls, 0);
     int eno = errno;
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
     GNUNET_array_grow (lscp, ls, 0);
-    if (childpipe_read)
-      GNUNET_DISK_file_close (childpipe_read);
-    if (childpipe_write)
+    if (NULL != childpipe_write)
       GNUNET_DISK_file_close (childpipe_write);
     if (0 <= childpipe_read_fd)
       close (childpipe_read_fd);
       GNUNET_DISK_file_close (childpipe_write);
     if (0 <= childpipe_read_fd)
       close (childpipe_read_fd);
@@ -723,7 +633,7 @@ start_process (int pipe_control,
   if (0 != ret)
   {
     unsetenv (GNUNET_OS_CONTROL_PIPE);
   if (0 != ret)
   {
     unsetenv (GNUNET_OS_CONTROL_PIPE);
-    gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
+    gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
     gnunet_proc->pid = ret;
     gnunet_proc->control_pipe = childpipe_write;
     if (GNUNET_YES == pipe_control)
     gnunet_proc->pid = ret;
     gnunet_proc->control_pipe = childpipe_write;
     if (GNUNET_YES == pipe_control)
@@ -769,7 +679,14 @@ start_process (int pipe_control,
     GNUNET_break (0 == close (1));
     open_dev_null (1, O_WRONLY);
   }
     GNUNET_break (0 == close (1));
     open_dev_null (1, O_WRONLY);
   }
-  if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
+  if (NULL != pipe_stderr)
+  {
+    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));
+  }
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
   {
     GNUNET_break (0 == close (2));
     open_dev_null (2, O_WRONLY);
   {
     GNUNET_break (0 == close (2));
     open_dev_null (2, O_WRONLY);
@@ -777,8 +694,6 @@ start_process (int pipe_control,
   if (NULL != lscp)
   {
     /* read systemd documentation... */
   if (NULL != lscp)
   {
     /* 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])
@@ -865,10 +780,11 @@ start_process (int pipe_control,
   DWORD stdif, stdof, stdef;
   BOOL bresult;
   DWORD error_code;
   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 */
 
   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
    */
@@ -1017,7 +933,7 @@ start_process (int pipe_control,
     else
       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
   }
     else
       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
   }
-    
+
 
   stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
   GetHandleInformation (stdoh, &stdof);
 
   stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
   GetHandleInformation (stdoh, &stdof);
@@ -1149,7 +1065,9 @@ start_process (int pipe_control,
   if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   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);
+         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n",
+         cmd,
+         errno);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     free (wpath);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     free (wpath);
@@ -1163,13 +1081,22 @@ start_process (int pipe_control,
     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,
   bresult = CreateProcessW (wpath, wcmd, NULL, NULL, GNUNET_YES,
-       DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
+       create_no_window | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
   error_code = GetLastError ();
 
   if ((NULL == pipe_stdin) && (stdih))
     SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
   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 ((NULL == pipe_stdout) && (stdoh))
     SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
@@ -1178,7 +1105,11 @@ start_process (int pipe_control,
     SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
 
   if (!bresult)
     SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
 
   if (!bresult)
-    LOG (GNUNET_ERROR_TYPE_ERROR, "CreateProcess(%s, %s) failed: %lu\n", path, cmd, error_code);
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "CreateProcess(%s, %s) failed: %lu\n",
+         path,
+         cmd,
+         error_code);
 
   GNUNET_free (env_block);
   GNUNET_free (cmd);
 
   GNUNET_free (env_block);
   GNUNET_free (cmd);
@@ -1201,7 +1132,7 @@ start_process (int pipe_control,
     return NULL;
   }
 
     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->control_pipe = childpipe_write;
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = childpipe_write;
@@ -1231,7 +1162,7 @@ start_process (int pipe_control,
     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
     if (sizeof (count) != wrote)
     {
     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
     if (sizeof (count) != wrote)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Failed to write %u count bytes to the child: %u\n",
                  sizeof (count), GetLastError ());
       break;
                  "Failed to write %u count bytes to the child: %u\n",
                  sizeof (count), GetLastError ());
       break;
@@ -1242,8 +1173,8 @@ start_process (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, 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to duplicate an socket[%llu]: %u\n", i,
                    GetLastError ());
         break;
       }
                    GetLastError ());
         break;
       }
@@ -1259,8 +1190,8 @@ start_process (int pipe_control,
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
       if (sizeof (size) != wrote)
       {
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
       if (sizeof (size) != wrote)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                   "Failed to write %u size[%llu] bytes to the child: %u\n", 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u size[%llu] bytes to the child: %u\n",
                    sizeof (size), i, GetLastError ());
         break;
       }
                    sizeof (size), i, GetLastError ());
         break;
       }
@@ -1268,8 +1199,8 @@ start_process (int pipe_control,
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
       if (sizeof (pi) != wrote)
       {
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
       if (sizeof (pi) != wrote)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                   "Failed to write %u socket[%llu] bytes to the child: %u\n", 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u socket[%llu] bytes to the child: %u\n",
                    sizeof (pi), i, GetLastError ());
         break;
       }
                    sizeof (pi), i, GetLastError ());
         break;
       }
@@ -1304,8 +1235,6 @@ start_process (int pipe_control,
 }
 
 
 }
 
 
-
-
 /**
  * Start a process.
  *
 /**
  * Start a process.
  *
@@ -1313,6 +1242,7 @@ start_process (int pipe_control,
  * @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 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
  * @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
@@ -1322,13 +1252,15 @@ 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,
                              enum GNUNET_OS_InheritStdioFlags std_inheritance,
                             struct GNUNET_DISK_PipeHandle *pipe_stdin,
                             struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                            const char *filename, 
+                             struct GNUNET_DISK_PipeHandle *pipe_stderr,
+                            const char *filename,
                             char *const argv[])
 {
   return start_process (pipe_control,
                         std_inheritance,
                        pipe_stdin,
                        pipe_stdout,
                             char *const argv[])
 {
   return start_process (pipe_control,
                         std_inheritance,
                        pipe_stdin,
                        pipe_stdout,
+                        pipe_stderr,
                        NULL,
                        filename,
                        argv);
                        NULL,
                        filename,
                        argv);
@@ -1342,6 +1274,7 @@ GNUNET_OS_start_process_vap (int pipe_control,
  * @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 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
  * @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
@@ -1351,6 +1284,7 @@ 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,
                             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;
                             const char *filename, va_list va)
 {
   struct GNUNET_OS_Process *ret;
@@ -1373,6 +1307,7 @@ GNUNET_OS_start_process_va (int pipe_control,
                                      std_inheritance,
                                     pipe_stdin,
                                     pipe_stdout,
                                      std_inheritance,
                                     pipe_stdin,
                                     pipe_stdout,
+                                     pipe_stderr,
                                     filename,
                                     argv);
   GNUNET_free (argv);
                                     filename,
                                     argv);
   GNUNET_free (argv);
@@ -1396,14 +1331,20 @@ 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,
                          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);
                          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, filename, ap);
+  ret = GNUNET_OS_start_process_va (pipe_control,
+                                    std_inheritance,
+                                    pipe_stdin,
+                                   pipe_stdout,
+                                    pipe_stderr,
+                                    filename,
+                                    ap);
   va_end (ap);
   return ret;
 }
   va_end (ap);
   return ret;
 }
@@ -1434,20 +1375,158 @@ GNUNET_OS_start_process_v (int pipe_control,
                         std_inheritance,
                        NULL,
                        NULL,
                         std_inheritance,
                        NULL,
                        NULL,
+                        NULL,
                        lsocks,
                        filename,
                        argv);
 }
 
 
                        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,
@@ -1462,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)
@@ -1511,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;
   }
@@ -1542,10 +1623,14 @@ 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)
@@ -1556,9 +1641,10 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 
   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
          (EINTR == errno) ) ;
 
   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;
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -1568,7 +1654,8 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
   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;
   }
@@ -1612,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;
 
@@ -1624,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.
@@ -1650,7 +1737,7 @@ GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
 {
   if (NULL != cmd->proc)
   {
 {
   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_SCHEDULER_cancel (cmd->rtask);
   }
   (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
@@ -1675,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. */
@@ -1720,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;
@@ -1741,7 +1830,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
     return NULL;
   va_start (ap, binary);
   /* redirect stdout, don't inherit stderr/stdin */
     return NULL;
   va_start (ap, binary);
   /* redirect stdout, don't inherit stderr/stdin */
-  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
+  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)
   {
@@ -1749,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;