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