-code deduplication in rsa sign/verify code
[oweals/gnunet.git] / src / util / os_priority.c
index cafb1504c1fef5640c65c98772ccb189f46c13cc..20d54341dbea9bfc6d5c4f8681006d1ebf1e381e 100644 (file)
@@ -79,7 +79,8 @@ static struct GNUNET_OS_Process current_process;
 /**
  * Creates a named pipe/FIFO and opens it
  *
- * @param fn pointer to the name of the named pipe or to NULL
+ * @param fn pointer to the name of the named pipe or to NULL,
+ *           possibly updated to the new name (or free'd)
  * @param flags open flags
  * @param perm access permissions
  * @return pipe handle on success, NULL on error
@@ -103,12 +104,12 @@ npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
     openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
 
-  while (h == NULL)
+  while (NULL == h)
   {
     DWORD error_code;
 
     name = NULL;
-    if (*fn != NULL)
+    if (NULL != *fn)
     {
       GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn);
       LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -134,25 +135,22 @@ npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
                            NULL);
     }
     error_code = GetLastError ();
-    if (name)
-      GNUNET_free (name);
+    GNUNET_free_non_null (name);
     /* don't re-set name to NULL yet */
-    if (h == INVALID_HANDLE_VALUE)
+    if (INVALID_HANDLE_VALUE == h)
     {
       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)
+      if (NULL != *fn)
       {
         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;
-        }
+        if ( (ERROR_ACCESS_DENIED != error_code) && (ERROR_PIPE_BUSY != error_code) )        
+          return NULL;        
         LOG (GNUNET_ERROR_TYPE_DEBUG,
              "Pipe name was not unique, trying again\n");
         h = NULL;
@@ -161,11 +159,9 @@ npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
         return NULL;
     }
   }
-  errno = 0;
-
-  ret = GNUNET_malloc (sizeof (*ret));
+  ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
   ret->h = h;
-  ret->type = GNUNET_PIPE;
+  ret->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
   ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
   ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
   ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
@@ -198,15 +194,15 @@ npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags)
 
   h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
                   FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
-  if (h == INVALID_HANDLE_VALUE)
+  if (INVALID_HANDLE_VALUE == h)
   {
     SetErrnoFromWinError (GetLastError ());
     return NULL;
   }
 
-  ret = GNUNET_malloc (sizeof (*ret));
+  ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
   ret->h = h;
-  ret->type = GNUNET_PIPE;
+  ret->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
   ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
   ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
   ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
