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) && (error_code != ERROR_PROCESS_ABORTED))
469 LOG ((error_code == ERROR_ACCESS_DENIED) ?
470 GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
471 "SafeTermiateProcess failed with code %lu\n", error_code);
472 /* The problem here is that a process that is already dying
473 * might cause SafeTerminateProcess to fail with
474 * ERROR_ACCESS_DENIED, but the process WILL die eventually.
475 * If we really had a permissions problem, hanging up (which
476 * is what will happen in process_wait() in that case) is
479 if (error_code == ERROR_ACCESS_DENIED)
485 SetErrnoFromWinError (error_code);
493 return PLIBC_KILL (proc->pid, sig);
500 return PLIBC_KILL (proc->pid, sig);
506 * Get the pid of the process in question
508 * @param proc the process to get the pid of
510 * @return the current process id
513 GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
520 * Cleans up process structure contents (OS-dependent) and deallocates it
522 * @param proc pointer to process structure
525 GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
527 if (NULL != proc->control_pipe)
528 GNUNET_DISK_file_close (proc->control_pipe);
531 if (proc->handle != NULL)
532 CloseHandle (proc->handle);
534 if (NULL != proc->childpipename)
537 cleanup_npipe (proc->childpipename);
539 GNUNET_free (proc->childpipename);
546 #include "gnunet_signal_lib.h"
548 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
551 * Make seaspider happy.
553 #define DWORD_WINAPI DWORD WINAPI
556 * @brief Waits for a process to terminate and invokes the SIGCHLD handler
557 * @param proc pointer to process structure
560 child_wait_thread (void *arg)
562 struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
564 WaitForSingleObject (proc->handle, INFINITE);
566 if (w32_sigchld_handler)
567 w32_sigchld_handler ();
575 * Set process priority
577 * @param proc pointer to process structure
578 * @param prio priority value
579 * @return GNUNET_OK on success, GNUNET_SYSERR on error
582 GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
583 enum GNUNET_SCHEDULER_Priority prio)
587 GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
588 if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
591 /* convert to MINGW/Unix values */
594 case GNUNET_SCHEDULER_PRIORITY_UI:
595 case GNUNET_SCHEDULER_PRIORITY_URGENT:
597 rprio = HIGH_PRIORITY_CLASS;
603 case GNUNET_SCHEDULER_PRIORITY_HIGH:
605 rprio = ABOVE_NORMAL_PRIORITY_CLASS;
611 case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
613 rprio = NORMAL_PRIORITY_CLASS;
619 case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
621 rprio = BELOW_NORMAL_PRIORITY_CLASS;
627 case GNUNET_SCHEDULER_PRIORITY_IDLE:
629 rprio = IDLE_PRIORITY_CLASS;
636 return GNUNET_SYSERR;
639 /* Set process priority */
642 HANDLE h = proc->handle;
644 GNUNET_assert (h != NULL);
645 SetPriorityClass (h, rprio);
651 if ((0 == pid) || (pid == getpid ()))
654 int delta = rprio - have;
657 if ((delta != 0) && (rprio == nice (delta)) && (errno != 0))
659 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice");
660 return GNUNET_SYSERR;
665 if (0 != setpriority (PRIO_PROCESS, pid, rprio))
667 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
669 return GNUNET_SYSERR;
673 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
674 "Priority management not availabe for this platform\n");
682 CreateCustomEnvTable (char **vars)
684 char *win32_env_table;
689 size_t tablesize = 0;
690 size_t items_count = 0;
699 win32_env_table = GetEnvironmentStringsA ();
700 if (win32_env_table == NULL)
702 for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
704 index = GNUNET_malloc (sizeof (char *) * n_var);
705 for (c = 0; c < n_var; c++)
707 for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
709 size_t len = strlen (ptr);
712 for (var_ptr = vars; *var_ptr; var_ptr++)
716 var_len = strlen (var);
717 if (strncmp (var, ptr, var_len) == 0)
721 tablesize += var_len + strlen (val) + 1;
726 tablesize += len + 1;
729 for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
734 n_found += strlen (var) + strlen (val) + 1;
736 result = GNUNET_malloc (tablesize + n_found + 1);
737 for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
739 size_t len = strlen (ptr);
742 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
746 var_len = strlen (var);
747 if (strncmp (var, ptr, var_len) == 0)
755 strcpy (result_ptr, ptr);
756 result_ptr += len + 1;
760 strcpy (result_ptr, var);
761 result_ptr += var_len;
762 strcpy (result_ptr, val);
763 result_ptr += strlen (val) + 1;
767 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
771 var_len = strlen (var);
774 strcpy (result_ptr, var);
775 result_ptr += var_len;
776 strcpy (result_ptr, val);
777 result_ptr += strlen (val) + 1;
780 FreeEnvironmentStrings (win32_env_table);
789 * Open '/dev/null' and make the result the given
792 * @param target_fd desired FD to point to /dev/null
793 * @param flags open flags (O_RDONLY, O_WRONLY)
796 open_dev_null (int target_fd,
801 fd = open ("/dev/null", flags);
804 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
809 if (-1 == dup2 (fd, target_fd))
811 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
815 GNUNET_break (0 == close (fd));
823 * @param pipe_control should a pipe be used to send signals to the child?
824 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
825 * std handles of the parent are inherited by the child.
826 * pipe_stdin and pipe_stdout take priority over std_inheritance
827 * (when they are non-NULL).
828 * @param pipe_stdin pipe to use to send input to child process (or NULL)
829 * @param pipe_stdout pipe to use to get output from child process (or NULL)
830 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
831 * must be NULL on platforms where dup is not supported
832 * @param filename name of the binary
833 * @param argv NULL-terminated list of arguments to the process
834 * @return process ID of the new process, -1 on error
836 static struct GNUNET_OS_Process *
837 start_process (int pipe_control,
838 enum GNUNET_OS_InheritStdioFlags std_inheritance,
839 struct GNUNET_DISK_PipeHandle *pipe_stdin,
840 struct GNUNET_DISK_PipeHandle *pipe_stdout,
841 const SOCKTYPE *lsocks,
842 const char *filename,
849 struct GNUNET_OS_Process *gnunet_proc;
850 char *childpipename = NULL;
863 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
864 return NULL; /* not executable */
865 if ( (GNUNET_YES == pipe_control) &&
866 (GNUNET_OK != npipe_setup (&childpipename)) )
868 if (NULL != pipe_stdout)
870 GNUNET_assert (GNUNET_OK ==
871 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
873 GNUNET_DISK_PIPE_END_WRITE),
874 &fd_stdout_write, sizeof (int)));
875 GNUNET_assert (GNUNET_OK ==
876 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
877 (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
878 &fd_stdout_read, sizeof (int)));
880 if (NULL != pipe_stdin)
882 GNUNET_assert (GNUNET_OK ==
883 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
884 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
885 &fd_stdin_read, sizeof (int)));
886 GNUNET_assert (GNUNET_OK ==
887 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
888 (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
889 &fd_stdin_write, sizeof (int)));
896 while (-1 != (k = lsocks[i++]))
897 GNUNET_array_append (lscp, ls, k);
898 GNUNET_array_append (lscp, ls, -1);
905 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
906 GNUNET_free_non_null (childpipename);
907 GNUNET_array_grow (lscp, ls, 0);
913 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
914 gnunet_proc->pid = ret;
915 gnunet_proc->childpipename = childpipename;
916 GNUNET_array_grow (lscp, ls, 0);
919 if (NULL != childpipename)
921 setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
922 GNUNET_free (childpipename);
924 if (NULL != pipe_stdin)
926 GNUNET_break (0 == close (fd_stdin_write));
927 if (-1 == dup2 (fd_stdin_read, 0))
928 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
929 GNUNET_break (0 == close (fd_stdin_read));
931 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
933 GNUNET_break (0 == close (0));
934 open_dev_null (0, O_RDONLY);
936 if (NULL != pipe_stdout)
938 GNUNET_break (0 == close (fd_stdout_read));
939 if (-1 == dup2 (fd_stdout_write, 1))
940 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
941 GNUNET_break (0 == close (fd_stdout_write));
943 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
945 GNUNET_break (0 == close (1));
946 open_dev_null (1, O_WRONLY);
948 if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
950 GNUNET_break (0 == close (2));
951 open_dev_null (2, O_WRONLY);
955 /* read systemd documentation... */
956 GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
957 setenv ("LISTEN_PID", lpid, 1);
960 while (-1 != lscp[i])
963 while (-1 != lscp[j])
969 GNUNET_assert (-1 != k);
970 GNUNET_assert (0 == close (lscp[j]));
978 /* Bury any existing FD, no matter what; they should all be closed
979 * on exec anyway and the important onces have been dup'ed away */
981 GNUNET_assert (-1 != dup2 (lscp[i], tgt));
983 /* unset close-on-exec flag */
984 flags = fcntl (tgt, F_GETFD);
985 GNUNET_assert (flags >= 0);
986 flags &= ~FD_CLOEXEC;
988 (void) fcntl (tgt, F_SETFD, flags);
992 GNUNET_snprintf (fds, sizeof (fds), "%u", i);
993 setenv ("LISTEN_FDS", fds, 1);
995 GNUNET_array_grow (lscp, ls, 0);
996 execvp (filename, argv);
997 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
1000 struct GNUNET_DISK_FileHandle *control_pipe;
1001 char *childpipename = NULL;
1003 char **non_const_argv;
1004 unsigned int cmdlen;
1008 PROCESS_INFORMATION proc;
1010 struct GNUNET_OS_Process *gnunet_proc;
1011 char path[MAX_PATH + 1];
1012 char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
1013 char *env_block = NULL;
1021 char *non_const_filename;
1022 char win_path[MAX_PATH + 1];
1023 struct GNUNET_DISK_PipeHandle *lsocks_pipe;
1024 const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
1026 HANDLE lsocks_write;
1034 HANDLE stdin_handle;
1035 HANDLE stdout_handle;
1036 HANDLE stdih, stdoh, stdeh;
1037 DWORD stdif, stdof, stdef;
1041 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
1042 return NULL; /* not executable */
1044 /* Search in prefix dir (hopefully - the directory from which
1045 * the current module was loaded), bindir and libdir, then in PATH
1047 self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
1048 bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
1049 libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
1051 pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
1054 pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
1057 pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
1060 ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
1061 GNUNET_free (self_prefix);
1062 GNUNET_free (bindir);
1063 GNUNET_free (libdir);
1065 alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
1066 if (alloc_len != pathbuf_len - 1)
1068 GNUNET_free (pathbuf);
1069 errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
1073 cmdlen = strlen (filename);
1074 if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
1075 GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
1077 GNUNET_asprintf (&non_const_filename, "%s", filename);
1079 /* It could be in POSIX form, convert it to a DOS path early on */
1080 if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
1082 SetErrnoFromWinError (lRet);
1083 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
1084 non_const_filename);
1085 GNUNET_free (non_const_filename);
1086 GNUNET_free (pathbuf);
1089 GNUNET_free (non_const_filename);
1090 non_const_filename = GNUNET_strdup (win_path);
1091 /* Check that this is the full path. If it isn't, search. */
1092 /* FIXME: convert it to wchar_t and use SearchPathW?
1093 * Remember: arguments to _start_process() are technically in UTF-8...
1095 if (non_const_filename[1] == ':')
1096 snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
1097 else if (!SearchPathA
1098 (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
1101 SetErrnoFromWinError (GetLastError ());
1102 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
1103 non_const_filename);
1104 GNUNET_free (non_const_filename);
1105 GNUNET_free (pathbuf);
1108 GNUNET_free (pathbuf);
1109 GNUNET_free (non_const_filename);
1111 /* Count the number of arguments */
1112 arg = (char **) argv;
1119 /* Allocate a copy argv */
1120 non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
1122 /* Copy all argv strings */
1124 arg = (char **) argv;
1128 non_const_argv[argcount] = GNUNET_strdup (path);
1130 non_const_argv[argcount] = GNUNET_strdup (*arg);
1134 non_const_argv[argcount] = NULL;
1138 arg = non_const_argv;
1141 cmdlen = cmdlen + strlen (*arg) + 4;
1145 /* Allocate and create cmd */
1146 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
1147 arg = non_const_argv;
1150 char arg_last_char = (*arg)[strlen (*arg) - 1];
1151 idx += sprintf (idx, "\"%s%s\"%s", *arg,
1152 arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
1156 while (argcount > 0)
1157 GNUNET_free (non_const_argv[--argcount]);
1158 GNUNET_free (non_const_argv);
1160 memset (&start, 0, sizeof (start));
1161 start.cb = sizeof (start);
1162 if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
1163 start.dwFlags |= STARTF_USESTDHANDLES;
1165 stdih = GetStdHandle (STD_INPUT_HANDLE);
1166 GetHandleInformation (stdih, &stdif);
1167 if (pipe_stdin != NULL)
1169 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1170 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
1171 &stdin_handle, sizeof (HANDLE));
1172 start.hStdInput = stdin_handle;
1176 if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1178 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
1179 if (pipe_stdin == NULL)
1180 start.hStdInput = stdih;
1183 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1187 stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1188 GetHandleInformation (stdoh, &stdof);
1189 if (NULL != pipe_stdout)
1191 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1193 GNUNET_DISK_PIPE_END_WRITE),
1194 &stdout_handle, sizeof (HANDLE));
1195 start.hStdOutput = stdout_handle;
1199 if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1201 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1202 if (pipe_stdout == NULL)
1203 start.hStdOutput = stdoh;
1206 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1209 stdeh = GetStdHandle (STD_ERROR_HANDLE);
1210 GetHandleInformation (stdeh, &stdef);
1213 if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1215 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1216 start.hStdError = stdeh;
1219 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1222 if (GNUNET_YES == pipe_control)
1225 npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
1226 GNUNET_DISK_PERM_USER_READ |
1227 GNUNET_DISK_PERM_USER_WRITE);
1228 if (control_pipe == NULL)
1236 control_pipe = NULL;
1237 if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1239 lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1241 if (lsocks_pipe == NULL)
1245 GNUNET_DISK_pipe_close (lsocks_pipe);
1248 lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1249 GNUNET_DISK_PIPE_END_WRITE);
1250 GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1251 &lsocks_write, sizeof (HANDLE));
1252 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1253 (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1254 &lsocks_read, sizeof (HANDLE));
1258 if (NULL != childpipename)
1260 LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
1262 GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1263 GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
1264 GNUNET_free (childpipename);
1266 if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1268 /*This will tell the child that we're going to send lsocks over the pipe*/
1269 GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1270 GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1272 our_env[env_off++] = NULL;
1273 env_block = CreateCustomEnvTable (our_env);
1275 GNUNET_free_non_null (our_env[--env_off]);
1278 if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1280 LOG (GNUNET_ERROR_TYPE_DEBUG,
1281 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1282 GNUNET_free (env_block);
1288 if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1290 LOG (GNUNET_ERROR_TYPE_DEBUG,
1291 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1292 GNUNET_free (env_block);
1298 bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
1299 DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1300 error_code = GetLastError ();
1302 if ((NULL == pipe_stdin) && (stdih))
1303 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1306 if ((NULL == pipe_stdout) && (stdoh))
1307 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1310 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1312 GNUNET_free (env_block);
1319 SetErrnoFromWinError (error_code);
1320 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1321 if (NULL != control_pipe)
1322 GNUNET_DISK_file_close (control_pipe);
1324 GNUNET_DISK_pipe_close (lsocks_pipe);
1328 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1329 gnunet_proc->pid = proc.dwProcessId;
1330 gnunet_proc->handle = proc.hProcess;
1331 gnunet_proc->control_pipe = control_pipe;
1333 CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1335 ResumeThread (proc.hThread);
1336 CloseHandle (proc.hThread);
1338 if (lsocks == NULL || lsocks[0] == INVALID_SOCKET)
1341 GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1343 /* This is a replacement for "goto error" that doesn't use goto */
1348 uint64_t size, count, i;
1350 /* Tell the number of sockets */
1351 for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1353 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1354 if (wrote != sizeof (count))
1356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ());
1359 for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1361 WSAPROTOCOL_INFOA pi;
1362 /* Get a socket duplication info */
1363 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ());
1366 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1369 /* Synchronous I/O is not nice, but we can't schedule this:
1370 * lsocks will be closed/freed by the caller soon, and until
1371 * the child creates a duplicate, closing a socket here will
1372 * close it for good.
1374 /* Send the size of the structure
1375 * (the child might be built with different headers...)
1378 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1379 if (wrote != sizeof (size))
1381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ());
1384 /* Finally! Send the data */
1385 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1386 if (wrote != sizeof (pi))
1388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ());
1392 /* This will block us until the child makes a final read or closes
1393 * the pipe (hence no 'wrote' check), since we have to wait for it
1394 * to duplicate the last socket, before we return and start closing
1397 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1402 GNUNET_DISK_file_sync (lsocks_write_fd);
1403 GNUNET_DISK_pipe_close (lsocks_pipe);
1407 /* If we can't pass on the socket(s), the child will block forever,
1408 * better put it out of its misery.
1410 SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1411 CloseHandle (gnunet_proc->handle);
1412 if (NULL != gnunet_proc->control_pipe)
1413 GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1414 GNUNET_free (gnunet_proc);
1427 * @param pipe_control should a pipe be used to send signals to the child?
1428 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1429 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1430 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1431 * @param filename name of the binary
1432 * @param argv NULL-terminated array of arguments to the process
1433 * @return pointer to process structure of the new process, NULL on error
1435 struct GNUNET_OS_Process *
1436 GNUNET_OS_start_process_vap (int pipe_control,
1437 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1438 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1439 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1440 const char *filename,
1443 return start_process (pipe_control,
1456 * @param pipe_control should a pipe be used to send signals to the child?
1457 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1458 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1459 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1460 * @param filename name of the binary
1461 * @param va NULL-terminated list of arguments to the process
1462 * @return pointer to process structure of the new process, NULL on error
1464 struct GNUNET_OS_Process *
1465 GNUNET_OS_start_process_va (int pipe_control,
1466 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1467 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1468 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1469 const char *filename, va_list va)
1471 struct GNUNET_OS_Process *ret;
1478 while (NULL != va_arg (ap, char *))
1481 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1484 while (NULL != (argv[argc] = va_arg (ap, char *)))
1487 ret = GNUNET_OS_start_process_vap (pipe_control,
1502 * @param pipe_control should a pipe be used to send signals to the child?
1503 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1504 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1505 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1506 * @param filename name of the binary
1507 * @param ... NULL-terminated list of arguments to the process
1509 * @return pointer to process structure of the new process, NULL on error
1512 struct GNUNET_OS_Process *
1513 GNUNET_OS_start_process (int pipe_control,
1514 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1515 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1516 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1517 const char *filename, ...)
1519 struct GNUNET_OS_Process *ret;
1522 va_start (ap, filename);
1523 ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1524 pipe_stdout, filename, ap);
1533 * @param pipe_control should a pipe be used to send signals to the child?
1534 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1535 * must be NULL on platforms where dup is not supported
1536 * @param filename name of the binary
1537 * @param argv NULL-terminated list of arguments to the process
1538 * @return process ID of the new process, -1 on error
1540 struct GNUNET_OS_Process *
1541 GNUNET_OS_start_process_v (int pipe_control,
1542 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1543 const SOCKTYPE *lsocks,
1544 const char *filename,
1547 return start_process (pipe_control,
1558 * Retrieve the status of a process, waiting on him if dead.
1559 * Nonblocking version.
1561 * @param proc process ID
1562 * @param type status type
1563 * @param code return code/signal number
1564 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1567 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1568 enum GNUNET_OS_ProcessStatusType *type,
1569 unsigned long *code)
1575 GNUNET_assert (0 != proc);
1576 ret = waitpid (proc->pid, &status, WNOHANG);
1579 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1580 return GNUNET_SYSERR;
1584 *type = GNUNET_OS_PROCESS_RUNNING;
1588 if (proc->pid != ret)
1590 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1591 return GNUNET_SYSERR;
1593 if (WIFEXITED (status))
1595 *type = GNUNET_OS_PROCESS_EXITED;
1596 *code = WEXITSTATUS (status);
1598 else if (WIFSIGNALED (status))
1600 *type = GNUNET_OS_PROCESS_SIGNALED;
1601 *code = WTERMSIG (status);
1603 else if (WIFSTOPPED (status))
1605 *type = GNUNET_OS_PROCESS_SIGNALED;
1606 *code = WSTOPSIG (status);
1609 else if (WIFCONTINUED (status))
1611 *type = GNUNET_OS_PROCESS_RUNNING;
1617 *type = GNUNET_OS_PROCESS_UNKNOWN;
1622 DWORD c, error_code, ret;
1626 if (h == NULL || ret == 0)
1628 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1630 return GNUNET_SYSERR;
1633 h = GetCurrentProcess ();
1636 ret = GetExitCodeProcess (h, &c);
1637 error_code = GetLastError ();
1638 if (ret == 0 || error_code != NO_ERROR)
1640 SetErrnoFromWinError (error_code);
1641 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1642 return GNUNET_SYSERR;
1644 if (STILL_ACTIVE == c)
1646 *type = GNUNET_OS_PROCESS_RUNNING;
1650 *type = GNUNET_OS_PROCESS_EXITED;
1659 * Wait for a process
1660 * @param proc pointer to process structure
1661 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1664 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1668 pid_t pid = proc->pid;
1671 while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1672 (EINTR == errno) ) ;
1675 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1676 return GNUNET_SYSERR;
1686 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1688 return GNUNET_SYSERR;
1691 h = GetCurrentProcess ();
1693 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1695 SetErrnoFromWinError (GetLastError ());
1696 ret = GNUNET_SYSERR;
1707 * Handle to a command.
1709 struct GNUNET_OS_CommandHandle
1715 struct GNUNET_OS_Process *eip;
1718 * Handle to the output pipe.
1720 struct GNUNET_DISK_PipeHandle *opipe;
1723 * Read-end of output pipe.
1725 const struct GNUNET_DISK_FileHandle *r;
1728 * Function to call on each line of output.
1730 GNUNET_OS_LineProcessor proc;
1733 * Closure for 'proc'.
1738 * Buffer for the output.
1743 * Task reading from pipe.
1745 GNUNET_SCHEDULER_TaskIdentifier rtask;
1750 struct GNUNET_TIME_Absolute timeout;
1753 * Current read offset in buf.
1760 * Stop/kill a command. Must ONLY be called either from
1761 * the callback after 'NULL' was passed for 'line' *OR*
1762 * from an independent task (not within the line processor).
1764 * @param cmd handle to the process
1767 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1770 if (cmd->proc != NULL)
1772 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1773 GNUNET_SCHEDULER_cancel (cmd->rtask);
1775 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1776 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1777 GNUNET_OS_process_destroy (cmd->eip);
1778 GNUNET_DISK_pipe_close (cmd->opipe);
1784 * Read from the process and call the line processor.
1786 * @param cls the 'struct GNUNET_OS_CommandHandle'
1787 * @param tc scheduler context
1790 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1792 struct GNUNET_OS_CommandHandle *cmd = cls;
1793 GNUNET_OS_LineProcessor proc;
1797 cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1798 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1800 /* timeout, shutdown, etc. */
1803 proc (cmd->proc_cls, NULL);
1807 GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1808 sizeof (cmd->buf) - cmd->off);
1811 if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1813 cmd->buf[cmd->off] = '\0';
1814 cmd->proc (cmd->proc_cls, cmd->buf);
1818 proc (cmd->proc_cls, NULL);
1821 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1826 cmd->proc (cmd->proc_cls, cmd->buf);
1827 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1828 cmd->off -= (end + 1 - cmd->buf);
1829 end = memchr (cmd->buf, '\n', cmd->off);
1832 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1833 (cmd->timeout), cmd->r, &cmd_read, cmd);
1838 * Run the given command line and call the given function
1839 * for each line of the output.
1841 * @param proc function to call for each line of the output
1842 * @param proc_cls closure for proc
1843 * @param timeout when to time out
1844 * @param binary command to run
1845 * @param ... arguments to command
1846 * @return NULL on error
1848 struct GNUNET_OS_CommandHandle *
1849 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1850 struct GNUNET_TIME_Relative timeout, const char *binary,
1853 struct GNUNET_OS_CommandHandle *cmd;
1854 struct GNUNET_OS_Process *eip;
1855 struct GNUNET_DISK_PipeHandle *opipe;
1858 opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1861 va_start (ap, binary);
1862 /* redirect stdout, don't inherit stderr/stdin */
1863 eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1867 GNUNET_DISK_pipe_close (opipe);
1870 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1871 cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1872 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1876 cmd->proc_cls = proc_cls;
1877 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1878 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1885 /* end of os_priority.c */