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