@@ -374,7 +370,7 @@ GNUNET_OS_install_parent_control_handler (void *cls,
   struct GNUNET_DISK_FileHandle *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",
@@ -442,7 +438,7 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   if (NULL != proc->control_pipe)
   {
     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 */
@@ -455,10 +451,38 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   case SIGKILL:
   case SIGTERM:
 #if WINDOWS && !defined(__CYGWIN__)
-    if (0 == TerminateProcess (proc->handle, 0))
     {
-      /* 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
@@ -557,7 +581,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
   int rprio;
 
   GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
-  if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
+  if (GNUNET_SCHEDULER_PRIORITY_KEEP == prio)
     return GNUNET_OK;
 
   /* convert to MINGW/Unix values */
@@ -669,7 +693,7 @@ CreateCustomEnvTable (char **vars)
   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;
@@ -754,6 +778,38 @@ CreateCustomEnvTable (char **vars)
   *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
 
 
@@ -761,6 +817,10 @@ CreateCustomEnvTable (char **vars)
  * 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 lsocks array of listen sockets to dup systemd-style (or NULL);
@@ -771,6 +831,7 @@ CreateCustomEnvTable (char **vars)
  */
 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,
               const SOCKTYPE *lsocks,
@@ -781,7 +842,7 @@ start_process (int pipe_control,
   pid_t ret;
   char lpid[16];
   char fds[16];
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_OS_Process *gnunet_proc;
   char *childpipename = NULL;
   int i;
   int j;
@@ -795,10 +856,15 @@ start_process (int pipe_control,
   int fd_stdin_read;
   int fd_stdin_write;
 
+  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
+    return NULL; /* not executable */
   if ( (GNUNET_YES == pipe_control) &&
        (GNUNET_OK != npipe_setup (&childpipename)) )
-    return NULL;  
-  if (pipe_stdout != NULL)
+  {
+    GNUNET_free (childpipename);
+    return NULL;
+  }
+  if (NULL != pipe_stdout)
   {
     GNUNET_assert (GNUNET_OK ==
                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
@@ -810,7 +876,7 @@ start_process (int pipe_control,
                                                      (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
                                                      &fd_stdout_read, sizeof (int)));
   }
-  if (pipe_stdin != NULL)
+  if (NULL != pipe_stdin)
   {
     GNUNET_assert (GNUNET_OK ==
                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
@@ -823,7 +889,7 @@ start_process (int pipe_control,
   }
   lscp = NULL;
   ls = 0;
-  if (lsocks != NULL)
+  if (NULL != lsocks)
   {
     i = 0;
     while (-1 != (k = lsocks[i++]))
@@ -854,22 +920,36 @@ start_process (int pipe_control,
     setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
     GNUNET_free (childpipename);
   }
-  if (pipe_stdout != NULL)
+  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));
+  }
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
+  {
+    GNUNET_break (0 == close (0));
+    open_dev_null (0, O_RDONLY);
+  }
+  if (NULL != pipe_stdout)
   {
     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));
   }
-  if (pipe_stdin != NULL)
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
   {
-
-    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 (1));
+    open_dev_null (1, O_WRONLY);
   }
-  if (lscp != NULL)
+  if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
+  {
+    GNUNET_break (0 == close (2));
+    open_dev_null (2, O_WRONLY);
+  }
+  if (NULL != lscp)
   {
     /* read systemd documentation... */
     GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
@@ -916,7 +996,7 @@ start_process (int pipe_control,
   LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
   _exit (1);
 #else
-  struct GNUNET_DISK_FileHandle *control_pipe = NULL;
+  struct GNUNET_DISK_FileHandle *control_pipe;
   char *childpipename = NULL;
   char **arg;
   char **non_const_argv;
@@ -926,7 +1006,7 @@ start_process (int pipe_control,
   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 *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
   char *env_block = NULL;
@@ -952,6 +1032,13 @@ start_process (int pipe_control,
   long lRet;
   HANDLE stdin_handle;
   HANDLE stdout_handle;
+  HANDLE stdih, stdoh, stdeh;
+  DWORD stdif, stdof, stdef;
+  BOOL bresult;
+  DWORD error_code;
+
+  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
+    return NULL; /* not executable */
  
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
@@ -983,7 +1070,7 @@ start_process (int pipe_control,
   }
 
   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);
@@ -1071,9 +1158,11 @@ start_process (int pipe_control,
 
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
-  if ((pipe_stdin != NULL) || (pipe_stdout != NULL))
+  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
@@ -1081,8 +1170,22 @@ start_process (int pipe_control,
                                        &stdin_handle, sizeof (HANDLE));
     start.hStdInput = stdin_handle;
   }
+  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);
+  }
+    
 
-  if (pipe_stdout != NULL)
+  stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
+  GetHandleInformation (stdoh, &stdof);
+  if (NULL != pipe_stdout)
   {
     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
                                        (pipe_stdout,
@@ -1090,6 +1193,30 @@ start_process (int pipe_control,
                                        &stdout_handle, sizeof (HANDLE));
     start.hStdOutput = stdout_handle;
   }
+  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)
   {
@@ -1167,24 +1294,36 @@ start_process (int pipe_control,
     return NULL;
   }
 
-  if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
-       DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc))
+  bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
+       DETACHED_PROCESS | 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);
+
+  GNUNET_free (env_block);
+  GNUNET_free (cmd);
+  free (wpath);
+  free (wcmd);
+
+  if (!bresult)
   {
-    SetErrnoFromWinError (GetLastError ());
+    SetErrnoFromWinError (error_code);
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
     if (NULL != control_pipe)
       GNUNET_DISK_file_close (control_pipe);
     if (NULL != lsocks)
       GNUNET_DISK_pipe_close (lsocks_pipe);
-    GNUNET_free (env_block);
-    GNUNET_free (cmd);
-    free (wpath);
-    free (wcmd);
     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;
@@ -1194,11 +1333,8 @@ start_process (int pipe_control,
 
   ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
-  GNUNET_free (cmd);
-  free (wpath);
-  free (wcmd);
 
-  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);
@@ -1207,16 +1343,20 @@ start_process (int pipe_control,
   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));
-    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++)
@@ -1225,8 +1365,9 @@ start_process (int pipe_control,
       /* 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:
@@ -1239,16 +1380,20 @@ start_process (int pipe_control,
        */
       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));
