Update plibc header
[oweals/gnunet.git] / src / util / os_priority.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/os_priority.c
23  * @brief Methods to set process priority
24  * @author Nils Durner
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "disk.h"
30 #include <unistr.h>
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
33
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
35
36 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
37
38 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
39
40
41 struct GNUNET_OS_Process
42 {
43   /**
44    * PID of the process.
45    */
46   pid_t pid;
47
48 #if WINDOWS
49   /**
50    * Process handle.
51    */
52   HANDLE handle;
53 #endif
54
55   /**
56    * Pipe we use to signal the process.
57    * NULL if unused, or if process was deemed uncontrollable.
58    */
59   struct GNUNET_DISK_FileHandle *control_pipe;
60 };
61
62
63 /**
64  * Handle for 'this' process.
65  */
66 static struct GNUNET_OS_Process current_process;
67
68
69 /**
70  * This handler is called when there are control data to be read on the pipe
71  *
72  * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe
73  * @param tc scheduler context
74  */
75 static void
76 parent_control_handler (void *cls,
77                         const struct GNUNET_SCHEDULER_TaskContext *tc)
78 {
79   struct GNUNET_DISK_FileHandle *control_pipe = cls;
80   char sig;
81   char *pipe_fd;
82   ssize_t ret;
83
84   LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
85        tc->reason);
86   if (0 != (tc->reason &
87             (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT)))
88   {
89     GNUNET_DISK_file_close (control_pipe);
90     control_pipe = NULL;
91     return;
92   }
93   ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig));
94   if (sizeof (sig) != ret)
95   {
96     if (-1 == ret)
97       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
98     LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
99     GNUNET_DISK_file_close (control_pipe);
100     control_pipe = NULL;
101     return;
102   }
103   pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
104   GNUNET_assert ( (NULL == pipe_fd) || (strlen (pipe_fd) <= 0) );
105   LOG (GNUNET_ERROR_TYPE_DEBUG,
106        "Got control code %d from parent via pipe %s\n", sig, pipe_fd);
107   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
108                                   control_pipe, &parent_control_handler,
109                                   control_pipe);
110   raise ((int) sig);
111 }
112
113
114 /**
115  * Task that connects this process to its parent via pipe;
116  * essentially, the parent control handler will read signal numbers
117  * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment
118  * variable) and raise those signals.
119  *
120  * @param cls closure (unused)
121  * @param tc scheduler context (unused)
122  */
123 void
124 GNUNET_OS_install_parent_control_handler (void *cls,
125                                           const struct
126                                           GNUNET_SCHEDULER_TaskContext *tc)
127 {
128   const char *env_buf;
129   char *env_buf_end;
130   struct GNUNET_DISK_FileHandle *control_pipe;
131   uint64_t pipe_fd;
132
133   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
134   if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
135   {
136     LOG (GNUNET_ERROR_TYPE_DEBUG,
137          "Not installing a handler because $%s is empty\n",
138          GNUNET_OS_CONTROL_PIPE);
139     putenv (GNUNET_OS_CONTROL_PIPE "=");
140     return;
141   }
142   errno = 0;
143   pipe_fd = strtoull (env_buf, &env_buf_end, 16);
144   if ((0 != errno) || (env_buf == env_buf_end))
145   {
146     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
147     putenv (GNUNET_OS_CONTROL_PIPE "=");
148     return;
149   }
150 #if !defined (WINDOWS)
151   if (pipe_fd >= FD_SETSIZE)
152 #else
153   if ((FILE_TYPE_UNKNOWN == GetFileType ((HANDLE) (uintptr_t) pipe_fd))
154       && (0 != GetLastError ()))
155 #endif
156   {
157     LOG (GNUNET_ERROR_TYPE_ERROR,
158          "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n", env_buf);
159     putenv (GNUNET_OS_CONTROL_PIPE "=");
160     return;
161   }
162 #if WINDOWS
163   control_pipe = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) (uintptr_t) pipe_fd);
164 #else
165   control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
166 #endif
167   if (NULL == control_pipe)
168   {
169     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
170     putenv (GNUNET_OS_CONTROL_PIPE "=");
171     return;
172   }
173   LOG (GNUNET_ERROR_TYPE_DEBUG,
174        "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
175   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
176                                   &parent_control_handler, control_pipe);
177   putenv (GNUNET_OS_CONTROL_PIPE "=");
178 }
179
180
181 /**
182  * Get process structure for current process
183  *
184  * The pointer it returns points to static memory location and must not be
185  * deallocated/closed
186  *
187  * @return pointer to the process sturcutre for this process
188  */
189 struct GNUNET_OS_Process *
190 GNUNET_OS_process_current ()
191 {
192 #if WINDOWS
193   current_process.pid = GetCurrentProcessId ();
194   current_process.handle = GetCurrentProcess ();
195 #else
196   current_process.pid = 0;
197 #endif
198   return &current_process;
199 }
200
201
202 /**
203  * Sends a signal to the process
204  *
205  * @param proc pointer to process structure
206  * @param sig signal
207  * @return 0 on success, -1 on error
208  */
209 int
210 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
211 {
212   int ret;
213   char csig;
214
215   csig = (char) sig;
216   if (NULL != proc->control_pipe)
217   {
218     LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via pipe\n", sig, proc->pid);
219     ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
220     if (sizeof (csig) == ret)
221       return 0;
222   }
223   /* pipe failed or non-existent, try other methods */
224   switch (sig)
225   {
226 #if !defined (WINDOWS)
227   case SIGHUP:
228 #endif
229   case SIGINT:
230   case SIGKILL:
231   case SIGTERM:
232 #if defined(WINDOWS) && !defined(__CYGWIN__)
233     {
234       DWORD exitcode;
235       int must_kill = GNUNET_YES;
236       if (0 != GetExitCodeProcess (proc->handle, &exitcode))
237         must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
238       if (GNUNET_YES == must_kill)
239         if (0 == SafeTerminateProcess (proc->handle, 0, 0))
240         {
241           DWORD error_code = GetLastError ();
242           if ((error_code != WAIT_TIMEOUT) && (error_code != ERROR_PROCESS_ABORTED))
243           {
244             LOG ((error_code == ERROR_ACCESS_DENIED) ?
245                 GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
246                 "SafeTermiateProcess failed with code %lu\n", error_code);
247             /* The problem here is that a process that is already dying
248              * might cause SafeTerminateProcess to fail with
249              * ERROR_ACCESS_DENIED, but the process WILL die eventually.
250              * If we really had a permissions problem, hanging up (which
251              * is what will happen in process_wait() in that case) is
252              * a valid option.
253              */
254             if (ERROR_ACCESS_DENIED == error_code)
255             {
256               errno = 0;
257             }
258             else
259             {
260               SetErrnoFromWinError (error_code);
261               return -1;
262             }
263           }
264         }
265     }
266     return 0;
267 #else
268     LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
269     return PLIBC_KILL (proc->pid, sig);
270 #endif
271   default:
272 #if defined (WINDOWS)
273     errno = EINVAL;
274     return -1;
275 #else
276     LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
277     return PLIBC_KILL (proc->pid, sig);
278 #endif
279   }
280 }
281
282 /**
283  * Get the pid of the process in question
284  *
285  * @param proc the process to get the pid of
286  *
287  * @return the current process id
288  */
289 pid_t
290 GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
291 {
292   return proc->pid;
293 }
294
295
296 /**
297  * Cleans up process structure contents (OS-dependent) and deallocates it
298  *
299  * @param proc pointer to process structure
300  */
301 void
302 GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
303 {
304   if (NULL != proc->control_pipe)
305     GNUNET_DISK_file_close (proc->control_pipe);
306 #if defined (WINDOWS)
307   if (proc->handle != NULL)
308     CloseHandle (proc->handle);
309 #endif
310   GNUNET_free (proc);
311 }
312
313 #if WINDOWS
314 #include "gnunet_signal_lib.h"
315
316 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
317
318 /**
319  * Make seaspider happy.
320  */
321 #define DWORD_WINAPI DWORD WINAPI
322
323 /**
324  * @brief Waits for a process to terminate and invokes the SIGCHLD handler
325  * @param proc pointer to process structure
326  */
327 static DWORD_WINAPI
328 child_wait_thread (void *arg)
329 {
330   struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
331
332   WaitForSingleObject (proc->handle, INFINITE);
333
334   if (w32_sigchld_handler)
335     w32_sigchld_handler ();
336
337   return 0;
338 }
339 #endif
340
341
342 #if MINGW
343 static char *
344 CreateCustomEnvTable (char **vars)
345 {
346   char *win32_env_table;
347   char *ptr;
348   char **var_ptr;
349   char *result;
350   char *result_ptr;
351   size_t tablesize = 0;
352   size_t items_count = 0;
353   size_t n_found = 0;
354   size_t n_var;
355   char *index = NULL;
356   size_t c;
357   size_t var_len;
358   char *var;
359   char *val;
360
361   win32_env_table = GetEnvironmentStringsA ();
362   if (NULL == win32_env_table)
363     return NULL;
364   for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
365   n_var = c;
366   index = GNUNET_malloc (sizeof (char *) * n_var);
367   for (c = 0; c < n_var; c++)
368     index[c] = 0;
369   for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
370   {
371     size_t len = strlen (ptr);
372     int found = 0;
373
374     for (var_ptr = vars; *var_ptr; var_ptr++)
375     {
376       var = *var_ptr++;
377       val = *var_ptr;
378       var_len = strlen (var);
379       if (strncmp (var, ptr, var_len) == 0)
380       {
381         found = 1;
382         index[c] = 1;
383         tablesize += var_len + strlen (val) + 1;
384         break;
385       }
386     }
387     if (!found)
388       tablesize += len + 1;
389     ptr += len + 1;
390   }
391   for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
392   {
393     var = *var_ptr++;
394     val = *var_ptr;
395     if (index[c] != 1)
396       n_found += strlen (var) + strlen (val) + 1;
397   }
398   result = GNUNET_malloc (tablesize + n_found + 1);
399   for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
400   {
401     size_t len = strlen (ptr);
402     int found = 0;
403
404     for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
405     {
406       var = *var_ptr++;
407       val = *var_ptr;
408       var_len = strlen (var);
409       if (strncmp (var, ptr, var_len) == 0)
410       {
411         found = 1;
412         break;
413       }
414     }
415     if (!found)
416     {
417       strcpy (result_ptr, ptr);
418       result_ptr += len + 1;
419     }
420     else
421     {
422       strcpy (result_ptr, var);
423       result_ptr += var_len;
424       strcpy (result_ptr, val);
425       result_ptr += strlen (val) + 1;
426     }
427     ptr += len + 1;
428   }
429   for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
430   {
431     var = *var_ptr++;
432     val = *var_ptr;
433     var_len = strlen (var);
434     if (index[c] != 1)
435     {
436       strcpy (result_ptr, var);
437       result_ptr += var_len;
438       strcpy (result_ptr, val);
439       result_ptr += strlen (val) + 1;
440     }
441   }
442   FreeEnvironmentStrings (win32_env_table);
443   GNUNET_free (index);
444   *result_ptr = 0;
445   return result;
446 }
447
448 #else
449
450 /**
451  * Open '/dev/null' and make the result the given
452  * file descriptor.
453  *
454  * @param target_fd desired FD to point to /dev/null
455  * @param flags open flags (O_RDONLY, O_WRONLY)
456  */
457 static void
458 open_dev_null (int target_fd,
459                int flags)
460 {
461   int fd;
462
463   fd = open ("/dev/null", flags);
464   if (-1 == fd)
465   {
466     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
467     return;
468   }
469   if (fd == target_fd)
470     return;
471   if (-1 == dup2 (fd, target_fd))
472   {
473     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
474     (void) close (fd);
475     return;
476   }
477   GNUNET_break (0 == close (fd));
478 }
479 #endif
480
481
482 /**
483  * Start a process.
484  *
485  * @param pipe_control should a pipe be used to send signals to the child?
486  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
487  *        std handles of the parent are inherited by the child.
488  *        pipe_stdin and pipe_stdout take priority over std_inheritance
489  *        (when they are non-NULL).
490  * @param pipe_stdin pipe to use to send input to child process (or NULL)
491  * @param pipe_stdout pipe to use to get output from child process (or NULL)
492  * @param lsocks array of listen sockets to dup systemd-style (or NULL);
493  *         must be NULL on platforms where dup is not supported
494  * @param filename name of the binary
495  * @param argv NULL-terminated list of arguments to the process
496  * @return process ID of the new process, -1 on error
497  */
498 static struct GNUNET_OS_Process *
499 start_process (int pipe_control,
500                enum GNUNET_OS_InheritStdioFlags std_inheritance,
501                struct GNUNET_DISK_PipeHandle *pipe_stdin,
502                struct GNUNET_DISK_PipeHandle *pipe_stdout,
503                const SOCKTYPE *lsocks,
504                const char *filename,
505                char *const argv[])
506 {
507 #ifndef MINGW
508   pid_t ret;
509   char fds[16];
510   struct GNUNET_OS_Process *gnunet_proc;
511   struct GNUNET_DISK_FileHandle *childpipe_read;
512   struct GNUNET_DISK_FileHandle *childpipe_write;
513   int childpipe_read_fd;
514   int i;
515   int j;
516   int k;
517   int tgt;
518   int flags;
519   int *lscp;
520   unsigned int ls;
521   int fd_stdout_write;
522   int fd_stdout_read;
523   int fd_stdin_read;
524   int fd_stdin_write;
525
526   if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
527     return NULL; /* not executable */
528   if (GNUNET_YES == pipe_control)
529   {
530     struct GNUNET_DISK_PipeHandle *childpipe;
531     int dup_childpipe_read_fd = -1;
532
533     childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
534     if (NULL == childpipe)
535       return NULL;
536     childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
537     childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
538     GNUNET_DISK_pipe_close (childpipe);
539     if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
540         (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
541         &childpipe_read_fd, sizeof (int))) ||
542         (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
543     {
544       if (NULL != childpipe_read)
545         GNUNET_DISK_file_close (childpipe_read);
546       if (NULL != childpipe_write)
547         GNUNET_DISK_file_close (childpipe_write);
548       if (0 <= dup_childpipe_read_fd)
549         close (dup_childpipe_read_fd);
550       return NULL;
551     }
552     childpipe_read_fd = dup_childpipe_read_fd;
553     GNUNET_DISK_file_close (childpipe_read);
554   }
555   else
556   {
557     childpipe_write = NULL;
558     childpipe_read_fd = -1;
559   }
560   if (NULL != pipe_stdout)
561   {
562     GNUNET_assert (GNUNET_OK ==
563                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
564                                                       (pipe_stdout,
565                                                        GNUNET_DISK_PIPE_END_WRITE),
566                                                       &fd_stdout_write, sizeof (int)));
567     GNUNET_assert (GNUNET_OK ==
568                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
569                                                       (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
570                                                       &fd_stdout_read, sizeof (int)));
571   }
572   if (NULL != pipe_stdin)
573   {
574     GNUNET_assert (GNUNET_OK ==
575                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
576                                                       (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
577                                                       &fd_stdin_read, sizeof (int)));
578     GNUNET_assert (GNUNET_OK ==
579                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
580                                                       (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
581                                                       &fd_stdin_write, sizeof (int)));
582   }
583   lscp = NULL;
584   ls = 0;
585   if (NULL != lsocks)
586   {
587     i = 0;
588     while (-1 != (k = lsocks[i++]))
589       GNUNET_array_append (lscp, ls, k);
590     GNUNET_array_append (lscp, ls, -1);
591   }
592 #if DARWIN
593   /* see https://gnunet.org/vfork */
594   ret = vfork ();
595 #else
596   ret = fork ();
597 #endif
598   if (-1 == ret)
599   {
600     int eno = errno;
601     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
602     GNUNET_array_grow (lscp, ls, 0);
603     if (NULL != childpipe_write)
604       GNUNET_DISK_file_close (childpipe_write);
605     if (0 <= childpipe_read_fd)
606       close (childpipe_read_fd);
607     errno = eno;
608     return NULL;
609   }
610   if (0 != ret)
611   {
612     unsetenv (GNUNET_OS_CONTROL_PIPE);
613     gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
614     gnunet_proc->pid = ret;
615     gnunet_proc->control_pipe = childpipe_write;
616     if (GNUNET_YES == pipe_control)
617     {
618       close (childpipe_read_fd);
619     }
620     GNUNET_array_grow (lscp, ls, 0);
621     return gnunet_proc;
622   }
623   if (0 <= childpipe_read_fd)
624   {
625     char fdbuf[100];
626 #ifndef DARWIN
627     /* due to vfork, we must NOT free memory on DARWIN! */
628     GNUNET_DISK_file_close (childpipe_write);
629 #endif
630     snprintf (fdbuf, 100, "%x", childpipe_read_fd);
631     setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
632   }
633   else
634     unsetenv (GNUNET_OS_CONTROL_PIPE);
635   if (NULL != pipe_stdin)
636   {
637     GNUNET_break (0 == close (fd_stdin_write));
638     if (-1 == dup2 (fd_stdin_read, 0))
639       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
640     GNUNET_break (0 == close (fd_stdin_read));
641   }
642   else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
643   {
644     GNUNET_break (0 == close (0));
645     open_dev_null (0, O_RDONLY);
646   }
647   if (NULL != pipe_stdout)
648   {
649     GNUNET_break (0 == close (fd_stdout_read));
650     if (-1 == dup2 (fd_stdout_write, 1))
651       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
652     GNUNET_break (0 == close (fd_stdout_write));
653   }
654   else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
655   {
656     GNUNET_break (0 == close (1));
657     open_dev_null (1, O_WRONLY);
658   }
659   if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
660   {
661     GNUNET_break (0 == close (2));
662     open_dev_null (2, O_WRONLY);
663   }
664   if (NULL != lscp)
665   {
666     /* read systemd documentation... */
667     i = 0;
668     tgt = 3;
669     while (-1 != lscp[i])
670     {
671       j = i + 1;
672       while (-1 != lscp[j])
673       {
674         if (lscp[j] == tgt)
675         {
676           /* dup away */
677           k = dup (lscp[j]);
678           GNUNET_assert (-1 != k);
679           GNUNET_assert (0 == close (lscp[j]));
680           lscp[j] = k;
681           break;
682         }
683         j++;
684       }
685       if (lscp[i] != tgt)
686       {
687         /* Bury any existing FD, no matter what; they should all be closed
688          * on exec anyway and the important onces have been dup'ed away */
689         (void) close (tgt);
690         GNUNET_assert (-1 != dup2 (lscp[i], tgt));
691       }
692       /* unset close-on-exec flag */
693       flags = fcntl (tgt, F_GETFD);
694       GNUNET_assert (flags >= 0);
695       flags &= ~FD_CLOEXEC;
696       fflush (stderr);
697       (void) fcntl (tgt, F_SETFD, flags);
698       tgt++;
699       i++;
700     }
701     GNUNET_snprintf (fds, sizeof (fds), "%u", i);
702     setenv ("LISTEN_FDS", fds, 1);
703   }
704 #ifndef DARWIN
705   /* due to vfork, we must NOT free memory on DARWIN! */
706   GNUNET_array_grow (lscp, ls, 0);
707 #endif
708   execvp (filename, argv);
709   LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
710   _exit (1);
711 #else
712   struct GNUNET_DISK_FileHandle *childpipe_read;
713   struct GNUNET_DISK_FileHandle *childpipe_write;
714   HANDLE childpipe_read_handle;
715   char **arg;
716   char **non_const_argv;
717   unsigned int cmdlen;
718   char *cmd;
719   char *idx;
720   STARTUPINFOW start;
721   PROCESS_INFORMATION proc;
722   int argcount = 0;
723   struct GNUNET_OS_Process *gnunet_proc;
724   char path[MAX_PATH + 1];
725   char *our_env[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
726   char *env_block = NULL;
727   char *pathbuf;
728   DWORD pathbuf_len;
729   DWORD alloc_len;
730   char *self_prefix;
731   char *bindir;
732   char *libdir;
733   char *ptr;
734   char *non_const_filename;
735   char win_path[MAX_PATH + 1];
736   struct GNUNET_DISK_PipeHandle *lsocks_pipe;
737   const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
738   HANDLE lsocks_read;
739   HANDLE lsocks_write;
740   wchar_t *wpath;
741   wchar_t *wcmd;
742   size_t wpath_len;
743   size_t wcmd_len;
744   int env_off;
745   int fail;
746   long lRet;
747   HANDLE stdin_handle;
748   HANDLE stdout_handle;
749   HANDLE stdih, stdoh, stdeh;
750   DWORD stdif, stdof, stdef;
751   BOOL bresult;
752   DWORD error_code;
753
754   if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
755     return NULL; /* not executable */
756
757   /* Search in prefix dir (hopefully - the directory from which
758    * the current module was loaded), bindir and libdir, then in PATH
759    */
760   self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
761   bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
762   libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
763
764   pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
765
766   alloc_len =
767       pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
768       strlen (libdir);
769
770   pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
771
772   ptr = pathbuf;
773   ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
774   GNUNET_free (self_prefix);
775   GNUNET_free (bindir);
776   GNUNET_free (libdir);
777
778   alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
779   if (alloc_len != pathbuf_len - 1)
780   {
781     GNUNET_free (pathbuf);
782     errno = ENOSYS;             /* PATH changed on the fly. What kind of error is that? */
783     return NULL;
784   }
785
786   cmdlen = strlen (filename);
787   if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
788     GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
789   else
790     GNUNET_asprintf (&non_const_filename, "%s", filename);
791
792   /* It could be in POSIX form, convert it to a DOS path early on */
793   if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
794   {
795     SetErrnoFromWinError (lRet);
796     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
797                        non_const_filename);
798     GNUNET_free (non_const_filename);
799     GNUNET_free (pathbuf);
800     return NULL;
801   }
802   GNUNET_free (non_const_filename);
803   non_const_filename = GNUNET_strdup (win_path);
804    /* Check that this is the full path. If it isn't, search. */
805   /* FIXME: convert it to wchar_t and use SearchPathW?
806    * Remember: arguments to _start_process() are technically in UTF-8...
807    */
808   if (non_const_filename[1] == ':')
809   {
810     snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
811     LOG (GNUNET_ERROR_TYPE_DEBUG,
812         "Using path `%s' as-is. PATH is %s\n", path, ptr);
813   }
814   else if (!SearchPathA
815            (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
816             path, NULL))
817   {
818     SetErrnoFromWinError (GetLastError ());
819     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
820                        non_const_filename);
821     GNUNET_free (non_const_filename);
822     GNUNET_free (pathbuf);
823     return NULL;
824   }
825   else
826     LOG (GNUNET_ERROR_TYPE_DEBUG,
827         "Found `%s' in PATH `%s'\n", path, pathbuf);
828   GNUNET_free (pathbuf);
829   GNUNET_free (non_const_filename);
830
831   /* Count the number of arguments */
832   arg = (char **) argv;
833   while (*arg)
834   {
835     arg++;
836     argcount++;
837   }
838
839   /* Allocate a copy argv */
840   non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
841
842   /* Copy all argv strings */
843   argcount = 0;
844   arg = (char **) argv;
845   while (*arg)
846   {
847     if (arg == argv)
848       non_const_argv[argcount] = GNUNET_strdup (path);
849     else
850       non_const_argv[argcount] = GNUNET_strdup (*arg);
851     arg++;
852     argcount++;
853   }
854   non_const_argv[argcount] = NULL;
855
856   /* Count cmd len */
857   cmdlen = 1;
858   arg = non_const_argv;
859   while (*arg)
860   {
861     cmdlen = cmdlen + strlen (*arg) + 4;
862     arg++;
863   }
864
865   /* Allocate and create cmd */
866   cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
867   arg = non_const_argv;
868   while (*arg)
869   {
870     char arg_last_char = (*arg)[strlen (*arg) - 1];
871     idx += sprintf (idx, "\"%s%s\"%s", *arg,
872         arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
873     arg++;
874   }
875
876   while (argcount > 0)
877     GNUNET_free (non_const_argv[--argcount]);
878   GNUNET_free (non_const_argv);
879
880   memset (&start, 0, sizeof (start));
881   start.cb = sizeof (start);
882   if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
883     start.dwFlags |= STARTF_USESTDHANDLES;
884
885   stdih = GetStdHandle (STD_INPUT_HANDLE);
886   GetHandleInformation (stdih, &stdif);
887   if (pipe_stdin != NULL)
888   {
889     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
890                                        (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
891                                        &stdin_handle, sizeof (HANDLE));
892     start.hStdInput = stdin_handle;
893   }
894   else if (stdih)
895   {
896     if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
897     {
898       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
899       if (pipe_stdin == NULL)
900         start.hStdInput = stdih;
901     }
902     else
903       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
904   }
905
906
907   stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
908   GetHandleInformation (stdoh, &stdof);
909   if (NULL != pipe_stdout)
910   {
911     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
912                                        (pipe_stdout,
913                                         GNUNET_DISK_PIPE_END_WRITE),
914                                        &stdout_handle, sizeof (HANDLE));
915     start.hStdOutput = stdout_handle;
916   }
917   else if (stdoh)
918   {
919     if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
920     {
921       SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
922       if (pipe_stdout == NULL)
923         start.hStdOutput = stdoh;
924     }
925     else
926       SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
927   }
928
929   stdeh = GetStdHandle (STD_ERROR_HANDLE);
930   GetHandleInformation (stdeh, &stdef);
931   if (stdeh)
932   {
933     if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
934     {
935       SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
936       start.hStdError = stdeh;
937     }
938     else
939       SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
940   }
941
942   if (GNUNET_YES == pipe_control)
943   {
944     struct GNUNET_DISK_PipeHandle *childpipe;
945     childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
946     if (NULL == childpipe)
947       return NULL;
948     childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
949     childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
950     GNUNET_DISK_pipe_close (childpipe);
951     if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
952         (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
953         &childpipe_read_handle, sizeof (HANDLE))))
954     {
955       if (childpipe_read)
956         GNUNET_DISK_file_close (childpipe_read);
957       if (childpipe_write)
958         GNUNET_DISK_file_close (childpipe_write);
959       GNUNET_free (cmd);
960       return NULL;
961     }
962     /* Unlike *nix variant, we don't dup the handle, so can't close
963      * filehandle right now.
964      */
965     SetHandleInformation (childpipe_read_handle, HANDLE_FLAG_INHERIT, 1);
966   }
967   else
968   {
969     childpipe_read = NULL;
970     childpipe_write = NULL;
971   }
972
973   if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
974   {
975     lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
976
977     if (lsocks_pipe == NULL)
978     {
979       GNUNET_free (cmd);
980       GNUNET_DISK_pipe_close (lsocks_pipe);
981       if (GNUNET_YES == pipe_control)
982       {
983         GNUNET_DISK_file_close (childpipe_write);
984         GNUNET_DISK_file_close (childpipe_read);
985       }
986       return NULL;
987     }
988     lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
989         GNUNET_DISK_PIPE_END_WRITE);
990     GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
991                                        &lsocks_write, sizeof (HANDLE));
992     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
993                                        (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
994                                        &lsocks_read, sizeof (HANDLE));
995   }
996   else
997     lsocks_pipe = NULL;
998
999   env_off = 0;
1000   if (GNUNET_YES == pipe_control)
1001   {
1002     GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1003     GNUNET_asprintf (&our_env[env_off++], "%p", childpipe_read_handle);
1004   }
1005   if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1006   {
1007     /*This will tell the child that we're going to send lsocks over the pipe*/
1008     GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1009     GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1010   }
1011   our_env[env_off++] = NULL;
1012   env_block = CreateCustomEnvTable (our_env);
1013   while (0 > env_off)
1014     GNUNET_free_non_null (our_env[--env_off]);
1015
1016   wpath_len = 0;
1017   if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1018   {
1019     LOG (GNUNET_ERROR_TYPE_DEBUG,
1020         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1021     GNUNET_free (env_block);
1022     GNUNET_free (cmd);
1023     if (lsocks_pipe)
1024       GNUNET_DISK_pipe_close (lsocks_pipe);
1025     if (GNUNET_YES == pipe_control)
1026     {
1027       GNUNET_DISK_file_close (childpipe_write);
1028       GNUNET_DISK_file_close (childpipe_read);
1029     }
1030     return NULL;
1031   }
1032
1033   wcmd_len = 0;
1034   if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1035   {
1036     LOG (GNUNET_ERROR_TYPE_DEBUG,
1037         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1038     GNUNET_free (env_block);
1039     GNUNET_free (cmd);
1040     free (wpath);
1041     if (lsocks_pipe)
1042       GNUNET_DISK_pipe_close (lsocks_pipe);
1043     if (GNUNET_YES == pipe_control)
1044     {
1045       GNUNET_DISK_file_close (childpipe_write);
1046       GNUNET_DISK_file_close (childpipe_read);
1047     }
1048     return NULL;
1049   }
1050
1051   bresult = CreateProcessW (wpath, wcmd, NULL, NULL, GNUNET_YES,
1052        CREATE_NO_WINDOW | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1053   error_code = GetLastError ();
1054
1055   if ((NULL == pipe_stdin) && (stdih))
1056     SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1057
1058
1059   if ((NULL == pipe_stdout) && (stdoh))
1060     SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1061
1062   if (stdeh)
1063     SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1064
1065   if (!bresult)
1066     LOG (GNUNET_ERROR_TYPE_ERROR, "CreateProcess(%s, %s) failed: %lu\n", path, cmd, error_code);
1067
1068   GNUNET_free (env_block);
1069   GNUNET_free (cmd);
1070   free (wpath);
1071   free (wcmd);
1072   if (GNUNET_YES == pipe_control)
1073   {
1074     GNUNET_DISK_file_close (childpipe_read);
1075   }
1076
1077   if (!bresult)
1078   {
1079     if (GNUNET_YES == pipe_control)
1080     {
1081       GNUNET_DISK_file_close (childpipe_write);
1082     }
1083     if (NULL != lsocks)
1084       GNUNET_DISK_pipe_close (lsocks_pipe);
1085     SetErrnoFromWinError (error_code);
1086     return NULL;
1087   }
1088
1089   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1090   gnunet_proc->pid = proc.dwProcessId;
1091   gnunet_proc->handle = proc.hProcess;
1092   gnunet_proc->control_pipe = childpipe_write;
1093
1094   CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1095
1096   ResumeThread (proc.hThread);
1097   CloseHandle (proc.hThread);
1098
1099   if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
1100     return gnunet_proc;
1101
1102   GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1103
1104   /* This is a replacement for "goto error" that doesn't use goto */
1105   fail = 1;
1106   do
1107   {
1108     ssize_t wrote;
1109     uint64_t size;
1110     uint64_t count;
1111     unsigned int i;
1112
1113     /* Tell the number of sockets */
1114     for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1115
1116     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1117     if (sizeof (count) != wrote)
1118     {
1119       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1120                   "Failed to write %u count bytes to the child: %u\n",
1121                   sizeof (count), GetLastError ());
1122       break;
1123     }
1124     for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1125     {
1126       WSAPROTOCOL_INFOA pi;
1127       /* Get a socket duplication info */
1128       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1129       {
1130         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131                     "Failed to duplicate an socket[%llu]: %u\n", i,
1132                     GetLastError ());
1133         break;
1134       }
1135       /* Synchronous I/O is not nice, but we can't schedule this:
1136        * lsocks will be closed/freed by the caller soon, and until
1137        * the child creates a duplicate, closing a socket here will
1138        * close it for good.
1139        */
1140       /* Send the size of the structure
1141        * (the child might be built with different headers...)
1142        */
1143       size = sizeof (pi);
1144       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1145       if (sizeof (size) != wrote)
1146       {
1147         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1148                     "Failed to write %u size[%llu] bytes to the child: %u\n",
1149                     sizeof (size), i, GetLastError ());
1150         break;
1151       }
1152       /* Finally! Send the data */
1153       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1154       if (sizeof (pi) != wrote)
1155       {
1156         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1157                     "Failed to write %u socket[%llu] bytes to the child: %u\n",
1158                     sizeof (pi), i, GetLastError ());
1159         break;
1160       }
1161     }
1162     /* This will block us until the child makes a final read or closes
1163      * the pipe (hence no 'wrote' check), since we have to wait for it
1164      * to duplicate the last socket, before we return and start closing
1165      * our own copies)
1166      */
1167     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1168     fail = 0;
1169   }
1170   while (fail);
1171
1172   GNUNET_DISK_file_sync (lsocks_write_fd);
1173   GNUNET_DISK_pipe_close (lsocks_pipe);
1174
1175   if (fail)
1176   {
1177     /* If we can't pass on the socket(s), the child will block forever,
1178      * better put it out of its misery.
1179      */
1180     SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1181     CloseHandle (gnunet_proc->handle);
1182     if (NULL != gnunet_proc->control_pipe)
1183       GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1184     GNUNET_free (gnunet_proc);
1185     return NULL;
1186   }
1187   return gnunet_proc;
1188 #endif
1189 }
1190
1191
1192
1193
1194 /**
1195  * Start a process.
1196  *
1197  * @param pipe_control should a pipe be used to send signals to the child?
1198  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1199  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1200  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1201  * @param filename name of the binary
1202  * @param argv NULL-terminated array of arguments to the process
1203  * @return pointer to process structure of the new process, NULL on error
1204  */
1205 struct GNUNET_OS_Process *
1206 GNUNET_OS_start_process_vap (int pipe_control,
1207                              enum GNUNET_OS_InheritStdioFlags std_inheritance,
1208                              struct GNUNET_DISK_PipeHandle *pipe_stdin,
1209                              struct GNUNET_DISK_PipeHandle *pipe_stdout,
1210                              const char *filename,
1211                              char *const argv[])
1212 {
1213   return start_process (pipe_control,
1214                         std_inheritance,
1215                         pipe_stdin,
1216                         pipe_stdout,
1217                         NULL,
1218                         filename,
1219                         argv);
1220 }
1221
1222
1223 /**
1224  * Start a process.
1225  *
1226  * @param pipe_control should a pipe be used to send signals to the child?
1227  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1228  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1229  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1230  * @param filename name of the binary
1231  * @param va NULL-terminated list of arguments to the process
1232  * @return pointer to process structure of the new process, NULL on error
1233  */
1234 struct GNUNET_OS_Process *
1235 GNUNET_OS_start_process_va (int pipe_control,
1236                             enum GNUNET_OS_InheritStdioFlags std_inheritance,
1237                             struct GNUNET_DISK_PipeHandle *pipe_stdin,
1238                             struct GNUNET_DISK_PipeHandle *pipe_stdout,
1239                             const char *filename, va_list va)
1240 {
1241   struct GNUNET_OS_Process *ret;
1242   va_list ap;
1243   char **argv;
1244   int argc;
1245
1246   argc = 0;
1247   va_copy (ap, va);
1248   while (NULL != va_arg (ap, char *))
1249     argc++;
1250   va_end (ap);
1251   argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1252   argc = 0;
1253   va_copy (ap, va);
1254   while (NULL != (argv[argc] = va_arg (ap, char *)))
1255     argc++;
1256   va_end (ap);
1257   ret = GNUNET_OS_start_process_vap (pipe_control,
1258                                      std_inheritance,
1259                                      pipe_stdin,
1260                                      pipe_stdout,
1261                                      filename,
1262                                      argv);
1263   GNUNET_free (argv);
1264   return ret;
1265 }
1266
1267
1268 /**
1269  * Start a process.
1270  *
1271  * @param pipe_control should a pipe be used to send signals to the child?
1272  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1273  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1274  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1275  * @param filename name of the binary
1276  * @param ... NULL-terminated list of arguments to the process
1277  * @return pointer to process structure of the new process, NULL on error
1278  */
1279 struct GNUNET_OS_Process *
1280 GNUNET_OS_start_process (int pipe_control,
1281                          enum GNUNET_OS_InheritStdioFlags std_inheritance,
1282                          struct GNUNET_DISK_PipeHandle *pipe_stdin,
1283                          struct GNUNET_DISK_PipeHandle *pipe_stdout,
1284                          const char *filename, ...)
1285 {
1286   struct GNUNET_OS_Process *ret;
1287   va_list ap;
1288
1289   va_start (ap, filename);
1290   ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1291                                     pipe_stdout, filename, ap);
1292   va_end (ap);
1293   return ret;
1294 }
1295
1296
1297 /**
1298  * Start a process.
1299  *
1300  * @param pipe_control should a pipe be used to send signals to the child?
1301  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
1302  *        std handles of the parent are inherited by the child.
1303  *        pipe_stdin and pipe_stdout take priority over std_inheritance
1304  *        (when they are non-NULL).
1305  * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1306  *         must be NULL on platforms where dup is not supported
1307  * @param filename name of the binary
1308  * @param argv NULL-terminated list of arguments to the process
1309  * @return process ID of the new process, -1 on error
1310  */
1311 struct GNUNET_OS_Process *
1312 GNUNET_OS_start_process_v (int pipe_control,
1313                            enum GNUNET_OS_InheritStdioFlags std_inheritance,
1314                            const SOCKTYPE *lsocks,
1315                            const char *filename,
1316                            char *const argv[])
1317 {
1318   return start_process (pipe_control,
1319                         std_inheritance,
1320                         NULL,
1321                         NULL,
1322                         lsocks,
1323                         filename,
1324                         argv);
1325 }
1326
1327
1328 /**
1329  * Retrieve the status of a process, waiting on him if dead.
1330  * Nonblocking version.
1331  *
1332  * @param proc process ID
1333  * @param type status type
1334  * @param code return code/signal number
1335  * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1336  */
1337 int
1338 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1339                           enum GNUNET_OS_ProcessStatusType *type,
1340                           unsigned long *code)
1341 {
1342 #ifndef MINGW
1343   int status;
1344   int ret;
1345
1346   GNUNET_assert (0 != proc);
1347   ret = waitpid (proc->pid, &status, WNOHANG);
1348   if (ret < 0)
1349   {
1350     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1351     return GNUNET_SYSERR;
1352   }
1353   if (0 == ret)
1354   {
1355     *type = GNUNET_OS_PROCESS_RUNNING;
1356     *code = 0;
1357     return GNUNET_NO;
1358   }
1359   if (proc->pid != ret)
1360   {
1361     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1362     return GNUNET_SYSERR;
1363   }
1364   if (WIFEXITED (status))
1365   {
1366     *type = GNUNET_OS_PROCESS_EXITED;
1367     *code = WEXITSTATUS (status);
1368   }
1369   else if (WIFSIGNALED (status))
1370   {
1371     *type = GNUNET_OS_PROCESS_SIGNALED;
1372     *code = WTERMSIG (status);
1373   }
1374   else if (WIFSTOPPED (status))
1375   {
1376     *type = GNUNET_OS_PROCESS_SIGNALED;
1377     *code = WSTOPSIG (status);
1378   }
1379 #ifdef WIFCONTINUED
1380   else if (WIFCONTINUED (status))
1381   {
1382     *type = GNUNET_OS_PROCESS_RUNNING;
1383     *code = 0;
1384   }
1385 #endif
1386   else
1387   {
1388     *type = GNUNET_OS_PROCESS_UNKNOWN;
1389     *code = 0;
1390   }
1391 #else
1392   HANDLE h;
1393   DWORD c, error_code, ret;
1394
1395   h = proc->handle;
1396   ret = proc->pid;
1397   if (h == NULL || ret == 0)
1398   {
1399     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1400          ret, h);
1401     return GNUNET_SYSERR;
1402   }
1403   if (h == NULL)
1404     h = GetCurrentProcess ();
1405
1406   SetLastError (0);
1407   ret = GetExitCodeProcess (h, &c);
1408   error_code = GetLastError ();
1409   if (ret == 0 || error_code != NO_ERROR)
1410   {
1411     SetErrnoFromWinError (error_code);
1412     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1413     return GNUNET_SYSERR;
1414   }
1415   if (STILL_ACTIVE == c)
1416   {
1417     *type = GNUNET_OS_PROCESS_RUNNING;
1418     *code = 0;
1419     return GNUNET_NO;
1420   }
1421   *type = GNUNET_OS_PROCESS_EXITED;
1422   *code = c;
1423 #endif
1424
1425   return GNUNET_OK;
1426 }
1427
1428
1429 /**
1430  * Wait for a process
1431  *
1432  * @param proc pointer to process structure
1433  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1434  */
1435 int
1436 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1437 {
1438 #ifndef MINGW
1439   pid_t pid = proc->pid;
1440   pid_t ret;
1441
1442   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1443           (EINTR == errno) ) ;
1444   if (pid != ret)
1445   {
1446     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1447     return GNUNET_SYSERR;
1448   }
1449   return GNUNET_OK;
1450 #else
1451   HANDLE h;
1452
1453   h = proc->handle;
1454   if (NULL == h)
1455   {
1456     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1457          proc->pid, h);
1458     return GNUNET_SYSERR;
1459   }
1460   if (NULL == h)
1461     h = GetCurrentProcess ();
1462
1463   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1464   {
1465     SetErrnoFromWinError (GetLastError ());
1466     return GNUNET_SYSERR;
1467   }
1468   return GNUNET_OK;
1469 #endif
1470 }
1471
1472
1473 /**
1474  * Handle to a command.
1475  */
1476 struct GNUNET_OS_CommandHandle
1477 {
1478
1479   /**
1480    * Process handle.
1481    */
1482   struct GNUNET_OS_Process *eip;
1483
1484   /**
1485    * Handle to the output pipe.
1486    */
1487   struct GNUNET_DISK_PipeHandle *opipe;
1488
1489   /**
1490    * Read-end of output pipe.
1491    */
1492   const struct GNUNET_DISK_FileHandle *r;
1493
1494   /**
1495    * Function to call on each line of output.
1496    */
1497   GNUNET_OS_LineProcessor proc;
1498
1499   /**
1500    * Closure for 'proc'.
1501    */
1502   void *proc_cls;
1503
1504   /**
1505    * Buffer for the output.
1506    */
1507   char buf[1024];
1508
1509   /**
1510    * Task reading from pipe.
1511    */
1512   GNUNET_SCHEDULER_TaskIdentifier rtask;
1513
1514   /**
1515    * When to time out.
1516    */
1517   struct GNUNET_TIME_Absolute timeout;
1518
1519   /**
1520    * Current read offset in buf.
1521    */
1522   size_t off;
1523 };
1524
1525
1526 /**
1527  * Stop/kill a command.  Must ONLY be called either from
1528  * the callback after 'NULL' was passed for 'line' *OR*
1529  * from an independent task (not within the line processor).
1530  *
1531  * @param cmd handle to the process
1532  */
1533 void
1534 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1535 {
1536   if (NULL != cmd->proc)
1537   {
1538     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1539     GNUNET_SCHEDULER_cancel (cmd->rtask);
1540   }
1541   (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1542   GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1543   GNUNET_OS_process_destroy (cmd->eip);
1544   GNUNET_DISK_pipe_close (cmd->opipe);
1545   GNUNET_free (cmd);
1546 }
1547
1548
1549 /**
1550  * Read from the process and call the line processor.
1551  *
1552  * @param cls the 'struct GNUNET_OS_CommandHandle'
1553  * @param tc scheduler context
1554  */
1555 static void
1556 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1557 {
1558   struct GNUNET_OS_CommandHandle *cmd = cls;
1559   GNUNET_OS_LineProcessor proc;
1560   char *end;
1561   ssize_t ret;
1562
1563   cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1564   if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1565   {
1566     /* timeout, shutdown, etc. */
1567     proc = cmd->proc;
1568     cmd->proc = NULL;
1569     proc (cmd->proc_cls, NULL);
1570     return;
1571   }
1572   ret =
1573       GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1574                              sizeof (cmd->buf) - cmd->off);
1575   if (ret <= 0)
1576   {
1577     if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1578     {
1579       cmd->buf[cmd->off] = '\0';
1580       cmd->proc (cmd->proc_cls, cmd->buf);
1581     }
1582     proc = cmd->proc;
1583     cmd->proc = NULL;
1584     proc (cmd->proc_cls, NULL);
1585     return;
1586   }
1587   end = memchr (&cmd->buf[cmd->off], '\n', ret);
1588   cmd->off += ret;
1589   while (NULL != end)
1590   {
1591     *end = '\0';
1592     cmd->proc (cmd->proc_cls, cmd->buf);
1593     memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1594     cmd->off -= (end + 1 - cmd->buf);
1595     end = memchr (cmd->buf, '\n', cmd->off);
1596   }
1597   cmd->rtask =
1598       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1599                                       (cmd->timeout), cmd->r, &cmd_read, cmd);
1600 }
1601
1602
1603 /**
1604  * Run the given command line and call the given function
1605  * for each line of the output.
1606  *
1607  * @param proc function to call for each line of the output
1608  * @param proc_cls closure for proc
1609  * @param timeout when to time out
1610  * @param binary command to run
1611  * @param ... arguments to command
1612  * @return NULL on error
1613  */
1614 struct GNUNET_OS_CommandHandle *
1615 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1616                        struct GNUNET_TIME_Relative timeout, const char *binary,
1617                        ...)
1618 {
1619   struct GNUNET_OS_CommandHandle *cmd;
1620   struct GNUNET_OS_Process *eip;
1621   struct GNUNET_DISK_PipeHandle *opipe;
1622   va_list ap;
1623
1624   opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1625   if (NULL == opipe)
1626     return NULL;
1627   va_start (ap, binary);
1628   /* redirect stdout, don't inherit stderr/stdin */
1629   eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1630   va_end (ap);
1631   if (NULL == eip)
1632   {
1633     GNUNET_DISK_pipe_close (opipe);
1634     return NULL;
1635   }
1636   GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1637   cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1638   cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1639   cmd->eip = eip;
1640   cmd->opipe = opipe;
1641   cmd->proc = proc;
1642   cmd->proc_cls = proc_cls;
1643   cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1644   cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1645   return cmd;
1646 }
1647
1648
1649 /* end of os_priority.c */