2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file util/os_priority.c
23 * @brief Methods to set process priority
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"
36 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
38 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
40 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
42 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
45 struct GNUNET_OS_Process
60 * Pipe we use to signal the process (if used).
62 struct GNUNET_DISK_FileHandle *control_pipe;
65 * Name of the pipe, NULL for none.
72 * Handle for 'this' process.
74 static struct GNUNET_OS_Process current_process;
77 /* MinGW version of named pipe API */
80 * Creates a named pipe/FIFO and opens it
82 * @param fn pointer to the name of the named pipe or to NULL
83 * @param flags open flags
84 * @param perm access permissions
85 * @return pipe handle on success, NULL on error
87 static struct GNUNET_DISK_FileHandle *
88 npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
89 enum GNUNET_DISK_AccessPermissions perm)
91 struct GNUNET_DISK_FileHandle *ret;
97 if (flags & GNUNET_DISK_OPEN_READWRITE)
98 openMode = PIPE_ACCESS_DUPLEX;
99 else if (flags & GNUNET_DISK_OPEN_READ)
100 openMode = PIPE_ACCESS_INBOUND;
101 else if (flags & GNUNET_DISK_OPEN_WRITE)
102 openMode = PIPE_ACCESS_OUTBOUND;
103 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
104 openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
113 GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn);
114 LOG (GNUNET_ERROR_TYPE_DEBUG,
115 "Trying to create an instance of named pipe `%s'\n", name);
116 /* 1) This might work just fine with UTF-8 strings as it is.
117 * 2) This is only used by GNUnet itself, and only with latin names.
119 h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
120 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
125 GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu",
126 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
128 LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n",
130 h = CreateNamedPipe (*fn,
131 openMode | FILE_FLAG_OVERLAPPED |
132 FILE_FLAG_FIRST_PIPE_INSTANCE,
133 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
136 error_code = GetLastError ();
139 /* don't re-set name to NULL yet */
140 if (h == INVALID_HANDLE_VALUE)
142 SetErrnoFromWinError (error_code);
143 LOG (GNUNET_ERROR_TYPE_DEBUG,
144 "Pipe creation have failed because of %d, errno is %d\n", error_code,
148 LOG (GNUNET_ERROR_TYPE_DEBUG,
149 "Pipe was to be unique, considering re-creation\n");
152 if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY)
156 LOG (GNUNET_ERROR_TYPE_DEBUG,
157 "Pipe name was not unique, trying again\n");
166 ret = GNUNET_malloc (sizeof (*ret));
168 ret->type = GNUNET_PIPE;
169 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
170 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
171 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
172 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
178 * Opens already existing named pipe/FIFO
180 * @param fn name of an existing named pipe
181 * @param flags open flags
182 * @return pipe handle on success, NULL on error
184 static struct GNUNET_DISK_FileHandle *
185 npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags)
187 struct GNUNET_DISK_FileHandle *ret;
192 if (flags & GNUNET_DISK_OPEN_READWRITE)
193 openMode = GENERIC_WRITE | GENERIC_READ;
194 else if (flags & GNUNET_DISK_OPEN_READ)
195 openMode = GENERIC_READ;
196 else if (flags & GNUNET_DISK_OPEN_WRITE)
197 openMode = GENERIC_WRITE;
199 h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
200 FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
201 if (h == INVALID_HANDLE_VALUE)
203 SetErrnoFromWinError (GetLastError ());
207 ret = GNUNET_malloc (sizeof (*ret));
209 ret->type = GNUNET_PIPE;
210 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
211 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
212 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
213 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
219 /* UNIX version of named-pipe API */
222 * Clean up a named pipe and the directory it was placed in.
224 * @param fn name of the pipe
227 cleanup_npipe (const char *fn)
232 if (0 != unlink (fn))
233 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
234 dn = GNUNET_strdup (fn);
237 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp);
243 * Setup a named pipe.
245 * @param fn where to store the name of the new pipe,
246 * if *fn is non-null, the name of the pipe to setup
247 * @return GNUNET_OK on success
250 npipe_setup (char **fn)
254 /* FIXME: hardwired '/tmp' path... is bad */
255 char dir[] = "/tmp/gnunet-pipe-XXXXXX";
257 if (NULL == mkdtemp (dir))
259 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp");
260 return GNUNET_SYSERR;
262 GNUNET_asprintf (fn, "%s/child-control", dir);
264 if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR))
265 return GNUNET_SYSERR;
271 * Open an existing named pipe.
273 * @param fn name of the file
274 * @param flags flags to use
275 * @return NULL on error
277 static struct GNUNET_DISK_FileHandle *
278 npipe_open (const char *fn,
279 enum GNUNET_DISK_OpenFlags flags)
281 struct GNUNET_DISK_FileHandle *ret;
286 /* 200 * 5ms = 1s at most */
289 fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONLY : O_WRONLY));
290 if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ))
292 /* as this is for killing a child process via pipe and it is conceivable that
293 the child process simply didn't finish starting yet, we do some sleeping
294 (which is obviously usually not allowed). We can't select on the FD as
295 'open' fails, and we probably shouldn't just "ignore" the error, so wait
296 and retry a few times is likely the best method; our process API doesn't
297 support continuations, so we need to sleep directly... */
299 req.tv_nsec = 5000000; /* 5ms */
300 (void) nanosleep (&req, NULL);
304 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
305 (flags == GNUNET_DISK_OPEN_READ)
306 ? _("Failed to open named pipe `%s' for reading: %s\n")
307 : _("Failed to open named pipe `%s' for writing: %s\n"),
312 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
320 * This handler is called when there are control data to be read on the pipe
322 * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe
323 * @param tc scheduler context
326 parent_control_handler (void *cls,
327 const struct GNUNET_SCHEDULER_TaskContext *tc)
329 struct GNUNET_DISK_FileHandle *control_pipe = cls;
333 LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
335 if (0 != (tc->reason &
336 (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT)))
338 GNUNET_DISK_file_close (control_pipe);
342 ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig));
343 if (sizeof (sig) != ret)
346 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
347 GNUNET_DISK_file_close (control_pipe);
351 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig);
352 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
353 control_pipe, &parent_control_handler,
360 * Task that connects this process to its parent via pipe;
361 * essentially, the parent control handler will read signal numbers
362 * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment
363 * variable) and raise those signals.
365 * @param cls closure (unused)
366 * @param tc scheduler context (unused)
369 GNUNET_OS_install_parent_control_handler (void *cls,
371 GNUNET_SCHEDULER_TaskContext *tc)
374 struct GNUNET_DISK_FileHandle *control_pipe;
376 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
377 if ( (env_buf == NULL) || (strlen (env_buf) <= 0) )
379 LOG (GNUNET_ERROR_TYPE_DEBUG,
380 "Not installing a handler because $%s is empty\n",
381 GNUNET_OS_CONTROL_PIPE);
382 putenv ("GNUNET_OS_CONTROL_PIPE=");
386 npipe_open (env_buf, GNUNET_DISK_OPEN_READ);
387 if (NULL == control_pipe)
389 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
390 putenv ("GNUNET_OS_CONTROL_PIPE=");
393 LOG (GNUNET_ERROR_TYPE_DEBUG,
394 "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
395 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
396 &parent_control_handler, control_pipe);
397 putenv ("GNUNET_OS_CONTROL_PIPE=");
402 * Get process structure for current process
404 * The pointer it returns points to static memory location and must not be
407 * @return pointer to the process sturcutre for this process
409 struct GNUNET_OS_Process *
410 GNUNET_OS_process_current ()
413 current_process.pid = GetCurrentProcessId ();
414 current_process.handle = GetCurrentProcess ();
416 current_process.pid = 0;
418 return ¤t_process;
423 * Sends a signal to the process
425 * @param proc pointer to process structure
427 * @return 0 on success, -1 on error
430 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
437 if ( (NULL == proc->control_pipe) &&
438 (NULL != proc->childpipename) )
439 proc->control_pipe = npipe_open (proc->childpipename,
440 GNUNET_DISK_OPEN_WRITE);
442 if (NULL != proc->control_pipe)
444 ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
445 if (ret == sizeof (csig))
448 /* pipe failed or non-existent, try other methods */
457 #if WINDOWS && !defined(__CYGWIN__)
460 int must_kill = GNUNET_YES;
461 if (0 != GetExitCodeProcess (proc->handle, &exitcode))
462 must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
463 if (GNUNET_YES == must_kill)
464 if (0 == SafeTerminateProcess (proc->handle, 0, 0))
466 DWORD error_code = GetLastError ();
467 if (error_code != WAIT_TIMEOUT) /* OK, since timeout is 0 */
469 LOG (GNUNET_ERROR_TYPE_WARNING,
470 "SafeTermiateProcess failed with code %lu\n", error_code);
471 SetErrnoFromWinError (error_code);
478 return PLIBC_KILL (proc->pid, sig);
485 return PLIBC_KILL (proc->pid, sig);
491 * Get the pid of the process in question
493 * @param proc the process to get the pid of
495 * @return the current process id
498 GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
505 * Cleans up process structure contents (OS-dependent) and deallocates it
507 * @param proc pointer to process structure
510 GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
512 if (NULL != proc->control_pipe)
513 GNUNET_DISK_file_close (proc->control_pipe);
516 if (proc->handle != NULL)
517 CloseHandle (proc->handle);
519 if (NULL != proc->childpipename)
522 cleanup_npipe (proc->childpipename);
524 GNUNET_free (proc->childpipename);
531 #include "gnunet_signal_lib.h"
533 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
536 * Make seaspider happy.
538 #define DWORD_WINAPI DWORD WINAPI
541 * @brief Waits for a process to terminate and invokes the SIGCHLD handler
542 * @param proc pointer to process structure
545 child_wait_thread (void *arg)
547 struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
549 WaitForSingleObject (proc->handle, INFINITE);
551 if (w32_sigchld_handler)
552 w32_sigchld_handler ();
560 * Set process priority
562 * @param proc pointer to process structure
563 * @param prio priority value
564 * @return GNUNET_OK on success, GNUNET_SYSERR on error
567 GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
568 enum GNUNET_SCHEDULER_Priority prio)
572 GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
573 if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
576 /* convert to MINGW/Unix values */
579 case GNUNET_SCHEDULER_PRIORITY_UI:
580 case GNUNET_SCHEDULER_PRIORITY_URGENT:
582 rprio = HIGH_PRIORITY_CLASS;
588 case GNUNET_SCHEDULER_PRIORITY_HIGH:
590 rprio = ABOVE_NORMAL_PRIORITY_CLASS;
596 case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
598 rprio = NORMAL_PRIORITY_CLASS;
604 case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
606 rprio = BELOW_NORMAL_PRIORITY_CLASS;
612 case GNUNET_SCHEDULER_PRIORITY_IDLE:
614 rprio = IDLE_PRIORITY_CLASS;
621 return GNUNET_SYSERR;
624 /* Set process priority */
627 HANDLE h = proc->handle;
629 GNUNET_assert (h != NULL);
630 SetPriorityClass (h, rprio);
636 if ((0 == pid) || (pid == getpid ()))
639 int delta = rprio - have;
642 if ((delta != 0) && (rprio == nice (delta)) && (errno != 0))
644 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice");
645 return GNUNET_SYSERR;
650 if (0 != setpriority (PRIO_PROCESS, pid, rprio))
652 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
654 return GNUNET_SYSERR;
658 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
659 "Priority management not availabe for this platform\n");
667 CreateCustomEnvTable (char **vars)
669 char *win32_env_table;
674 size_t tablesize = 0;
675 size_t items_count = 0;
684 win32_env_table = GetEnvironmentStringsA ();
685 if (win32_env_table == NULL)
687 for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
689 index = GNUNET_malloc (sizeof (char *) * n_var);
690 for (c = 0; c < n_var; c++)
692 for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
694 size_t len = strlen (ptr);
697 for (var_ptr = vars; *var_ptr; var_ptr++)
701 var_len = strlen (var);
702 if (strncmp (var, ptr, var_len) == 0)
706 tablesize += var_len + strlen (val) + 1;
711 tablesize += len + 1;
714 for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
719 n_found += strlen (var) + strlen (val) + 1;
721 result = GNUNET_malloc (tablesize + n_found + 1);
722 for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
724 size_t len = strlen (ptr);
727 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
731 var_len = strlen (var);
732 if (strncmp (var, ptr, var_len) == 0)
740 strcpy (result_ptr, ptr);
741 result_ptr += len + 1;
745 strcpy (result_ptr, var);
746 result_ptr += var_len;
747 strcpy (result_ptr, val);
748 result_ptr += strlen (val) + 1;
752 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
756 var_len = strlen (var);
759 strcpy (result_ptr, var);
760 result_ptr += var_len;
761 strcpy (result_ptr, val);
762 result_ptr += strlen (val) + 1;
765 FreeEnvironmentStrings (win32_env_table);
774 * Open '/dev/null' and make the result the given
777 * @param target_fd desired FD to point to /dev/null
778 * @param flags open flags (O_RDONLY, O_WRONLY)
781 open_dev_null (int target_fd,
786 fd = open ("/dev/null", flags);
789 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
794 if (-1 == dup2 (fd, target_fd))
796 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
800 GNUNET_break (0 == close (fd));
808 * @param pipe_control should a pipe be used to send signals to the child?
809 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
810 * std handles of the parent are inherited by the child.
811 * pipe_stdin and pipe_stdout take priority over std_inheritance
812 * (when they are non-NULL).
813 * @param pipe_stdin pipe to use to send input to child process (or NULL)
814 * @param pipe_stdout pipe to use to get output from child process (or NULL)
815 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
816 * must be NULL on platforms where dup is not supported
817 * @param filename name of the binary
818 * @param argv NULL-terminated list of arguments to the process
819 * @return process ID of the new process, -1 on error
821 static struct GNUNET_OS_Process *
822 start_process (int pipe_control,
823 enum GNUNET_OS_InheritStdioFlags std_inheritance,
824 struct GNUNET_DISK_PipeHandle *pipe_stdin,
825 struct GNUNET_DISK_PipeHandle *pipe_stdout,
826 const SOCKTYPE *lsocks,
827 const char *filename,
834 struct GNUNET_OS_Process *gnunet_proc;
835 char *childpipename = NULL;
848 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
849 return NULL; /* not executable */
850 if ( (GNUNET_YES == pipe_control) &&
851 (GNUNET_OK != npipe_setup (&childpipename)) )
853 if (NULL != pipe_stdout)
855 GNUNET_assert (GNUNET_OK ==
856 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
858 GNUNET_DISK_PIPE_END_WRITE),
859 &fd_stdout_write, sizeof (int)));
860 GNUNET_assert (GNUNET_OK ==
861 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
862 (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
863 &fd_stdout_read, sizeof (int)));
865 if (NULL != pipe_stdin)
867 GNUNET_assert (GNUNET_OK ==
868 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
869 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
870 &fd_stdin_read, sizeof (int)));
871 GNUNET_assert (GNUNET_OK ==
872 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
873 (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
874 &fd_stdin_write, sizeof (int)));
881 while (-1 != (k = lsocks[i++]))
882 GNUNET_array_append (lscp, ls, k);
883 GNUNET_array_append (lscp, ls, -1);
890 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
891 GNUNET_free_non_null (childpipename);
892 GNUNET_array_grow (lscp, ls, 0);
898 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
899 gnunet_proc->pid = ret;
900 gnunet_proc->childpipename = childpipename;
901 GNUNET_array_grow (lscp, ls, 0);
904 if (NULL != childpipename)
906 setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
907 GNUNET_free (childpipename);
909 if (NULL != pipe_stdin)
911 GNUNET_break (0 == close (fd_stdin_write));
912 if (-1 == dup2 (fd_stdin_read, 0))
913 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
914 GNUNET_break (0 == close (fd_stdin_read));
916 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
918 GNUNET_break (0 == close (0));
919 open_dev_null (0, O_RDONLY);
921 if (NULL != pipe_stdout)
923 GNUNET_break (0 == close (fd_stdout_read));
924 if (-1 == dup2 (fd_stdout_write, 1))
925 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
926 GNUNET_break (0 == close (fd_stdout_write));
928 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
930 GNUNET_break (0 == close (1));
931 open_dev_null (1, O_WRONLY);
933 if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
935 GNUNET_break (0 == close (2));
936 open_dev_null (2, O_WRONLY);
940 /* read systemd documentation... */
941 GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
942 setenv ("LISTEN_PID", lpid, 1);
945 while (-1 != lscp[i])
948 while (-1 != lscp[j])
954 GNUNET_assert (-1 != k);
955 GNUNET_assert (0 == close (lscp[j]));
963 /* Bury any existing FD, no matter what; they should all be closed
964 * on exec anyway and the important onces have been dup'ed away */
966 GNUNET_assert (-1 != dup2 (lscp[i], tgt));
968 /* unset close-on-exec flag */
969 flags = fcntl (tgt, F_GETFD);
970 GNUNET_assert (flags >= 0);
971 flags &= ~FD_CLOEXEC;
973 (void) fcntl (tgt, F_SETFD, flags);
977 GNUNET_snprintf (fds, sizeof (fds), "%u", i);
978 setenv ("LISTEN_FDS", fds, 1);
980 GNUNET_array_grow (lscp, ls, 0);
981 execvp (filename, argv);
982 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
985 struct GNUNET_DISK_FileHandle *control_pipe;
986 char *childpipename = NULL;
988 char **non_const_argv;
993 PROCESS_INFORMATION proc;
995 struct GNUNET_OS_Process *gnunet_proc;
996 char path[MAX_PATH + 1];
997 char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
998 char *env_block = NULL;
1006 char *non_const_filename;
1007 char win_path[MAX_PATH + 1];
1008 struct GNUNET_DISK_PipeHandle *lsocks_pipe;
1009 const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
1011 HANDLE lsocks_write;
1019 HANDLE stdin_handle;
1020 HANDLE stdout_handle;
1021 HANDLE stdih, stdoh, stdeh;
1022 DWORD stdif, stdof, stdef;
1026 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
1027 return NULL; /* not executable */
1029 /* Search in prefix dir (hopefully - the directory from which
1030 * the current module was loaded), bindir and libdir, then in PATH
1032 self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
1033 bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
1034 libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
1036 pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
1039 pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
1042 pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
1045 ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
1046 GNUNET_free (self_prefix);
1047 GNUNET_free (bindir);
1048 GNUNET_free (libdir);
1050 alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
1051 if (alloc_len != pathbuf_len - 1)
1053 GNUNET_free (pathbuf);
1054 errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
1058 cmdlen = strlen (filename);
1059 if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
1060 GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
1062 GNUNET_asprintf (&non_const_filename, "%s", filename);
1064 /* It could be in POSIX form, convert it to a DOS path early on */
1065 if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
1067 SetErrnoFromWinError (lRet);
1068 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
1069 non_const_filename);
1070 GNUNET_free (non_const_filename);
1071 GNUNET_free (pathbuf);
1074 GNUNET_free (non_const_filename);
1075 non_const_filename = GNUNET_strdup (win_path);
1076 /* Check that this is the full path. If it isn't, search. */
1077 /* FIXME: convert it to wchar_t and use SearchPathW?
1078 * Remember: arguments to _start_process() are technically in UTF-8...
1080 if (non_const_filename[1] == ':')
1081 snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
1082 else if (!SearchPathA
1083 (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
1086 SetErrnoFromWinError (GetLastError ());
1087 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
1088 non_const_filename);
1089 GNUNET_free (non_const_filename);
1090 GNUNET_free (pathbuf);
1093 GNUNET_free (pathbuf);
1094 GNUNET_free (non_const_filename);
1096 /* Count the number of arguments */
1097 arg = (char **) argv;
1104 /* Allocate a copy argv */
1105 non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
1107 /* Copy all argv strings */
1109 arg = (char **) argv;
1113 non_const_argv[argcount] = GNUNET_strdup (path);
1115 non_const_argv[argcount] = GNUNET_strdup (*arg);
1119 non_const_argv[argcount] = NULL;
1123 arg = non_const_argv;
1126 cmdlen = cmdlen + strlen (*arg) + 4;
1130 /* Allocate and create cmd */
1131 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
1132 arg = non_const_argv;
1135 char arg_last_char = (*arg)[strlen (*arg) - 1];
1136 idx += sprintf (idx, "\"%s%s\"%s", *arg,
1137 arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
1141 while (argcount > 0)
1142 GNUNET_free (non_const_argv[--argcount]);
1143 GNUNET_free (non_const_argv);
1145 memset (&start, 0, sizeof (start));
1146 start.cb = sizeof (start);
1147 if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
1148 start.dwFlags |= STARTF_USESTDHANDLES;
1150 stdih = GetStdHandle (STD_INPUT_HANDLE);
1151 GetHandleInformation (stdih, &stdif);
1152 if (pipe_stdin != NULL)
1154 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1155 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
1156 &stdin_handle, sizeof (HANDLE));
1157 start.hStdInput = stdin_handle;
1161 if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1163 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
1164 if (pipe_stdin == NULL)
1165 start.hStdInput = stdih;
1168 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1172 stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1173 GetHandleInformation (stdoh, &stdof);
1174 if (NULL != pipe_stdout)
1176 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1178 GNUNET_DISK_PIPE_END_WRITE),
1179 &stdout_handle, sizeof (HANDLE));
1180 start.hStdOutput = stdout_handle;
1184 if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1186 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1187 if (pipe_stdout == NULL)
1188 start.hStdOutput = stdoh;
1191 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1194 stdeh = GetStdHandle (STD_ERROR_HANDLE);
1195 GetHandleInformation (stdeh, &stdef);
1198 if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1200 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1201 start.hStdError = stdeh;
1204 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1207 if (GNUNET_YES == pipe_control)
1210 npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
1211 GNUNET_DISK_PERM_USER_READ |
1212 GNUNET_DISK_PERM_USER_WRITE);
1213 if (control_pipe == NULL)
1221 control_pipe = NULL;
1222 if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1224 lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1226 if (lsocks_pipe == NULL)
1230 GNUNET_DISK_pipe_close (lsocks_pipe);
1233 lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1234 GNUNET_DISK_PIPE_END_WRITE);
1235 GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1236 &lsocks_write, sizeof (HANDLE));
1237 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1238 (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1239 &lsocks_read, sizeof (HANDLE));
1243 if (NULL != childpipename)
1245 LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
1247 GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1248 GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
1249 GNUNET_free (childpipename);
1251 if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1253 /*This will tell the child that we're going to send lsocks over the pipe*/
1254 GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1255 GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1257 our_env[env_off++] = NULL;
1258 env_block = CreateCustomEnvTable (our_env);
1260 GNUNET_free_non_null (our_env[--env_off]);
1263 if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1265 LOG (GNUNET_ERROR_TYPE_DEBUG,
1266 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1267 GNUNET_free (env_block);
1273 if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1275 LOG (GNUNET_ERROR_TYPE_DEBUG,
1276 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1277 GNUNET_free (env_block);
1283 bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
1284 DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1285 error_code = GetLastError ();
1287 if ((NULL == pipe_stdin) && (stdih))
1288 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1291 if ((NULL == pipe_stdout) && (stdoh))
1292 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1295 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1297 GNUNET_free (env_block);
1304 SetErrnoFromWinError (error_code);
1305 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1306 if (NULL != control_pipe)
1307 GNUNET_DISK_file_close (control_pipe);
1309 GNUNET_DISK_pipe_close (lsocks_pipe);
1313 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1314 gnunet_proc->pid = proc.dwProcessId;
1315 gnunet_proc->handle = proc.hProcess;
1316 gnunet_proc->control_pipe = control_pipe;
1318 CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1320 ResumeThread (proc.hThread);
1321 CloseHandle (proc.hThread);
1323 if (lsocks == NULL || lsocks[0] == INVALID_SOCKET)
1326 GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1328 /* This is a replacement for "goto error" that doesn't use goto */
1333 uint64_t size, count, i;
1335 /* Tell the number of sockets */
1336 for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1338 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1339 if (wrote != sizeof (count))
1341 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ());
1344 for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1346 WSAPROTOCOL_INFOA pi;
1347 /* Get a socket duplication info */
1348 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1350 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ());
1351 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1354 /* Synchronous I/O is not nice, but we can't schedule this:
1355 * lsocks will be closed/freed by the caller soon, and until
1356 * the child creates a duplicate, closing a socket here will
1357 * close it for good.
1359 /* Send the size of the structure
1360 * (the child might be built with different headers...)
1363 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1364 if (wrote != sizeof (size))
1366 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ());
1369 /* Finally! Send the data */
1370 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1371 if (wrote != sizeof (pi))
1373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ());
1377 /* This will block us until the child makes a final read or closes
1378 * the pipe (hence no 'wrote' check), since we have to wait for it
1379 * to duplicate the last socket, before we return and start closing
1382 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1387 GNUNET_DISK_file_sync (lsocks_write_fd);
1388 GNUNET_DISK_pipe_close (lsocks_pipe);
1392 /* If we can't pass on the socket(s), the child will block forever,
1393 * better put it out of its misery.
1395 SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1396 CloseHandle (gnunet_proc->handle);
1397 if (NULL != gnunet_proc->control_pipe)
1398 GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1399 GNUNET_free (gnunet_proc);
1412 * @param pipe_control should a pipe be used to send signals to the child?
1413 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1414 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1415 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1416 * @param filename name of the binary
1417 * @param argv NULL-terminated array of arguments to the process
1418 * @return pointer to process structure of the new process, NULL on error
1420 struct GNUNET_OS_Process *
1421 GNUNET_OS_start_process_vap (int pipe_control,
1422 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1423 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1424 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1425 const char *filename,
1428 return start_process (pipe_control,
1441 * @param pipe_control should a pipe be used to send signals to the child?
1442 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1443 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1444 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1445 * @param filename name of the binary
1446 * @param va NULL-terminated list of arguments to the process
1447 * @return pointer to process structure of the new process, NULL on error
1449 struct GNUNET_OS_Process *
1450 GNUNET_OS_start_process_va (int pipe_control,
1451 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1452 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1453 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1454 const char *filename, va_list va)
1456 struct GNUNET_OS_Process *ret;
1463 while (NULL != va_arg (ap, char *))
1466 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1469 while (NULL != (argv[argc] = va_arg (ap, char *)))
1472 ret = GNUNET_OS_start_process_vap (pipe_control,
1487 * @param pipe_control should a pipe be used to send signals to the child?
1488 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1489 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1490 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1491 * @param filename name of the binary
1492 * @param ... NULL-terminated list of arguments to the process
1494 * @return pointer to process structure of the new process, NULL on error
1497 struct GNUNET_OS_Process *
1498 GNUNET_OS_start_process (int pipe_control,
1499 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1500 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1501 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1502 const char *filename, ...)
1504 struct GNUNET_OS_Process *ret;
1507 va_start (ap, filename);
1508 ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1509 pipe_stdout, filename, ap);
1518 * @param pipe_control should a pipe be used to send signals to the child?
1519 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1520 * must be NULL on platforms where dup is not supported
1521 * @param filename name of the binary
1522 * @param argv NULL-terminated list of arguments to the process
1523 * @return process ID of the new process, -1 on error
1525 struct GNUNET_OS_Process *
1526 GNUNET_OS_start_process_v (int pipe_control,
1527 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1528 const SOCKTYPE *lsocks,
1529 const char *filename,
1532 return start_process (pipe_control,
1543 * Retrieve the status of a process, waiting on him if dead.
1544 * Nonblocking version.
1546 * @param proc process ID
1547 * @param type status type
1548 * @param code return code/signal number
1549 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1552 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1553 enum GNUNET_OS_ProcessStatusType *type,
1554 unsigned long *code)
1560 GNUNET_assert (0 != proc);
1561 ret = waitpid (proc->pid, &status, WNOHANG);
1564 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1565 return GNUNET_SYSERR;
1569 *type = GNUNET_OS_PROCESS_RUNNING;
1573 if (proc->pid != ret)
1575 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1576 return GNUNET_SYSERR;
1578 if (WIFEXITED (status))
1580 *type = GNUNET_OS_PROCESS_EXITED;
1581 *code = WEXITSTATUS (status);
1583 else if (WIFSIGNALED (status))
1585 *type = GNUNET_OS_PROCESS_SIGNALED;
1586 *code = WTERMSIG (status);
1588 else if (WIFSTOPPED (status))
1590 *type = GNUNET_OS_PROCESS_SIGNALED;
1591 *code = WSTOPSIG (status);
1594 else if (WIFCONTINUED (status))
1596 *type = GNUNET_OS_PROCESS_RUNNING;
1602 *type = GNUNET_OS_PROCESS_UNKNOWN;
1607 DWORD c, error_code, ret;
1611 if (h == NULL || ret == 0)
1613 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1615 return GNUNET_SYSERR;
1618 h = GetCurrentProcess ();
1621 ret = GetExitCodeProcess (h, &c);
1622 error_code = GetLastError ();
1623 if (ret == 0 || error_code != NO_ERROR)
1625 SetErrnoFromWinError (error_code);
1626 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1627 return GNUNET_SYSERR;
1629 if (STILL_ACTIVE == c)
1631 *type = GNUNET_OS_PROCESS_RUNNING;
1635 *type = GNUNET_OS_PROCESS_EXITED;
1644 * Wait for a process
1645 * @param proc pointer to process structure
1646 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1649 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1653 pid_t pid = proc->pid;
1656 while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1657 (EINTR == errno) ) ;
1660 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1661 return GNUNET_SYSERR;
1671 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1673 return GNUNET_SYSERR;
1676 h = GetCurrentProcess ();
1678 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1680 SetErrnoFromWinError (GetLastError ());
1681 ret = GNUNET_SYSERR;
1692 * Handle to a command.
1694 struct GNUNET_OS_CommandHandle
1700 struct GNUNET_OS_Process *eip;
1703 * Handle to the output pipe.
1705 struct GNUNET_DISK_PipeHandle *opipe;
1708 * Read-end of output pipe.
1710 const struct GNUNET_DISK_FileHandle *r;
1713 * Function to call on each line of output.
1715 GNUNET_OS_LineProcessor proc;
1718 * Closure for 'proc'.
1723 * Buffer for the output.
1728 * Task reading from pipe.
1730 GNUNET_SCHEDULER_TaskIdentifier rtask;
1735 struct GNUNET_TIME_Absolute timeout;
1738 * Current read offset in buf.
1745 * Stop/kill a command. Must ONLY be called either from
1746 * the callback after 'NULL' was passed for 'line' *OR*
1747 * from an independent task (not within the line processor).
1749 * @param cmd handle to the process
1752 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1755 if (cmd->proc != NULL)
1757 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1758 GNUNET_SCHEDULER_cancel (cmd->rtask);
1760 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1761 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1762 GNUNET_OS_process_destroy (cmd->eip);
1763 GNUNET_DISK_pipe_close (cmd->opipe);
1769 * Read from the process and call the line processor.
1771 * @param cls the 'struct GNUNET_OS_CommandHandle'
1772 * @param tc scheduler context
1775 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1777 struct GNUNET_OS_CommandHandle *cmd = cls;
1778 GNUNET_OS_LineProcessor proc;
1782 cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1783 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1785 /* timeout, shutdown, etc. */
1788 proc (cmd->proc_cls, NULL);
1792 GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1793 sizeof (cmd->buf) - cmd->off);
1796 if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1798 cmd->buf[cmd->off] = '\0';
1799 cmd->proc (cmd->proc_cls, cmd->buf);
1803 proc (cmd->proc_cls, NULL);
1806 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1811 cmd->proc (cmd->proc_cls, cmd->buf);
1812 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1813 cmd->off -= (end + 1 - cmd->buf);
1814 end = memchr (cmd->buf, '\n', cmd->off);
1817 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1818 (cmd->timeout), cmd->r, &cmd_read, cmd);
1823 * Run the given command line and call the given function
1824 * for each line of the output.
1826 * @param proc function to call for each line of the output
1827 * @param proc_cls closure for proc
1828 * @param timeout when to time out
1829 * @param binary command to run
1830 * @param ... arguments to command
1831 * @return NULL on error
1833 struct GNUNET_OS_CommandHandle *
1834 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1835 struct GNUNET_TIME_Relative timeout, const char *binary,
1838 struct GNUNET_OS_CommandHandle *cmd;
1839 struct GNUNET_OS_Process *eip;
1840 struct GNUNET_DISK_PipeHandle *opipe;
1843 opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1846 va_start (ap, binary);
1847 /* redirect stdout, don't inherit stderr/stdin */
1848 eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1852 GNUNET_DISK_pipe_close (opipe);
1855 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1856 cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1857 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1861 cmd->proc_cls = proc_cls;
1862 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1863 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1870 /* end of os_priority.c */