-typo
[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     return NULL;  
864   if (NULL != pipe_stdout)
865   {
866     GNUNET_assert (GNUNET_OK ==
867                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
868                                                       (pipe_stdout,
869                                                        GNUNET_DISK_PIPE_END_WRITE),
870                                                       &fd_stdout_write, sizeof (int)));
871     GNUNET_assert (GNUNET_OK ==
872                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
873                                                       (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
874                                                       &fd_stdout_read, sizeof (int)));
875   }
876   if (NULL != pipe_stdin)
877   {
878     GNUNET_assert (GNUNET_OK ==
879                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
880                                                       (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
881                                                       &fd_stdin_read, sizeof (int)));
882     GNUNET_assert (GNUNET_OK ==
883                    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
884                                                       (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
885                                                       &fd_stdin_write, sizeof (int)));
886   }
887   lscp = NULL;
888   ls = 0;
889   if (NULL != lsocks)
890   {
891     i = 0;
892     while (-1 != (k = lsocks[i++]))
893       GNUNET_array_append (lscp, ls, k);
894     GNUNET_array_append (lscp, ls, -1);
895   }
896   ret = fork ();
897   if (-1 == ret)
898   {
899     int eno = errno;
900
901     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
902     GNUNET_free_non_null (childpipename);
903     GNUNET_array_grow (lscp, ls, 0);
904     errno = eno;
905     return NULL;
906   }
907   if (0 != ret)
908   {
909     gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
910     gnunet_proc->pid = ret;
911     gnunet_proc->childpipename = childpipename;  
912     GNUNET_array_grow (lscp, ls, 0);
913     return gnunet_proc;
914   }
915   if (NULL != childpipename)
916   {
917     setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
918     GNUNET_free (childpipename);
919   }
920   if (NULL != pipe_stdin)
921   {
922     GNUNET_break (0 == close (fd_stdin_write));
923     if (-1 == dup2 (fd_stdin_read, 0))
924       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
925     GNUNET_break (0 == close (fd_stdin_read));
926   }
927   else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
928   {
929     GNUNET_break (0 == close (0));
930     open_dev_null (0, O_RDONLY);
931   }
932   if (NULL != pipe_stdout)
933   {
934     GNUNET_break (0 == close (fd_stdout_read));
935     if (-1 == dup2 (fd_stdout_write, 1))
936       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
937     GNUNET_break (0 == close (fd_stdout_write));
938   }
939   else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
940   {
941     GNUNET_break (0 == close (1));
942     open_dev_null (1, O_WRONLY);
943   }
944   if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
945   {
946     GNUNET_break (0 == close (2));
947     open_dev_null (2, O_WRONLY);
948   }
949   if (NULL != lscp)
950   {
951     /* read systemd documentation... */
952     GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
953     setenv ("LISTEN_PID", lpid, 1);
954     i = 0;
955     tgt = 3;
956     while (-1 != lscp[i])
957     {
958       j = i + 1;
959       while (-1 != lscp[j])
960       {
961         if (lscp[j] == tgt)
962         {
963           /* dup away */
964           k = dup (lscp[j]);
965           GNUNET_assert (-1 != k);
966           GNUNET_assert (0 == close (lscp[j]));
967           lscp[j] = k;
968           break;
969         }
970         j++;
971       }
972       if (lscp[i] != tgt)
973       {
974         /* Bury any existing FD, no matter what; they should all be closed
975          * on exec anyway and the important onces have been dup'ed away */
976         (void) close (tgt);
977         GNUNET_assert (-1 != dup2 (lscp[i], tgt));
978       }
979       /* unset close-on-exec flag */
980       flags = fcntl (tgt, F_GETFD);
981       GNUNET_assert (flags >= 0);
982       flags &= ~FD_CLOEXEC;
983       fflush (stderr);
984       (void) fcntl (tgt, F_SETFD, flags);
985       tgt++;
986       i++;
987     }
988     GNUNET_snprintf (fds, sizeof (fds), "%u", i);
989     setenv ("LISTEN_FDS", fds, 1);
990   }
991   GNUNET_array_grow (lscp, ls, 0);
992   execvp (filename, argv);
993   LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
994   _exit (1);
995 #else
996   struct GNUNET_DISK_FileHandle *control_pipe;
997   char *childpipename = NULL;
998   char **arg;
999   char **non_const_argv;
1000   unsigned int cmdlen;
1001   char *cmd;
1002   char *idx;
1003   STARTUPINFOW start;
1004   PROCESS_INFORMATION proc;
1005   int argcount = 0;
1006   struct GNUNET_OS_Process *gnunet_proc;
1007   char path[MAX_PATH + 1];
1008   char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
1009   char *env_block = NULL;
1010   char *pathbuf;
1011   DWORD pathbuf_len;
1012   DWORD alloc_len;
1013   char *self_prefix;
1014   char *bindir;
1015   char *libdir;
1016   char *ptr;
1017   char *non_const_filename;
1018   char win_path[MAX_PATH + 1];
1019   struct GNUNET_DISK_PipeHandle *lsocks_pipe;
1020   const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
1021   HANDLE lsocks_read;
1022   HANDLE lsocks_write;
1023   wchar_t *wpath;
1024   wchar_t *wcmd;
1025   size_t wpath_len;
1026   size_t wcmd_len;
1027   int env_off;
1028   int fail;
1029   long lRet;
1030   HANDLE stdin_handle;
1031   HANDLE stdout_handle;
1032   HANDLE stdih, stdoh, stdeh;
1033   DWORD stdif, stdof, stdef;
1034   BOOL bresult;
1035   DWORD error_code;
1036
1037   if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
1038     return NULL; /* not executable */
1039  
1040   /* Search in prefix dir (hopefully - the directory from which
1041    * the current module was loaded), bindir and libdir, then in PATH
1042    */
1043   self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
1044   bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
1045   libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
1046
1047   pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
1048
1049   alloc_len =
1050       pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
1051       strlen (libdir);
1052
1053   pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
1054
1055   ptr = pathbuf;
1056   ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
1057   GNUNET_free (self_prefix);
1058   GNUNET_free (bindir);
1059   GNUNET_free (libdir);
1060
1061   alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
1062   if (alloc_len != pathbuf_len - 1)
1063   {
1064     GNUNET_free (pathbuf);
1065     errno = ENOSYS;             /* PATH changed on the fly. What kind of error is that? */
1066     return NULL;
1067   }
1068
1069   cmdlen = strlen (filename);
1070   if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
1071     GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
1072   else
1073     GNUNET_asprintf (&non_const_filename, "%s", filename);
1074
1075   /* It could be in POSIX form, convert it to a DOS path early on */
1076   if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
1077   {
1078     SetErrnoFromWinError (lRet);
1079     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
1080                        non_const_filename);
1081     GNUNET_free (non_const_filename);
1082     GNUNET_free (pathbuf);
1083     return NULL;
1084   }
1085   GNUNET_free (non_const_filename);
1086   non_const_filename = GNUNET_strdup (win_path);
1087    /* Check that this is the full path. If it isn't, search. */
1088   /* FIXME: convert it to wchar_t and use SearchPathW?
1089    * Remember: arguments to _start_process() are technically in UTF-8...
1090    */
1091   if (non_const_filename[1] == ':')
1092     snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
1093   else if (!SearchPathA
1094            (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
1095             path, NULL))
1096   {
1097     SetErrnoFromWinError (GetLastError ());
1098     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
1099                        non_const_filename);
1100     GNUNET_free (non_const_filename);
1101     GNUNET_free (pathbuf);
1102     return NULL;
1103   }
1104   GNUNET_free (pathbuf);
1105   GNUNET_free (non_const_filename);
1106
1107   /* Count the number of arguments */
1108   arg = (char **) argv;
1109   while (*arg)
1110   {
1111     arg++;
1112     argcount++;
1113   }
1114
1115   /* Allocate a copy argv */
1116   non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
1117
1118   /* Copy all argv strings */
1119   argcount = 0;
1120   arg = (char **) argv;
1121   while (*arg)
1122   {
1123     if (arg == argv)
1124       non_const_argv[argcount] = GNUNET_strdup (path);
1125     else
1126       non_const_argv[argcount] = GNUNET_strdup (*arg);
1127     arg++;
1128     argcount++;
1129   }
1130   non_const_argv[argcount] = NULL;
1131
1132   /* Count cmd len */
1133   cmdlen = 1;
1134   arg = non_const_argv;
1135   while (*arg)
1136   {
1137     cmdlen = cmdlen + strlen (*arg) + 4;
1138     arg++;
1139   }
1140
1141   /* Allocate and create cmd */
1142   cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
1143   arg = non_const_argv;
1144   while (*arg)
1145   {
1146     char arg_last_char = (*arg)[strlen (*arg) - 1];
1147     idx += sprintf (idx, "\"%s%s\"%s", *arg,
1148         arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
1149     arg++;
1150   }
1151
1152   while (argcount > 0)
1153     GNUNET_free (non_const_argv[--argcount]);
1154   GNUNET_free (non_const_argv);
1155
1156   memset (&start, 0, sizeof (start));
1157   start.cb = sizeof (start);
1158   if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
1159     start.dwFlags |= STARTF_USESTDHANDLES;
1160
1161   stdih = GetStdHandle (STD_INPUT_HANDLE);
1162   GetHandleInformation (stdih, &stdif);
1163   if (pipe_stdin != NULL)
1164   {
1165     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1166                                        (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
1167                                        &stdin_handle, sizeof (HANDLE));
1168     start.hStdInput = stdin_handle;
1169   }
1170   if (stdih)
1171   {
1172     if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1173     {
1174       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
1175       if (pipe_stdin == NULL)
1176         start.hStdInput = stdih;
1177     }
1178     else
1179       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1180   }
1181     
1182
1183   stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1184   GetHandleInformation (stdoh, &stdof);
1185   if (NULL != pipe_stdout)
1186   {
1187     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1188                                        (pipe_stdout,
1189                                         GNUNET_DISK_PIPE_END_WRITE),
1190                                        &stdout_handle, sizeof (HANDLE));
1191     start.hStdOutput = stdout_handle;
1192   }
1193   if (stdoh)
1194   {
1195     if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1196     {
1197       SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1198       if (pipe_stdout == NULL)
1199         start.hStdOutput = stdoh;
1200     }
1201     else
1202       SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1203   }
1204
1205   stdeh = GetStdHandle (STD_ERROR_HANDLE);
1206   GetHandleInformation (stdeh, &stdef);
1207   if (stdeh)
1208   {
1209     if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1210     {
1211       SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1212       start.hStdError = stdeh;
1213     }
1214     else
1215       SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1216   }
1217
1218   if (GNUNET_YES == pipe_control)
1219   {
1220     control_pipe =
1221       npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
1222                     GNUNET_DISK_PERM_USER_READ |
1223                     GNUNET_DISK_PERM_USER_WRITE);
1224     if (control_pipe == NULL)
1225     {
1226       GNUNET_free (cmd);
1227       GNUNET_free (path);
1228       return NULL;
1229     }
1230   }
1231   else
1232     control_pipe = NULL;
1233   if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1234   {
1235     lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1236
1237     if (lsocks_pipe == NULL)
1238     {
1239       GNUNET_free (cmd);
1240       GNUNET_free (path);
1241       GNUNET_DISK_pipe_close (lsocks_pipe);
1242       return NULL;
1243     }
1244     lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1245         GNUNET_DISK_PIPE_END_WRITE);
1246     GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1247                                        &lsocks_write, sizeof (HANDLE));
1248     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1249                                        (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1250                                        &lsocks_read, sizeof (HANDLE));
1251   }
1252
1253   env_off = 0;
1254   if (NULL != childpipename)
1255   {
1256     LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
1257          childpipename);
1258     GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1259     GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
1260     GNUNET_free (childpipename);
1261   }
1262   if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1263   {
1264     /*This will tell the child that we're going to send lsocks over the pipe*/
1265     GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1266     GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1267   }
1268   our_env[env_off++] = NULL;
1269   env_block = CreateCustomEnvTable (our_env);
1270   while (0 > env_off)
1271     GNUNET_free_non_null (our_env[--env_off]);
1272
1273   wpath_len = 0;
1274   if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1275   {
1276     LOG (GNUNET_ERROR_TYPE_DEBUG,
1277         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1278     GNUNET_free (env_block);
1279     GNUNET_free (cmd);
1280     return NULL;
1281   }
1282
1283   wcmd_len = 0;
1284   if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1285   {
1286     LOG (GNUNET_ERROR_TYPE_DEBUG,
1287         "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1288     GNUNET_free (env_block);
1289     GNUNET_free (cmd);
1290     free (wpath);
1291     return NULL;
1292   }
1293
1294   bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
1295        DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1296   error_code = GetLastError ();
1297
1298   if ((NULL == pipe_stdin) && (stdih))
1299     SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1300     
1301
1302   if ((NULL == pipe_stdout) && (stdoh))
1303     SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1304
1305   if (stdeh)
1306     SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1307
1308   GNUNET_free (env_block);
1309   GNUNET_free (cmd);
1310   free (wpath);
1311   free (wcmd);
1312
1313   if (!bresult)
1314   {
1315     SetErrnoFromWinError (error_code);
1316     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1317     if (NULL != control_pipe)
1318       GNUNET_DISK_file_close (control_pipe);
1319     if (NULL != lsocks)
1320       GNUNET_DISK_pipe_close (lsocks_pipe);
1321     return NULL;
1322   }
1323
1324   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1325   gnunet_proc->pid = proc.dwProcessId;
1326   gnunet_proc->handle = proc.hProcess;
1327   gnunet_proc->control_pipe = control_pipe;
1328
1329   CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1330
1331   ResumeThread (proc.hThread);
1332   CloseHandle (proc.hThread);
1333
1334   if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
1335     return gnunet_proc;
1336
1337   GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1338
1339   /* This is a replacement for "goto error" that doesn't use goto */
1340   fail = 1;
1341   do
1342   {
1343     ssize_t wrote;
1344     uint64_t size;
1345     uint64_t count;
1346     unsigned int i;
1347
1348     /* Tell the number of sockets */
1349     for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1350
1351     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1352     if (sizeof (count) != wrote)
1353     {
1354       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1355                   "Failed to write %u count bytes to the child: %u\n",
1356                   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, 
1366                     "Failed to duplicate an socket[%llu]: %u\n", i, 
1367                     GetLastError ());
1368         break;
1369       }
1370       /* Synchronous I/O is not nice, but we can't schedule this:
1371        * lsocks will be closed/freed by the caller soon, and until
1372        * the child creates a duplicate, closing a socket here will
1373        * close it for good.
1374        */
1375       /* Send the size of the structure
1376        * (the child might be built with different headers...)
1377        */
1378       size = sizeof (pi);
1379       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1380       if (sizeof (size) != wrote)
1381       {
1382         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1383                     "Failed to write %u size[%llu] bytes to the child: %u\n", 
1384                     sizeof (size), i, GetLastError ());
1385         break;
1386       }
1387       /* Finally! Send the data */
1388       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1389       if (sizeof (pi) != wrote)
1390       {
1391         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1392                     "Failed to write %u socket[%llu] bytes to the child: %u\n", 
1393                     sizeof (pi), i, GetLastError ());
1394         break;
1395       }
1396     }
1397     /* This will block us until the child makes a final read or closes
1398      * the pipe (hence no 'wrote' check), since we have to wait for it
1399      * to duplicate the last socket, before we return and start closing
1400      * our own copies)
1401      */
1402     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1403     fail = 0;
1404   }
1405   while (fail);
1406
1407   GNUNET_DISK_file_sync (lsocks_write_fd);
1408   GNUNET_DISK_pipe_close (lsocks_pipe);
1409
1410   if (fail)
1411   {
1412     /* If we can't pass on the socket(s), the child will block forever,
1413      * better put it out of its misery.
1414      */
1415     SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1416     CloseHandle (gnunet_proc->handle);
1417     if (NULL != gnunet_proc->control_pipe)
1418       GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1419     GNUNET_free (gnunet_proc);
1420     return NULL;
1421   }
1422   return gnunet_proc;
1423 #endif
1424 }
1425
1426
1427
1428
1429 /**
1430  * Start a process.
1431  *
1432  * @param pipe_control should a pipe be used to send signals to the child?
1433  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1434  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1435  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1436  * @param filename name of the binary
1437  * @param argv NULL-terminated array of arguments to the process
1438  * @return pointer to process structure of the new process, NULL on error
1439  */
1440 struct GNUNET_OS_Process *
1441 GNUNET_OS_start_process_vap (int pipe_control,
1442                              enum GNUNET_OS_InheritStdioFlags std_inheritance,
1443                              struct GNUNET_DISK_PipeHandle *pipe_stdin,
1444                              struct GNUNET_DISK_PipeHandle *pipe_stdout,
1445                              const char *filename, 
1446                              char *const argv[])
1447 {
1448   return start_process (pipe_control,
1449                         std_inheritance,
1450                         pipe_stdin,
1451                         pipe_stdout,
1452                         NULL,
1453                         filename,
1454                         argv);
1455 }
1456
1457
1458 /**
1459  * Start a process.
1460  *
1461  * @param pipe_control should a pipe be used to send signals to the child?
1462  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1463  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1464  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1465  * @param filename name of the binary
1466  * @param va NULL-terminated list of arguments to the process
1467  * @return pointer to process structure of the new process, NULL on error
1468  */
1469 struct GNUNET_OS_Process *
1470 GNUNET_OS_start_process_va (int pipe_control,
1471                             enum GNUNET_OS_InheritStdioFlags std_inheritance,
1472                             struct GNUNET_DISK_PipeHandle *pipe_stdin,
1473                             struct GNUNET_DISK_PipeHandle *pipe_stdout,
1474                             const char *filename, va_list va)
1475 {
1476   struct GNUNET_OS_Process *ret;
1477   va_list ap;
1478   char **argv;
1479   int argc;
1480
1481   argc = 0;
1482   va_copy (ap, va);
1483   while (NULL != va_arg (ap, char *))
1484     argc++;
1485   va_end (ap);
1486   argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1487   argc = 0;
1488   va_copy (ap, va);
1489   while (NULL != (argv[argc] = va_arg (ap, char *)))
1490     argc++;
1491   va_end (ap);
1492   ret = GNUNET_OS_start_process_vap (pipe_control,
1493                                      std_inheritance,
1494                                      pipe_stdin,
1495                                      pipe_stdout,
1496                                      filename,
1497                                      argv);
1498   GNUNET_free (argv);
1499   return ret;
1500 }
1501
1502
1503 /**
1504  * Start a process.
1505  *
1506  * @param pipe_control should a pipe be used to send signals to the child?
1507  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1508  * @param pipe_stdin pipe to use to send input to child process (or NULL)
1509  * @param pipe_stdout pipe to use to get output from child process (or NULL)
1510  * @param filename name of the binary
1511  * @param ... NULL-terminated list of arguments to the process
1512  * @return pointer to process structure of the new process, NULL on error
1513  */
1514 struct GNUNET_OS_Process *
1515 GNUNET_OS_start_process (int pipe_control,
1516                          enum GNUNET_OS_InheritStdioFlags std_inheritance,
1517                          struct GNUNET_DISK_PipeHandle *pipe_stdin,
1518                          struct GNUNET_DISK_PipeHandle *pipe_stdout,
1519                          const char *filename, ...)
1520 {
1521   struct GNUNET_OS_Process *ret;
1522   va_list ap;
1523
1524   va_start (ap, filename);
1525   ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1526                                     pipe_stdout, filename, ap);
1527   va_end (ap);
1528   return ret;
1529 }
1530
1531
1532 /**
1533  * Start a process.
1534  *
1535  * @param pipe_control should a pipe be used to send signals to the child?
1536  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
1537  *        std handles of the parent are inherited by the child.
1538  *        pipe_stdin and pipe_stdout take priority over std_inheritance
1539  *        (when they are non-NULL).
1540  * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1541  *         must be NULL on platforms where dup is not supported
1542  * @param filename name of the binary
1543  * @param argv NULL-terminated list of arguments to the process
1544  * @return process ID of the new process, -1 on error
1545  */
1546 struct GNUNET_OS_Process *
1547 GNUNET_OS_start_process_v (int pipe_control,
1548                            enum GNUNET_OS_InheritStdioFlags std_inheritance,
1549                            const SOCKTYPE *lsocks,
1550                            const char *filename,
1551                            char *const argv[])
1552 {
1553   return start_process (pipe_control,
1554                         std_inheritance,
1555                         NULL,
1556                         NULL,
1557                         lsocks,
1558                         filename,
1559                         argv);
1560 }
1561
1562
1563 /**
1564  * Retrieve the status of a process, waiting on him if dead.
1565  * Nonblocking version.
1566  * 
1567  * @param proc process ID
1568  * @param type status type
1569  * @param code return code/signal number
1570  * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1571  */
1572 int
1573 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1574                           enum GNUNET_OS_ProcessStatusType *type,
1575                           unsigned long *code)
1576 {
1577 #ifndef MINGW
1578   int status;
1579   int ret;
1580
1581   GNUNET_assert (0 != proc);
1582   ret = waitpid (proc->pid, &status, WNOHANG);
1583   if (ret < 0)
1584   {
1585     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1586     return GNUNET_SYSERR;
1587   }
1588   if (0 == ret)
1589   {
1590     *type = GNUNET_OS_PROCESS_RUNNING;
1591     *code = 0;
1592     return GNUNET_NO;
1593   }
1594   if (proc->pid != ret)
1595   {
1596     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1597     return GNUNET_SYSERR;
1598   }
1599   if (WIFEXITED (status))
1600   {
1601     *type = GNUNET_OS_PROCESS_EXITED;
1602     *code = WEXITSTATUS (status);
1603   }
1604   else if (WIFSIGNALED (status))
1605   {
1606     *type = GNUNET_OS_PROCESS_SIGNALED;
1607     *code = WTERMSIG (status);
1608   }
1609   else if (WIFSTOPPED (status))
1610   {
1611     *type = GNUNET_OS_PROCESS_SIGNALED;
1612     *code = WSTOPSIG (status);
1613   }
1614 #ifdef WIFCONTINUED
1615   else if (WIFCONTINUED (status))
1616   {
1617     *type = GNUNET_OS_PROCESS_RUNNING;
1618     *code = 0;
1619   }
1620 #endif
1621   else
1622   {
1623     *type = GNUNET_OS_PROCESS_UNKNOWN;
1624     *code = 0;
1625   }
1626 #else
1627   HANDLE h;
1628   DWORD c, error_code, ret;
1629
1630   h = proc->handle;
1631   ret = proc->pid;
1632   if (h == NULL || ret == 0)
1633   {
1634     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1635          ret, h);
1636     return GNUNET_SYSERR;
1637   }
1638   if (h == NULL)
1639     h = GetCurrentProcess ();
1640
1641   SetLastError (0);
1642   ret = GetExitCodeProcess (h, &c);
1643   error_code = GetLastError ();
1644   if (ret == 0 || error_code != NO_ERROR)
1645   {
1646     SetErrnoFromWinError (error_code);
1647     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1648     return GNUNET_SYSERR;
1649   }
1650   if (STILL_ACTIVE == c)
1651   {
1652     *type = GNUNET_OS_PROCESS_RUNNING;
1653     *code = 0;
1654     return GNUNET_NO;
1655   }
1656   *type = GNUNET_OS_PROCESS_EXITED;
1657   *code = c;
1658 #endif
1659
1660   return GNUNET_OK;
1661 }
1662
1663
1664 /**
1665  * Wait for a process
1666  *
1667  * @param proc pointer to process structure
1668  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1669  */
1670 int
1671 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1672 {
1673 #ifndef MINGW
1674   pid_t pid = proc->pid;
1675   pid_t ret;
1676
1677   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1678           (EINTR == errno) ) ;
1679   if (pid != ret) 
1680   {
1681     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1682     return GNUNET_SYSERR;
1683   }
1684   return GNUNET_OK;
1685 #else
1686   HANDLE h;
1687
1688   h = proc->handle;
1689   if (NULL == h)
1690   {
1691     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1692          proc->pid, h);
1693     return GNUNET_SYSERR;
1694   }
1695   if (NULL == h)
1696     h = GetCurrentProcess ();
1697
1698   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1699   {
1700     SetErrnoFromWinError (GetLastError ());
1701     return GNUNET_SYSERR;
1702   }
1703   return GNUNET_OK;
1704 #endif
1705 }
1706
1707
1708 /**
1709  * Handle to a command.
1710  */
1711 struct GNUNET_OS_CommandHandle
1712 {
1713
1714   /**
1715    * Process handle.
1716    */
1717   struct GNUNET_OS_Process *eip;
1718
1719   /**
1720    * Handle to the output pipe.
1721    */
1722   struct GNUNET_DISK_PipeHandle *opipe;
1723
1724   /**
1725    * Read-end of output pipe.
1726    */
1727   const struct GNUNET_DISK_FileHandle *r;
1728
1729   /**
1730    * Function to call on each line of output.
1731    */
1732   GNUNET_OS_LineProcessor proc;
1733
1734   /**
1735    * Closure for 'proc'.
1736    */
1737   void *proc_cls;
1738
1739   /**
1740    * Buffer for the output.
1741    */
1742   char buf[1024];
1743
1744   /**
1745    * Task reading from pipe.
1746    */
1747   GNUNET_SCHEDULER_TaskIdentifier rtask;
1748
1749   /**
1750    * When to time out.
1751    */
1752   struct GNUNET_TIME_Absolute timeout;
1753
1754   /**
1755    * Current read offset in buf.
1756    */
1757   size_t off;
1758 };
1759
1760
1761 /**
1762  * Stop/kill a command.  Must ONLY be called either from
1763  * the callback after 'NULL' was passed for 'line' *OR*
1764  * from an independent task (not within the line processor).
1765  *
1766  * @param cmd handle to the process
1767  */
1768 void
1769 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1770 {
1771   if (NULL != cmd->proc)
1772   {
1773     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1774     GNUNET_SCHEDULER_cancel (cmd->rtask);
1775   }
1776   (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1777   GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1778   GNUNET_OS_process_destroy (cmd->eip);
1779   GNUNET_DISK_pipe_close (cmd->opipe);
1780   GNUNET_free (cmd);
1781 }
1782
1783
1784 /**
1785  * Read from the process and call the line processor.
1786  *
1787  * @param cls the 'struct GNUNET_OS_CommandHandle'
1788  * @param tc scheduler context
1789  */
1790 static void
1791 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1792 {
1793   struct GNUNET_OS_CommandHandle *cmd = cls;
1794   GNUNET_OS_LineProcessor proc;
1795   char *end;
1796   ssize_t ret;
1797
1798   cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1799   if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1800   {
1801     /* timeout, shutdown, etc. */
1802     proc = cmd->proc;
1803     cmd->proc = NULL;
1804     proc (cmd->proc_cls, NULL);
1805     return;
1806   }
1807   ret =
1808       GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1809                              sizeof (cmd->buf) - cmd->off);
1810   if (ret <= 0)
1811   {
1812     if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1813     {
1814       cmd->buf[cmd->off] = '\0';
1815       cmd->proc (cmd->proc_cls, cmd->buf);
1816     }
1817     proc = cmd->proc;
1818     cmd->proc = NULL;
1819     proc (cmd->proc_cls, NULL);
1820     return;
1821   }
1822   end = memchr (&cmd->buf[cmd->off], '\n', ret);
1823   cmd->off += ret;
1824   while (NULL != end)
1825   {
1826     *end = '\0';
1827     cmd->proc (cmd->proc_cls, cmd->buf);
1828     memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1829     cmd->off -= (end + 1 - cmd->buf);
1830     end = memchr (cmd->buf, '\n', cmd->off);
1831   }
1832   cmd->rtask =
1833       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1834                                       (cmd->timeout), cmd->r, &cmd_read, cmd);
1835 }
1836
1837
1838 /**
1839  * Run the given command line and call the given function
1840  * for each line of the output.
1841  *
1842  * @param proc function to call for each line of the output
1843  * @param proc_cls closure for proc
1844  * @param timeout when to time out
1845  * @param binary command to run
1846  * @param ... arguments to command
1847  * @return NULL on error
1848  */
1849 struct GNUNET_OS_CommandHandle *
1850 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1851                        struct GNUNET_TIME_Relative timeout, const char *binary,
1852                        ...)
1853 {
1854   struct GNUNET_OS_CommandHandle *cmd;
1855   struct GNUNET_OS_Process *eip;
1856   struct GNUNET_DISK_PipeHandle *opipe;
1857   va_list ap;
1858
1859   opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1860   if (NULL == opipe)
1861     return NULL;
1862   va_start (ap, binary);
1863   /* redirect stdout, don't inherit stderr/stdin */
1864   eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1865   va_end (ap);
1866   if (NULL == eip)
1867   {
1868     GNUNET_DISK_pipe_close (opipe);
1869     return NULL;
1870   }
1871   GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1872   cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1873   cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1874   cmd->eip = eip;
1875   cmd->opipe = opipe;
1876   cmd->proc = proc;
1877   cmd->proc_cls = proc_cls;
1878   cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1879   cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1880   return cmd;
1881 }
1882
1883
1884 /* end of os_priority.c */