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