-      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;
       }
     }
@@ -1270,7 +1415,7 @@ start_process (int pipe_control,
     /* 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);
@@ -1288,6 +1433,7 @@ start_process (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 filename name of the binary
@@ -1296,12 +1442,14 @@ start_process (int pipe_control,
  */
 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,
                             const char *filename, 
                             char *const argv[])
 {
   return start_process (pipe_control,
+                        std_inheritance,
                        pipe_stdin,
                        pipe_stdout,
                        NULL,
@@ -1314,6 +1462,7 @@ GNUNET_OS_start_process_vap (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 filename name of the binary
@@ -1322,6 +1471,7 @@ GNUNET_OS_start_process_vap (int pipe_control,
  */
 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,
                             const char *filename, va_list va)
@@ -1343,6 +1493,7 @@ GNUNET_OS_start_process_va (int pipe_control,
     argc++;
   va_end (ap);
   ret = GNUNET_OS_start_process_vap (pipe_control,
+                                     std_inheritance,
                                     pipe_stdin,
                                     pipe_stdout,
                                     filename,
@@ -1352,21 +1503,20 @@ GNUNET_OS_start_process_va (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 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,
                          const char *filename, ...)
@@ -1375,7 +1525,8 @@ GNUNET_OS_start_process (int pipe_control,
   va_list ap;
 
   va_start (ap, filename);
-  ret = GNUNET_OS_start_process_va (pipe_control, pipe_stdin, pipe_stdout, filename, ap);
+  ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
+                                   pipe_stdout, filename, ap);
   va_end (ap);
   return ret;
 }
@@ -1385,6 +1536,10 @@ GNUNET_OS_start_process (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 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
@@ -1393,11 +1548,13 @@ GNUNET_OS_start_process (int pipe_control,
  */
 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,
                        lsocks,
@@ -1509,13 +1666,13 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 
 /**
  * Wait for a process
+ *
  * @param proc pointer to process structure
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
 int
 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 {
-
 #ifndef MINGW
   pid_t pid = proc->pid;
   pid_t ret;
@@ -1530,7 +1687,6 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
   return GNUNET_OK;
 #else
   HANDLE h;
-  int ret;
 
   h = proc->handle;
   if (NULL == h)
@@ -1539,18 +1695,15 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
          proc->pid, h);
     return GNUNET_SYSERR;
   }
-  if (h == NULL)
+  if (NULL == h)
     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
 }
 
@@ -1618,8 +1771,7 @@ struct GNUNET_OS_CommandHandle
 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_SCHEDULER_cancel (cmd->rtask);
@@ -1672,7 +1824,7 @@ cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   }
   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);
@@ -1711,7 +1863,8 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
   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, binary, ap);
   va_end (ap);
   if (NULL == eip)
   {
@@ -1731,6 +1884,4 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
 }
 
 
-
-
 /* end of os_priority.c */