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