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