GNUnet  0.10.x
os_priority.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "disk.h"
30 #include <unistr.h>
31 
32 #define LOG(kind,...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
33 
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
35 
36 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
37 
38 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
39 
40 
42 {
46  pid_t pid;
47 
48 #if WINDOWS
49 
52  HANDLE handle;
53 #endif
54 
60 };
61 
62 
67 
71 static struct GNUNET_SCHEDULER_Task *pch;
72 
76 static struct GNUNET_SCHEDULER_Task *spch;
77 
78 
84 static void
85 shutdown_pch (void *cls)
86 {
88 
90  pch = NULL;
91  GNUNET_DISK_file_close (control_pipe);
92  control_pipe = NULL;
93 }
94 
95 
101 static void
103 {
104  struct GNUNET_DISK_FileHandle *control_pipe = cls;
105  char sig;
106  char *pipe_fd;
107  ssize_t ret;
108 
109  pch = NULL;
110  ret = GNUNET_DISK_file_read (control_pipe,
111  &sig,
112  sizeof (sig));
113  if (sizeof (sig) != ret)
114  {
115  if (-1 == ret)
117  "GNUNET_DISK_file_read");
119  "Closing control pipe\n");
120  GNUNET_DISK_file_close (control_pipe);
121  control_pipe = NULL;
123  spch = NULL;
124  return;
125  }
126  pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
127  GNUNET_assert ( (NULL == pipe_fd) ||
128  (strlen (pipe_fd) <= 0) );
130  "Got control code %d from parent via pipe %s\n",
131  sig,
132  pipe_fd);
134  control_pipe,
136  control_pipe);
137  GNUNET_SIGNAL_raise ((int) sig);
138 }
139 
140 
149 void
151 {
152  const char *env_buf;
153  char *env_buf_end;
155  uint64_t pipe_fd;
156 
157  (void) cls;
158  if (NULL != pch)
159  {
160  /* already done, we've been called twice... */
161  GNUNET_break (0);
162  return;
163  }
164  env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
165  if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
166  {
168  "Not installing a handler because $%s is empty\n",
170  putenv (GNUNET_OS_CONTROL_PIPE "=");
171  return;
172  }
173  errno = 0;
174  pipe_fd = strtoull (env_buf, &env_buf_end, 16);
175  if ((0 != errno) || (env_buf == env_buf_end))
176  {
178  "strtoull",
179  env_buf);
180  putenv (GNUNET_OS_CONTROL_PIPE "=");
181  return;
182  }
183 #if !defined (WINDOWS)
184  if (pipe_fd >= FD_SETSIZE)
185 #else
186  if ((FILE_TYPE_UNKNOWN == GetFileType ((HANDLE) (uintptr_t) pipe_fd))
187  && (0 != GetLastError ()))
188 #endif
189  {
191  "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
192  env_buf);
193  putenv (GNUNET_OS_CONTROL_PIPE "=");
194  return;
195  }
196 #if WINDOWS
197  control_pipe = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) (uintptr_t) pipe_fd);
198 #else
199  control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
200 #endif
201  if (NULL == control_pipe)
202  {
204  "open",
205  env_buf);
206  putenv (GNUNET_OS_CONTROL_PIPE "=");
207  return;
208  }
210  "Adding parent control handler pipe `%s' to the scheduler\n",
211  env_buf);
213  control_pipe,
215  control_pipe);
217  control_pipe);
218  putenv (GNUNET_OS_CONTROL_PIPE "=");
219 }
220 
221 
230 struct GNUNET_OS_Process *
232 {
233 #if WINDOWS
234  current_process.pid = GetCurrentProcessId ();
235  current_process.handle = GetCurrentProcess ();
236 #else
237  current_process.pid = 0;
238 #endif
239  return &current_process;
240 }
241 
242 
250 int
252  int sig)
253 {
254  int ret;
255  char csig;
256 
257  csig = (char) sig;
258  if (NULL != proc->control_pipe)
259  {
261  "Sending signal %d to pid: %u via pipe\n",
262  sig,
263  proc->pid);
265  &csig,
266  sizeof (csig));
267  if (sizeof (csig) == ret)
268  return 0;
269  }
270  /* pipe failed or non-existent, try other methods */
271  switch (sig)
272  {
273 #if !defined (WINDOWS)
274  case SIGHUP:
275 #endif
276  case SIGINT:
277  case SIGKILL:
278  case SIGTERM:
279 #if (SIGTERM != GNUNET_TERM_SIG)
280  case GNUNET_TERM_SIG:
281 #endif
282 #if defined(WINDOWS) && !defined(__CYGWIN__)
283  {
284  DWORD exitcode;
285  int must_kill = GNUNET_YES;
286  if (0 != GetExitCodeProcess (proc->handle, &exitcode))
287  must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
288  if (GNUNET_YES == must_kill)
289  {
290  if (0 == SafeTerminateProcess (proc->handle, 0, 0))
291  {
292  DWORD error_code = GetLastError ();
293  if ( (error_code != WAIT_TIMEOUT) &&
294  (error_code != ERROR_PROCESS_ABORTED) )
295  {
296  LOG ((error_code == ERROR_ACCESS_DENIED) ?
298  "SafeTermiateProcess failed with code %lu\n",
299  error_code);
300  /* The problem here is that a process that is already dying
301  * might cause SafeTerminateProcess to fail with
302  * ERROR_ACCESS_DENIED, but the process WILL die eventually.
303  * If we really had a permissions problem, hanging up (which
304  * is what will happen in process_wait() in that case) is
305  * a valid option.
306  */
307  if (ERROR_ACCESS_DENIED == error_code)
308  {
309  errno = 0;
310  }
311  else
312  {
313  SetErrnoFromWinError (error_code);
314  return -1;
315  }
316  }
317  }
318  }
319  }
320  return 0;
321 #else
323  "Sending signal %d to pid: %u via system call\n",
324  sig,
325  proc->pid);
326  return PLIBC_KILL (proc->pid, sig);
327 #endif
328  default:
329 #if defined (WINDOWS)
330  errno = EINVAL;
331  return -1;
332 #else
334  "Sending signal %d to pid: %u via system call\n",
335  sig,
336  proc->pid);
337  return PLIBC_KILL (proc->pid, sig);
338 #endif
339  }
340 }
341 
342 
350 pid_t
352 {
353  return proc->pid;
354 }
355 
356 
363 void
365 {
366  if (NULL != proc->control_pipe)
368 #if defined (WINDOWS)
369  if (NULL != proc->handle)
370  CloseHandle (proc->handle);
371 #endif
372  GNUNET_free (proc);
373 }
374 
375 
376 #if WINDOWS
377 #include "gnunet_signal_lib.h"
378 
379 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
380 
384 #define DWORD_WINAPI DWORD WINAPI
385 
386 
391 static DWORD_WINAPI
392 child_wait_thread (void *arg)
393 {
394  struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
395 
396  WaitForSingleObject (proc->handle, INFINITE);
397 
398  if (w32_sigchld_handler)
399  w32_sigchld_handler ();
400 
401  return 0;
402 }
403 #endif
404 
405 
406 #if MINGW
407 static char *
408 CreateCustomEnvTable (char **vars)
409 {
410  char *win32_env_table;
411  char *ptr;
412  char **var_ptr;
413  char *result;
414  char *result_ptr;
415  size_t tablesize = 0;
416  size_t items_count = 0;
417  size_t n_found = 0;
418  size_t n_var;
419  char *index = NULL;
420  size_t c;
421  size_t var_len;
422  char *var;
423  char *val;
424 
425  win32_env_table = GetEnvironmentStringsA ();
426  if (NULL == win32_env_table)
427  return NULL;
428  for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
429  n_var = c;
430  index = GNUNET_malloc (sizeof (char *) * n_var);
431  for (c = 0; c < n_var; c++)
432  index[c] = 0;
433  for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
434  {
435  size_t len = strlen (ptr);
436  int found = 0;
437 
438  for (var_ptr = vars; *var_ptr; var_ptr++)
439  {
440  var = *var_ptr++;
441  val = *var_ptr;
442  var_len = strlen (var);
443  if (strncmp (var, ptr, var_len) == 0)
444  {
445  found = 1;
446  index[c] = 1;
447  tablesize += var_len + strlen (val) + 1;
448  break;
449  }
450  }
451  if (!found)
452  tablesize += len + 1;
453  ptr += len + 1;
454  }
455  for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
456  {
457  var = *var_ptr++;
458  val = *var_ptr;
459  if (index[c] != 1)
460  n_found += strlen (var) + strlen (val) + 1;
461  }
462  result = GNUNET_malloc (tablesize + n_found + 1);
463  for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
464  {
465  size_t len = strlen (ptr);
466  int found = 0;
467 
468  for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
469  {
470  var = *var_ptr++;
471  val = *var_ptr;
472  var_len = strlen (var);
473  if (strncmp (var, ptr, var_len) == 0)
474  {
475  found = 1;
476  break;
477  }
478  }
479  if (!found)
480  {
481  strcpy (result_ptr, ptr);
482  result_ptr += len + 1;
483  }
484  else
485  {
486  strcpy (result_ptr, var);
487  result_ptr += var_len;
488  strcpy (result_ptr, val);
489  result_ptr += strlen (val) + 1;
490  }
491  ptr += len + 1;
492  }
493  for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
494  {
495  var = *var_ptr++;
496  val = *var_ptr;
497  var_len = strlen (var);
498  if (index[c] != 1)
499  {
500  strcpy (result_ptr, var);
501  result_ptr += var_len;
502  strcpy (result_ptr, val);
503  result_ptr += strlen (val) + 1;
504  }
505  }
506  FreeEnvironmentStrings (win32_env_table);
507  GNUNET_free (index);
508  *result_ptr = 0;
509  return result;
510 }
511 
512 #else
513 
521 static void
522 open_dev_null (int target_fd,
523  int flags)
524 {
525  int fd;
526 
527  fd = open ("/dev/null", flags);
528  if (-1 == fd)
529  {
531  "open",
532  "/dev/null");
533  return;
534  }
535  if (fd == target_fd)
536  return;
537  if (-1 == dup2 (fd, target_fd))
538  {
540  (void) close (fd);
541  return;
542  }
543  GNUNET_break (0 == close (fd));
544 }
545 #endif
546 
547 
565 static struct GNUNET_OS_Process *
566 start_process (int pipe_control,
567  enum GNUNET_OS_InheritStdioFlags std_inheritance,
568  struct GNUNET_DISK_PipeHandle *pipe_stdin,
569  struct GNUNET_DISK_PipeHandle *pipe_stdout,
570  struct GNUNET_DISK_PipeHandle *pipe_stderr,
571  const SOCKTYPE *lsocks,
572  const char *filename,
573  char *const argv[])
574 {
575 #ifndef MINGW
576  pid_t ret;
577  char fds[16];
578  struct GNUNET_OS_Process *gnunet_proc;
579  struct GNUNET_DISK_FileHandle *childpipe_read;
580  struct GNUNET_DISK_FileHandle *childpipe_write;
581  int childpipe_read_fd;
582  int i;
583  int j;
584  int k;
585  int tgt;
586  int flags;
587  int *lscp;
588  unsigned int ls;
589  int fd_stdout_write;
590  int fd_stdout_read;
591  int fd_stderr_write;
592  int fd_stderr_read;
593  int fd_stdin_read;
594  int fd_stdin_write;
595 
596  if (GNUNET_SYSERR ==
597  GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
598  return NULL; /* not executable */
599  if (GNUNET_YES == pipe_control)
600  {
601  struct GNUNET_DISK_PipeHandle *childpipe;
602  int dup_childpipe_read_fd = -1;
603 
604  childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
606  if (NULL == childpipe)
607  return NULL;
608  childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe,
610  childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe,
612  GNUNET_DISK_pipe_close (childpipe);
613  if ( (NULL == childpipe_read) ||
614  (NULL == childpipe_write) ||
615  (GNUNET_OK !=
616  GNUNET_DISK_internal_file_handle_ (childpipe_read,
617  &childpipe_read_fd,
618  sizeof (int))) ||
619  (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
620  {
621  if (NULL != childpipe_read)
622  GNUNET_DISK_file_close (childpipe_read);
623  if (NULL != childpipe_write)
624  GNUNET_DISK_file_close (childpipe_write);
625  if (0 <= dup_childpipe_read_fd)
626  close (dup_childpipe_read_fd);
627  return NULL;
628  }
629  childpipe_read_fd = dup_childpipe_read_fd;
630  GNUNET_DISK_file_close (childpipe_read);
631  }
632  else
633  {
634  childpipe_write = NULL;
635  childpipe_read_fd = -1;
636  }
637  if (NULL != pipe_stdin)
638  {
641  (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
642  &fd_stdin_read, sizeof (int)));
645  (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
646  &fd_stdin_write, sizeof (int)));
647  }
648  if (NULL != pipe_stdout)
649  {
652  (pipe_stdout,
654  &fd_stdout_write, sizeof (int)));
657  (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
658  &fd_stdout_read, sizeof (int)));
659  }
660  if (NULL != pipe_stderr)
661  {
664  (pipe_stderr,
666  &fd_stderr_read, sizeof (int)));
669  (pipe_stderr,
671  &fd_stderr_write, sizeof (int)));
672  }
673  lscp = NULL;
674  ls = 0;
675  if (NULL != lsocks)
676  {
677  i = 0;
678  while (-1 != (k = lsocks[i++]))
679  GNUNET_array_append (lscp, ls, k);
680  GNUNET_array_append (lscp, ls, -1);
681  }
682 #if DARWIN
683  /* see https://gnunet.org/vfork */
684  ret = vfork ();
685 #else
686  ret = fork ();
687 #endif
688  if (-1 == ret)
689  {
690  int eno = errno;
692  GNUNET_array_grow (lscp, ls, 0);
693  if (NULL != childpipe_write)
694  GNUNET_DISK_file_close (childpipe_write);
695  if (0 <= childpipe_read_fd)
696  close (childpipe_read_fd);
697  errno = eno;
698  return NULL;
699  }
700  if (0 != ret)
701  {
702  unsetenv (GNUNET_OS_CONTROL_PIPE);
703  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
704  gnunet_proc->pid = ret;
705  gnunet_proc->control_pipe = childpipe_write;
706  if (GNUNET_YES == pipe_control)
707  {
708  close (childpipe_read_fd);
709  }
710  GNUNET_array_grow (lscp, ls, 0);
711  return gnunet_proc;
712  }
713  if (0 <= childpipe_read_fd)
714  {
715  char fdbuf[100];
716 #ifndef DARWIN
717  /* due to vfork, we must NOT free memory on DARWIN! */
718  GNUNET_DISK_file_close (childpipe_write);
719 #endif
720  snprintf (fdbuf, 100, "%x", childpipe_read_fd);
721  setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
722  }
723  else
724  unsetenv (GNUNET_OS_CONTROL_PIPE);
725  if (NULL != pipe_stdin)
726  {
727  GNUNET_break (0 == close (fd_stdin_write));
728  if (-1 == dup2 (fd_stdin_read, 0))
730  GNUNET_break (0 == close (fd_stdin_read));
731  }
732  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
733  {
734  GNUNET_break (0 == close (0));
735  open_dev_null (0, O_RDONLY);
736  }
737  if (NULL != pipe_stdout)
738  {
739  GNUNET_break (0 == close (fd_stdout_read));
740  if (-1 == dup2 (fd_stdout_write, 1))
742  GNUNET_break (0 == close (fd_stdout_write));
743  }
744  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
745  {
746  GNUNET_break (0 == close (1));
747  open_dev_null (1, O_WRONLY);
748  }
749  if (NULL != pipe_stderr)
750  {
751  GNUNET_break (0 == close (fd_stderr_read));
752  if (-1 == dup2 (fd_stderr_write, 2))
754  GNUNET_break (0 == close (fd_stderr_write));
755  }
756  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
757  {
758  GNUNET_break (0 == close (2));
759  open_dev_null (2, O_WRONLY);
760  }
761  if (NULL != lscp)
762  {
763  /* read systemd documentation... */
764  i = 0;
765  tgt = 3;
766  while (-1 != lscp[i])
767  {
768  j = i + 1;
769  while (-1 != lscp[j])
770  {
771  if (lscp[j] == tgt)
772  {
773  /* dup away */
774  k = dup (lscp[j]);
775  GNUNET_assert (-1 != k);
776  GNUNET_assert (0 == close (lscp[j]));
777  lscp[j] = k;
778  break;
779  }
780  j++;
781  }
782  if (lscp[i] != tgt)
783  {
784  /* Bury any existing FD, no matter what; they should all be closed
785  * on exec anyway and the important onces have been dup'ed away */
786  (void) close (tgt);
787  GNUNET_assert (-1 != dup2 (lscp[i], tgt));
788  }
789  /* unset close-on-exec flag */
790  flags = fcntl (tgt, F_GETFD);
791  GNUNET_assert (flags >= 0);
792  flags &= ~FD_CLOEXEC;
793  fflush (stderr);
794  (void) fcntl (tgt, F_SETFD, flags);
795  tgt++;
796  i++;
797  }
798  GNUNET_snprintf (fds, sizeof (fds), "%u", i);
799  setenv ("LISTEN_FDS", fds, 1);
800  }
801 #ifndef DARWIN
802  /* due to vfork, we must NOT free memory on DARWIN! */
803  GNUNET_array_grow (lscp, ls, 0);
804 #endif
805  execvp (filename, argv);
806  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
807  _exit (1);
808 #else
809  struct GNUNET_DISK_FileHandle *childpipe_read;
810  struct GNUNET_DISK_FileHandle *childpipe_write;
811  HANDLE childpipe_read_handle;
812  char **arg;
813  char **non_const_argv;
814  unsigned int cmdlen;
815  char *cmd;
816  char *idx;
817  STARTUPINFOW start;
818  PROCESS_INFORMATION proc;
819  int argcount = 0;
820  struct GNUNET_OS_Process *gnunet_proc;
821  char path[MAX_PATH + 1];
822  char *our_env[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
823  char *env_block = NULL;
824  char *pathbuf;
825  DWORD pathbuf_len;
826  DWORD alloc_len;
827  char *self_prefix;
828  char *bindir;
829  char *libdir;
830  char *ptr;
831  char *non_const_filename;
832  char win_path[MAX_PATH + 1];
833  struct GNUNET_DISK_PipeHandle *lsocks_pipe;
834  const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
835  HANDLE lsocks_read;
836  HANDLE lsocks_write;
837  wchar_t *wpath;
838  wchar_t *wcmd;
839  size_t wpath_len;
840  size_t wcmd_len;
841  int env_off;
842  int fail;
843  long lRet;
844  HANDLE stdin_handle;
845  HANDLE stdout_handle;
846  HANDLE stdih, stdoh, stdeh;
847  DWORD stdif, stdof, stdef;
848  BOOL bresult;
849  DWORD error_code;
850  DWORD create_no_window;
851 
852  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
853  return NULL; /* not executable */
854 
855  /* Search in prefix dir (hopefully - the directory from which
856  * the current module was loaded), bindir and libdir, then in PATH
857  */
861 
862  pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
863 
864  alloc_len =
865  pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
866  strlen (libdir);
867 
868  pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
869 
870  ptr = pathbuf;
871  ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
872  GNUNET_free (self_prefix);
873  GNUNET_free (bindir);
874  GNUNET_free (libdir);
875 
876  alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
877  if (alloc_len != pathbuf_len - 1)
878  {
879  GNUNET_free (pathbuf);
880  errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
881  return NULL;
882  }
883 
884  cmdlen = strlen (filename);
885  if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
886  GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
887  else
888  GNUNET_asprintf (&non_const_filename, "%s", filename);
889 
890  /* It could be in POSIX form, convert it to a DOS path early on */
891  if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
892  {
893  SetErrnoFromWinError (lRet);
894  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
895  non_const_filename);
896  GNUNET_free (non_const_filename);
897  GNUNET_free (pathbuf);
898  return NULL;
899  }
900  GNUNET_free (non_const_filename);
901  non_const_filename = GNUNET_strdup (win_path);
902  /* Check that this is the full path. If it isn't, search. */
903  /* FIXME: convert it to wchar_t and use SearchPathW?
904  * Remember: arguments to _start_process() are technically in UTF-8...
905  */
906  if (non_const_filename[1] == ':')
907  {
908  snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
910  "Using path `%s' as-is. PATH is %s\n", path, ptr);
911  }
912  else if (!SearchPathA
913  (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
914  path, NULL))
915  {
916  SetErrnoFromWinError (GetLastError ());
918  non_const_filename);
919  GNUNET_free (non_const_filename);
920  GNUNET_free (pathbuf);
921  return NULL;
922  }
923  else
925  "Found `%s' in PATH `%s'\n", path, pathbuf);
926  GNUNET_free (pathbuf);
927  GNUNET_free (non_const_filename);
928 
929  /* Count the number of arguments */
930  arg = (char **) argv;
931  while (*arg)
932  {
933  arg++;
934  argcount++;
935  }
936 
937  /* Allocate a copy argv */
938  non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
939 
940  /* Copy all argv strings */
941  argcount = 0;
942  arg = (char **) argv;
943  while (*arg)
944  {
945  if (arg == argv)
946  non_const_argv[argcount] = GNUNET_strdup (path);
947  else
948  non_const_argv[argcount] = GNUNET_strdup (*arg);
949  arg++;
950  argcount++;
951  }
952  non_const_argv[argcount] = NULL;
953 
954  /* Count cmd len */
955  cmdlen = 1;
956  arg = non_const_argv;
957  while (*arg)
958  {
959  cmdlen = cmdlen + strlen (*arg) + 4;
960  arg++;
961  }
962 
963  /* Allocate and create cmd */
964  cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
965  arg = non_const_argv;
966  while (*arg)
967  {
968  char arg_last_char = (*arg)[strlen (*arg) - 1];
969  idx += sprintf (idx, "\"%s%s\"%s", *arg,
970  arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
971  arg++;
972  }
973 
974  while (argcount > 0)
975  GNUNET_free (non_const_argv[--argcount]);
976  GNUNET_free (non_const_argv);
977 
978  memset (&start, 0, sizeof (start));
979  start.cb = sizeof (start);
980  if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
981  start.dwFlags |= STARTF_USESTDHANDLES;
982 
983  stdih = GetStdHandle (STD_INPUT_HANDLE);
984  GetHandleInformation (stdih, &stdif);
985  if (pipe_stdin != NULL)
986  {
988  (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
989  &stdin_handle, sizeof (HANDLE));
990  start.hStdInput = stdin_handle;
991  }
992  else if (stdih)
993  {
994  if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
995  {
996  SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
997  if (pipe_stdin == NULL)
998  start.hStdInput = stdih;
999  }
1000  else
1001  SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1002  }
1003 
1004 
1005  stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1006  GetHandleInformation (stdoh, &stdof);
1007  if (NULL != pipe_stdout)
1008  {
1010  (pipe_stdout,
1012  &stdout_handle, sizeof (HANDLE));
1013  start.hStdOutput = stdout_handle;
1014  }
1015  else if (stdoh)
1016  {
1017  if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1018  {
1019  SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1020  if (pipe_stdout == NULL)
1021  start.hStdOutput = stdoh;
1022  }
1023  else
1024  SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1025  }
1026 
1027  stdeh = GetStdHandle (STD_ERROR_HANDLE);
1028  GetHandleInformation (stdeh, &stdef);
1029  if (stdeh)
1030  {
1031  if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1032  {
1033  SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1034  start.hStdError = stdeh;
1035  }
1036  else
1037  SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1038  }
1039 
1040  if (GNUNET_YES == pipe_control)
1041  {
1042  struct GNUNET_DISK_PipeHandle *childpipe;
1044  if (NULL == childpipe)
1045  return NULL;
1046  childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
1047  childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
1048  GNUNET_DISK_pipe_close (childpipe);
1049  if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
1050  (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
1051  &childpipe_read_handle, sizeof (HANDLE))))
1052  {
1053  if (childpipe_read)
1054  GNUNET_DISK_file_close (childpipe_read);
1055  if (childpipe_write)
1056  GNUNET_DISK_file_close (childpipe_write);
1057  GNUNET_free (cmd);
1058  return NULL;
1059  }
1060  /* Unlike *nix variant, we don't dup the handle, so can't close
1061  * filehandle right now.
1062  */
1063  SetHandleInformation (childpipe_read_handle, HANDLE_FLAG_INHERIT, 1);
1064  }
1065  else
1066  {
1067  childpipe_read = NULL;
1068  childpipe_write = NULL;
1069  }
1070 
1071  if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1072  {
1074 
1075  if (lsocks_pipe == NULL)
1076  {
1077  GNUNET_free (cmd);
1078  GNUNET_DISK_pipe_close (lsocks_pipe);
1079  if (GNUNET_YES == pipe_control)
1080  {
1081  GNUNET_DISK_file_close (childpipe_write);
1082  GNUNET_DISK_file_close (childpipe_read);
1083  }
1084  return NULL;
1085  }
1086  lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1088  GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1089  &lsocks_write, sizeof (HANDLE));
1091  (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1092  &lsocks_read, sizeof (HANDLE));
1093  }
1094  else
1095  {
1096  lsocks_pipe = NULL;
1097  lsocks_write_fd = NULL;
1098  }
1099 
1100  env_off = 0;
1101  if (GNUNET_YES == pipe_control)
1102  {
1103  GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1104  GNUNET_asprintf (&our_env[env_off++], "%p", childpipe_read_handle);
1105  }
1106  if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1107  {
1108  /*This will tell the child that we're going to send lsocks over the pipe*/
1109  GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1110  GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1111  }
1112  our_env[env_off++] = NULL;
1113  env_block = CreateCustomEnvTable (our_env);
1114  while (0 > env_off)
1115  GNUNET_free_non_null (our_env[--env_off]);
1116 
1117  wpath_len = 0;
1118  if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1119  {
1121  "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1122  GNUNET_free (env_block);
1123  GNUNET_free (cmd);
1124  if (lsocks_pipe)
1125  GNUNET_DISK_pipe_close (lsocks_pipe);
1126  if (GNUNET_YES == pipe_control)
1127  {
1128  GNUNET_DISK_file_close (childpipe_write);
1129  GNUNET_DISK_file_close (childpipe_read);
1130  }
1131  return NULL;
1132  }
1133 
1134  wcmd_len = 0;
1135  if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1136  {
1138  "Failed to convert `%s' from UTF-8 to UTF-16: %d\n",
1139  cmd,
1140  errno);
1141  GNUNET_free (env_block);
1142  GNUNET_free (cmd);
1143  free (wpath);
1144  if (lsocks_pipe)
1145  GNUNET_DISK_pipe_close (lsocks_pipe);
1146  if (GNUNET_YES == pipe_control)
1147  {
1148  GNUNET_DISK_file_close (childpipe_write);
1149  GNUNET_DISK_file_close (childpipe_read);
1150  }
1151  return NULL;
1152  }
1153 
1154  create_no_window = 0;
1155  {
1156  HANDLE console_input = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1157  if (INVALID_HANDLE_VALUE == console_input)
1158  create_no_window = CREATE_NO_WINDOW;
1159  else
1160  CloseHandle (console_input);
1161  }
1162 
1163  bresult = CreateProcessW (wpath, wcmd, NULL, NULL, GNUNET_YES,
1164  create_no_window | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1165  error_code = GetLastError ();
1166 
1167  if ((NULL == pipe_stdin) && (stdih))
1168  SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1169 
1170 
1171  if ((NULL == pipe_stdout) && (stdoh))
1172  SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1173 
1174  if (stdeh)
1175  SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1176 
1177  if (!bresult)
1179  "CreateProcess(%s, %s) failed: %lu\n",
1180  path,
1181  cmd,
1182  error_code);
1183 
1184  GNUNET_free (env_block);
1185  GNUNET_free (cmd);
1186  free (wpath);
1187  free (wcmd);
1188  if (GNUNET_YES == pipe_control)
1189  {
1190  GNUNET_DISK_file_close (childpipe_read);
1191  }
1192 
1193  if (!bresult)
1194  {
1195  if (GNUNET_YES == pipe_control)
1196  {
1197  GNUNET_DISK_file_close (childpipe_write);
1198  }
1199  if (NULL != lsocks)
1200  GNUNET_DISK_pipe_close (lsocks_pipe);
1201  SetErrnoFromWinError (error_code);
1202  return NULL;
1203  }
1204 
1205  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
1206  gnunet_proc->pid = proc.dwProcessId;
1207  gnunet_proc->handle = proc.hProcess;
1208  gnunet_proc->control_pipe = childpipe_write;
1209 
1210  CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1211 
1212  ResumeThread (proc.hThread);
1213  CloseHandle (proc.hThread);
1214 
1215  if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
1216  return gnunet_proc;
1217 
1219 
1220  /* This is a replacement for "goto error" that doesn't use goto */
1221  fail = 1;
1222  do
1223  {
1224  ssize_t wrote;
1225  uint64_t size;
1226  uint64_t count;
1227  unsigned int i;
1228 
1229  /* Tell the number of sockets */
1230  for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1231 
1232  wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1233  if (sizeof (count) != wrote)
1234  {
1236  "Failed to write %u count bytes to the child: %lu\n",
1237  sizeof (count), GetLastError ());
1238  break;
1239  }
1240  for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1241  {
1242  WSAPROTOCOL_INFOA pi;
1243  /* Get a socket duplication info */
1244  if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1245  {
1247  "Failed to duplicate an socket[%u]: %lu\n", i,
1248  GetLastError ());
1249  break;
1250  }
1251  /* Synchronous I/O is not nice, but we can't schedule this:
1252  * lsocks will be closed/freed by the caller soon, and until
1253  * the child creates a duplicate, closing a socket here will
1254  * close it for good.
1255  */
1256  /* Send the size of the structure
1257  * (the child might be built with different headers...)
1258  */
1259  size = sizeof (pi);
1260  wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1261  if (sizeof (size) != wrote)
1262  {
1264  "Failed to write %u size[%u] bytes to the child: %lu\n",
1265  sizeof (size), i, GetLastError ());
1266  break;
1267  }
1268  /* Finally! Send the data */
1269  wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1270  if (sizeof (pi) != wrote)
1271  {
1273  "Failed to write %u socket[%u] bytes to the child: %lu\n",
1274  sizeof (pi), i, GetLastError ());
1275  break;
1276  }
1277  }
1278  /* This will block us until the child makes a final read or closes
1279  * the pipe (hence no 'wrote' check), since we have to wait for it
1280  * to duplicate the last socket, before we return and start closing
1281  * our own copies)
1282  */
1283  wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1284  fail = 0;
1285  }
1286  while (fail);
1287 
1288  GNUNET_DISK_file_sync (lsocks_write_fd);
1289  GNUNET_DISK_pipe_close (lsocks_pipe);
1290 
1291  if (fail)
1292  {
1293  /* If we can't pass on the socket(s), the child will block forever,
1294  * better put it out of its misery.
1295  */
1296  SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1297  CloseHandle (gnunet_proc->handle);
1298  if (NULL != gnunet_proc->control_pipe)
1299  GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1300  GNUNET_free (gnunet_proc);
1301  return NULL;
1302  }
1303  return gnunet_proc;
1304 #endif
1305 }
1306 
1307 
1320 struct GNUNET_OS_Process *
1322  enum GNUNET_OS_InheritStdioFlags std_inheritance,
1323  struct GNUNET_DISK_PipeHandle *pipe_stdin,
1324  struct GNUNET_DISK_PipeHandle *pipe_stdout,
1325  struct GNUNET_DISK_PipeHandle *pipe_stderr,
1326  const char *filename,
1327  char *const argv[])
1328 {
1329  return start_process (pipe_control,
1330  std_inheritance,
1331  pipe_stdin,
1332  pipe_stdout,
1333  pipe_stderr,
1334  NULL,
1335  filename,
1336  argv);
1337 }
1338 
1339 
1352 struct GNUNET_OS_Process *
1353 GNUNET_OS_start_process_va (int pipe_control,
1354  enum GNUNET_OS_InheritStdioFlags std_inheritance,
1355  struct GNUNET_DISK_PipeHandle *pipe_stdin,
1356  struct GNUNET_DISK_PipeHandle *pipe_stdout,
1357  struct GNUNET_DISK_PipeHandle *pipe_stderr,
1358  const char *filename, va_list va)
1359 {
1360  struct GNUNET_OS_Process *ret;
1361  va_list ap;
1362  char **argv;
1363  int argc;
1364 
1365  argc = 0;
1366  va_copy (ap, va);
1367  while (NULL != va_arg (ap, char *))
1368  argc++;
1369  va_end (ap);
1370  argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1371  argc = 0;
1372  va_copy (ap, va);
1373  while (NULL != (argv[argc] = va_arg (ap, char *)))
1374  argc++;
1375  va_end (ap);
1376  ret = GNUNET_OS_start_process_vap (pipe_control,
1377  std_inheritance,
1378  pipe_stdin,
1379  pipe_stdout,
1380  pipe_stderr,
1381  filename,
1382  argv);
1383  GNUNET_free (argv);
1384  return ret;
1385 }
1386 
1387 
1399 struct GNUNET_OS_Process *
1400 GNUNET_OS_start_process (int pipe_control,
1401  enum GNUNET_OS_InheritStdioFlags std_inheritance,
1402  struct GNUNET_DISK_PipeHandle *pipe_stdin,
1403  struct GNUNET_DISK_PipeHandle *pipe_stdout,
1404  struct GNUNET_DISK_PipeHandle *pipe_stderr,
1405  const char *filename, ...)
1406 {
1407  struct GNUNET_OS_Process *ret;
1408  va_list ap;
1409 
1410  va_start (ap, filename);
1411  ret = GNUNET_OS_start_process_va (pipe_control,
1412  std_inheritance,
1413  pipe_stdin,
1414  pipe_stdout,
1415  pipe_stderr,
1416  filename,
1417  ap);
1418  va_end (ap);
1419  return ret;
1420 }
1421 
1422 
1437 struct GNUNET_OS_Process *
1438 GNUNET_OS_start_process_v (int pipe_control,
1439  enum GNUNET_OS_InheritStdioFlags std_inheritance,
1440  const SOCKTYPE *lsocks,
1441  const char *filename,
1442  char *const argv[])
1443 {
1444  return start_process (pipe_control,
1445  std_inheritance,
1446  NULL,
1447  NULL,
1448  NULL,
1449  lsocks,
1450  filename,
1451  argv);
1452 }
1453 
1454 
1473 struct GNUNET_OS_Process *
1474 GNUNET_OS_start_process_s (int pipe_control,
1475  unsigned int std_inheritance,
1476  const SOCKTYPE * lsocks,
1477  const char *filename, ...)
1478 {
1479  va_list ap;
1480  char **argv;
1481  unsigned int argv_size;
1482  const char *arg;
1483  const char *rpos;
1484  char *pos;
1485  char *cp;
1486  const char *last;
1487  struct GNUNET_OS_Process *proc;
1488  char *binary_path;
1489  int quote_on;
1490  unsigned int i;
1491  size_t len;
1492 
1493  argv_size = 1;
1494  va_start (ap, filename);
1495  arg = filename;
1496  last = NULL;
1497  do
1498  {
1499  rpos = arg;
1500  quote_on = 0;
1501  while ('\0' != *rpos)
1502  {
1503  if ('"' == *rpos)
1504  {
1505  if (1 == quote_on)
1506  quote_on = 0;
1507  else
1508  quote_on = 1;
1509  }
1510  if ( (' ' == *rpos) && (0 == quote_on) )
1511  {
1512  if (NULL != last)
1513  argv_size++;
1514  last = NULL;
1515  rpos++;
1516  while (' ' == *rpos)
1517  rpos++;
1518  }
1519  if ( (NULL == last) && ('\0' != *rpos) ) // FIXME: == or !=?
1520  last = rpos;
1521  if ('\0' != *rpos)
1522  rpos++;
1523  }
1524  if (NULL != last)
1525  argv_size++;
1526  }
1527  while (NULL != (arg = (va_arg (ap, const char*))));
1528  va_end (ap);
1529 
1530  argv = GNUNET_malloc (argv_size * sizeof (char *));
1531  argv_size = 0;
1532  va_start (ap, filename);
1533  arg = filename;
1534  last = NULL;
1535  do
1536  {
1537  cp = GNUNET_strdup (arg);
1538  quote_on = 0;
1539  pos = cp;
1540  while ('\0' != *pos)
1541  {
1542  if ('"' == *pos)
1543  {
1544  if (1 == quote_on)
1545  quote_on = 0;
1546  else
1547  quote_on = 1;
1548  }
1549  if ( (' ' == *pos) && (0 == quote_on) )
1550  {
1551  *pos = '\0';
1552  if (NULL != last)
1553  argv[argv_size++] = GNUNET_strdup (last);
1554  last = NULL;
1555  pos++;
1556  while (' ' == *pos)
1557  pos++;
1558  }
1559  if ( (NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
1560  last = pos;
1561  if ('\0' != *pos)
1562  pos++;
1563  }
1564  if (NULL != last)
1565  argv[argv_size++] = GNUNET_strdup (last);
1566  last = NULL;
1567  GNUNET_free (cp);
1568  }
1569  while (NULL != (arg = (va_arg (ap, const char*))));
1570  va_end (ap);
1571  argv[argv_size] = NULL;
1572 
1573  for(i = 0; i < argv_size; i++)
1574  {
1575  len = strlen (argv[i]);
1576  if ( (argv[i][0] == '"') && (argv[i][len-1] == '"'))
1577  {
1578  memmove (&argv[i][0], &argv[i][1], len - 2);
1579  argv[i][len-2] = '\0';
1580  }
1581  }
1582  binary_path = argv[0];
1583  proc = GNUNET_OS_start_process_v (pipe_control, std_inheritance, lsocks,
1584  binary_path, argv);
1585  while (argv_size > 0)
1586  GNUNET_free (argv[--argv_size]);
1587  GNUNET_free (argv);
1588  return proc;
1589 }
1590 
1591 
1602 static int
1605  unsigned long *code,
1606  int options)
1607 {
1608 #ifndef MINGW
1609  int status;
1610  int ret;
1611 
1612  GNUNET_assert (0 != proc);
1613  ret = waitpid (proc->pid, &status, options);
1614  if (ret < 0)
1615  {
1617  "waitpid");
1618  return GNUNET_SYSERR;
1619  }
1620  if (0 == ret)
1621  {
1622  *type = GNUNET_OS_PROCESS_RUNNING;
1623  *code = 0;
1624  return GNUNET_NO;
1625  }
1626  if (proc->pid != ret)
1627  {
1629  return GNUNET_SYSERR;
1630  }
1631  if (WIFEXITED (status))
1632  {
1633  *type = GNUNET_OS_PROCESS_EXITED;
1634  *code = WEXITSTATUS (status);
1635  }
1636  else if (WIFSIGNALED (status))
1637  {
1639  *code = WTERMSIG (status);
1640  }
1641  else if (WIFSTOPPED (status))
1642  {
1644  *code = WSTOPSIG (status);
1645  }
1646 #ifdef WIFCONTINUED
1647  else if (WIFCONTINUED (status))
1648  {
1649  *type = GNUNET_OS_PROCESS_RUNNING;
1650  *code = 0;
1651  }
1652 #endif
1653  else
1654  {
1655  *type = GNUNET_OS_PROCESS_UNKNOWN;
1656  *code = 0;
1657  }
1658 #else
1659 #ifndef WNOHANG
1660 #define WNOHANG 42 /* just a flag for W32, purely internal at this point */
1661 #endif
1662 
1663  HANDLE h;
1664  DWORD c, error_code, ret;
1665 
1666  h = proc->handle;
1667  ret = proc->pid;
1668  if (h == NULL || ret == 0)
1669  {
1671  "Invalid process information {%d, %08X}\n",
1672  ret, h);
1673  return GNUNET_SYSERR;
1674  }
1675  if (h == NULL)
1676  h = GetCurrentProcess ();
1677 
1678  if (WNOHANG != options)
1679  {
1680  if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1681  {
1682  SetErrnoFromWinError (GetLastError ());
1683  return GNUNET_SYSERR;
1684  }
1685  }
1686  SetLastError (0);
1687  ret = GetExitCodeProcess (h, &c);
1688  error_code = GetLastError ();
1689  if (ret == 0 || error_code != NO_ERROR)
1690  {
1691  SetErrnoFromWinError (error_code);
1692  LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1693  return GNUNET_SYSERR;
1694  }
1695  if (STILL_ACTIVE == c)
1696  {
1697  *type = GNUNET_OS_PROCESS_RUNNING;
1698  *code = 0;
1699  return GNUNET_NO;
1700  }
1701  *type = GNUNET_OS_PROCESS_EXITED;
1702  *code = c;
1703 #endif
1704 
1705  return GNUNET_OK;
1706 }
1707 
1708 
1718 int
1721  unsigned long *code)
1722 {
1723  return process_status (proc,
1724  type,
1725  code,
1726  WNOHANG);
1727 }
1728 
1729 
1739 int
1742  unsigned long *code)
1743 {
1744  return process_status (proc,
1745  type,
1746  code,
1747  0);
1748 }
1749 
1750 
1761 int
1763 {
1764 #ifndef MINGW
1765  pid_t pid = proc->pid;
1766  pid_t ret;
1767 
1768  while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1769  (EINTR == errno) ) ;
1770  if (pid != ret)
1771  {
1773  "waitpid");
1774  return GNUNET_SYSERR;
1775  }
1776  return GNUNET_OK;
1777 #else
1778  HANDLE h;
1779 
1780  h = proc->handle;
1781  if (NULL == h)
1782  {
1784  "Invalid process information {%d, %08X}\n",
1785  proc->pid, h);
1786  return GNUNET_SYSERR;
1787  }
1788  if (NULL == h)
1789  h = GetCurrentProcess ();
1790 
1791  if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1792  {
1793  SetErrnoFromWinError (GetLastError ());
1794  return GNUNET_SYSERR;
1795  }
1796  return GNUNET_OK;
1797 #endif
1798 }
1799 
1800 
1805 {
1806 
1811 
1816 
1820  const struct GNUNET_DISK_FileHandle *r;
1821 
1826 
1830  void *proc_cls;
1831 
1835  char buf[1024];
1836 
1841 
1846 
1850  size_t off;
1851 };
1852 
1853 
1861 void
1863 {
1864  if (NULL != cmd->proc)
1865  {
1866  GNUNET_assert (NULL != cmd->rtask);
1868  }
1869  (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1873  GNUNET_free (cmd);
1874 }
1875 
1876 
1882 static void
1883 cmd_read (void *cls)
1884 {
1885  struct GNUNET_OS_CommandHandle *cmd = cls;
1886  const struct GNUNET_SCHEDULER_TaskContext *tc;
1888  char *end;
1889  ssize_t ret;
1890 
1891  cmd->rtask = NULL;
1893  if (GNUNET_YES !=
1895  cmd->r))
1896  {
1897  /* timeout */
1898  proc = cmd->proc;
1899  cmd->proc = NULL;
1900  proc (cmd->proc_cls, NULL);
1901  return;
1902  }
1903  ret = GNUNET_DISK_file_read (cmd->r,
1904  &cmd->buf[cmd->off],
1905  sizeof (cmd->buf) - cmd->off);
1906  if (ret <= 0)
1907  {
1908  if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1909  {
1910  cmd->buf[cmd->off] = '\0';
1911  cmd->proc (cmd->proc_cls, cmd->buf);
1912  }
1913  proc = cmd->proc;
1914  cmd->proc = NULL;
1915  proc (cmd->proc_cls, NULL);
1916  return;
1917  }
1918  end = memchr (&cmd->buf[cmd->off], '\n', ret);
1919  cmd->off += ret;
1920  while (NULL != end)
1921  {
1922  *end = '\0';
1923  cmd->proc (cmd->proc_cls, cmd->buf);
1924  memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1925  cmd->off -= (end + 1 - cmd->buf);
1926  end = memchr (cmd->buf, '\n', cmd->off);
1927  }
1928  cmd->rtask
1930  (cmd->timeout),
1931  cmd->r,
1932  &cmd_read, cmd);
1933 }
1934 
1935 
1947 struct GNUNET_OS_CommandHandle *
1949  void *proc_cls,
1951  const char *binary,
1952  ...)
1953 {
1954  struct GNUNET_OS_CommandHandle *cmd;
1955  struct GNUNET_OS_Process *eip;
1956  struct GNUNET_DISK_PipeHandle *opipe;
1957  va_list ap;
1958 
1961  if (NULL == opipe)
1962  return NULL;
1963  va_start (ap, binary);
1964  /* redirect stdout, don't inherit stderr/stdin */
1965  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL,
1966  opipe, NULL, binary,
1967  ap);
1968  va_end (ap);
1969  if (NULL == eip)
1970  {
1971  GNUNET_DISK_pipe_close (opipe);
1972  return NULL;
1973  }
1975  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1976  cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1977  cmd->eip = eip;
1978  cmd->opipe = opipe;
1979  cmd->proc = proc;
1980  cmd->proc_cls = proc_cls;
1981  cmd->r = GNUNET_DISK_pipe_handle (opipe,
1983  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout,
1984  cmd->r,
1985  &cmd_read,
1986  cmd);
1987  return cmd;
1988 }
1989 
1990 
1991 /* end of os_priority.c */
void GNUNET_SIGNAL_raise(const int sig)
Raise the given signal by calling the installed signal handlers.
Definition: signal.c:120
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:746
int GNUNET_DISK_file_sync(const struct GNUNET_DISK_FileHandle *h)
Write file changes to disk.
Definition: disk.c:2133
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process...
Definition: gnunet_os_lib.h:68
When this flag is set, the child process will inherit stderr of the parent.
Definition: gnunet_os_lib.h:92
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:351
int GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1817
#define GNUNET_OS_CONTROL_PIPE
Definition: os_priority.c:38
char buf[1024]
Buffer for the output.
Definition: os_priority.c:1835
#define LOG_STRERROR(kind, syscall)
Definition: os_priority.c:34
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
Terminate a process by creating a remote thread within it, which proceeds to call ExitProcess() insid...
Definition: win.c:1288
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define SOCKTYPE
Definition: platform.h:276
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:364
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:881
int GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:1719
Context information passed to each scheduler task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1293
Return the directory where libraries are installed.
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
Definition: os_priority.c:1820
pid_t pid
PID of the process.
Definition: os_priority.c:46
size_t off
Current read offset in buf.
Definition: os_priority.c:1850
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:245
struct GNUNET_DISK_PipeHandle * opipe
Handle to the output pipe.
Definition: os_priority.c:1815
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_OS_Process * GNUNET_OS_start_process(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename,...)
Start a process.
Definition: os_priority.c:1400
When this flag is set, the child process will inherit stdin of the parent.
Definition: gnunet_os_lib.h:80
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:417
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(int pipe_control, unsigned int std_inheritance, const SOCKTYPE *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:1474
static int process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code, int options)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:1603
static void open_dev_null(int target_fd, int flags)
Open &#39;/dev/null&#39; and make the result the given file descriptor.
Definition: os_priority.c:522
#define GNUNET_NO
Definition: gnunet_common.h:81
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1643
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct GNUNET_OS_Process * GNUNET_OS_start_process_va(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, va_list va)
Start a process.
Definition: os_priority.c:1353
static struct GNUNET_PEERINFO_Handle * pi
Handle to peerinfo service.
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
struct GNUNET_TIME_Absolute timeout
When to time out.
Definition: os_priority.c:1845
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
void * proc_cls
Closure for proc.
Definition: os_priority.c:1830
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:2641
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:94
struct GNUNET_OS_Process * eip
Process handle.
Definition: os_priority.c:1810
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition: os_priority.c:76
#define FD_SETSIZE
Definition: winproc.h:39
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
#define INVALID_SOCKET
Definition: network.c:39
static void cmd_read(void *cls)
Read from the process and call the line processor.
Definition: os_priority.c:1883
struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_detach_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Detaches one of the ends from the pipe.
Definition: disk.c:2570
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:1049
When this flag is set, the child process will inherit stdout of the parent.
Definition: gnunet_os_lib.h:86
GNUNET_OS_ProcessStatusType
Process status types.
char * GNUNET_OS_installation_get_path(enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory.
struct GNUNET_OS_Process * GNUNET_OS_process_current()
Get process structure for current process.
Definition: os_priority.c:231
struct GNUNET_OS_Process * GNUNET_OS_start_process_vap(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:1321
int GNUNET_OS_process_wait_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:1740
uint16_t status
See PRISM_STATUS_*-constants.
static char buf[2048]
static char * filename
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static int result
Global testing status.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
The reading-end of a pipe.
The process exited with a return code.
void GNUNET_OS_install_parent_control_handler(void *cls)
Task that connects this process to its parent via pipe; essentially, the parent control handler will ...
Definition: os_priority.c:150
static struct GNUNET_OS_Process * start_process(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const SOCKTYPE *lsocks, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:566
int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows)
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(int blocking_read, int blocking_write, int inherit_read, int inherit_write)
Creates an interprocess channel.
Definition: disk.c:2289
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static unsigned int size
Size of the "table".
Definition: peer.c:67
int GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len)
Retrieve OS file handle.
Definition: disk.c:2665
char * getenv()
struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run(GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary,...)
Run the given command line and call the given function for each line of the output.
Definition: os_priority.c:1948
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: os_priority.c:36
The process was killed by a signal.
Return the installation directory of this application, not the one of the overall GNUnet installation...
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
#define PLIBC_KILL(p, s)
Definition: plibc.h:659
struct GNUNET_SCHEDULER_Task * rtask
Task reading from pipe.
Definition: os_priority.c:1840
int GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h)
Check if a file handle is part of an fd set.
Definition: network.c:1419
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition: os_priority.c:71
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:2603
Return the directory where the program binaries are installed.
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
int GNUNET_DISK_pipe_close_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Closes one half of an interprocess channel.
Definition: disk.c:2532
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:1762
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1937
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition: os_priority.c:59
Handle to a command.
Definition: os_priority.c:1804
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
The process is still running.
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
Definition: os_priority.c:1825
The process is not known to the OS (or at least not one of our children).
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:331
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
Definition: os_priority.c:1862
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
static struct GNUNET_OS_Process current_process
Handle for &#39;this&#39; process.
Definition: os_priority.c:66
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:282
void(* GNUNET_OS_LineProcessor)(void *cls, const char *line)
Type of a function to process a line of output.
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition: os_priority.c:85
static void parent_control_handler(void *cls)
This handler is called when there are control data to be read on the pipe.
Definition: os_priority.c:102
Handle used to access files (and pipes).
struct GNUNET_OS_Process * GNUNET_OS_start_process_v(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, const SOCKTYPE *lsocks, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:1438
Handle used to manage a pipe.
Definition: disk.c:66
#define LOG(kind,...)
Definition: os_priority.c:32
#define GNUNET_malloc(size)
Wrapper around malloc.
Internal DISK related helper functions.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
void(* GNUNET_SIGNAL_Handler)(void)
A signal handler.
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:251
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965