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