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