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 * possibly updated to the new name (or free'd)
84 * @param flags open flags
85 * @param perm access permissions
86 * @return pipe handle on success, NULL on error
88 static struct GNUNET_DISK_FileHandle *
89 npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
90 enum GNUNET_DISK_AccessPermissions perm)
92 struct GNUNET_DISK_FileHandle *ret;
98 if (flags & GNUNET_DISK_OPEN_READWRITE)
99 openMode = PIPE_ACCESS_DUPLEX;
100 else if (flags & GNUNET_DISK_OPEN_READ)
101 openMode = PIPE_ACCESS_INBOUND;
102 else if (flags & GNUNET_DISK_OPEN_WRITE)
103 openMode = PIPE_ACCESS_OUTBOUND;
104 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
105 openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
114 GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn);
115 LOG (GNUNET_ERROR_TYPE_DEBUG,
116 "Trying to create an instance of named pipe `%s'\n", name);
117 /* 1) This might work just fine with UTF-8 strings as it is.
118 * 2) This is only used by GNUnet itself, and only with latin names.
120 h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
121 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
126 GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu",
127 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
129 LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n",
131 h = CreateNamedPipe (*fn,
132 openMode | FILE_FLAG_OVERLAPPED |
133 FILE_FLAG_FIRST_PIPE_INSTANCE,
134 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
137 error_code = GetLastError ();
138 GNUNET_free_non_null (name);
139 /* don't re-set name to NULL yet */
140 if (INVALID_HANDLE_VALUE == h)
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_ACCESS_DENIED != error_code) && (ERROR_PIPE_BUSY != error_code) )
154 LOG (GNUNET_ERROR_TYPE_DEBUG,
155 "Pipe name was not unique, trying again\n");
162 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
164 ret->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
165 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
166 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
167 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
168 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
174 * Opens already existing named pipe/FIFO
176 * @param fn name of an existing named pipe
177 * @param flags open flags
178 * @return pipe handle on success, NULL on error
180 static struct GNUNET_DISK_FileHandle *
181 npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags)
183 struct GNUNET_DISK_FileHandle *ret;
188 if (flags & GNUNET_DISK_OPEN_READWRITE)
189 openMode = GENERIC_WRITE | GENERIC_READ;
190 else if (flags & GNUNET_DISK_OPEN_READ)
191 openMode = GENERIC_READ;
192 else if (flags & GNUNET_DISK_OPEN_WRITE)
193 openMode = GENERIC_WRITE;
195 h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
196 FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
197 if (INVALID_HANDLE_VALUE == h)
199 SetErrnoFromWinError (GetLastError ());
203 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
205 ret->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
206 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
207 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
208 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
209 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
215 /* UNIX version of named-pipe API */
218 * Clean up a named pipe and the directory it was placed in.
220 * @param fn name of the pipe
223 cleanup_npipe (const char *fn)
228 if (0 != unlink (fn))
229 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
230 dn = GNUNET_strdup (fn);
233 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp);
239 * Setup a named pipe.
241 * @param fn where to store the name of the new pipe,
242 * if *fn is non-null, the name of the pipe to setup
243 * @return GNUNET_OK on success
246 npipe_setup (char **fn)
250 /* FIXME: hardwired '/tmp' path... is bad */
251 char dir[] = "/tmp/gnunet-pipe-XXXXXX";
253 if (NULL == mkdtemp (dir))
255 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp");
256 return GNUNET_SYSERR;
258 GNUNET_asprintf (fn, "%s/child-control", dir);
260 if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR))
261 return GNUNET_SYSERR;
267 * Open an existing named pipe.
269 * @param fn name of the file
270 * @param flags flags to use
271 * @return NULL on error
273 static struct GNUNET_DISK_FileHandle *
274 npipe_open (const char *fn,
275 enum GNUNET_DISK_OpenFlags flags)
277 struct GNUNET_DISK_FileHandle *ret;
282 /* 200 * 5ms = 1s at most */
285 fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONLY : O_WRONLY));
286 if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ))
288 /* as this is for killing a child process via pipe and it is conceivable that
289 the child process simply didn't finish starting yet, we do some sleeping
290 (which is obviously usually not allowed). We can't select on the FD as
291 'open' fails, and we probably shouldn't just "ignore" the error, so wait
292 and retry a few times is likely the best method; our process API doesn't
293 support continuations, so we need to sleep directly... */
295 req.tv_nsec = 5000000; /* 5ms */
296 (void) nanosleep (&req, NULL);
300 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
301 (flags == GNUNET_DISK_OPEN_READ)
302 ? _("Failed to open named pipe `%s' for reading: %s\n")
303 : _("Failed to open named pipe `%s' for writing: %s\n"),
308 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
316 * This handler is called when there are control data to be read on the pipe
318 * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe
319 * @param tc scheduler context
322 parent_control_handler (void *cls,
323 const struct GNUNET_SCHEDULER_TaskContext *tc)
325 struct GNUNET_DISK_FileHandle *control_pipe = cls;
329 LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
331 if (0 != (tc->reason &
332 (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT)))
334 GNUNET_DISK_file_close (control_pipe);
338 ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig));
339 if (sizeof (sig) != ret)
342 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
343 LOG (GNUNET_ERROR_TYPE_WARNING, "Closing control pipe\n");
344 GNUNET_DISK_file_close (control_pipe);
348 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig);
349 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
350 control_pipe, &parent_control_handler,
357 * Task that connects this process to its parent via pipe;
358 * essentially, the parent control handler will read signal numbers
359 * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment
360 * variable) and raise those signals.
362 * @param cls closure (unused)
363 * @param tc scheduler context (unused)
366 GNUNET_OS_install_parent_control_handler (void *cls,
368 GNUNET_SCHEDULER_TaskContext *tc)
371 struct GNUNET_DISK_FileHandle *control_pipe;
373 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
374 if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
376 LOG (GNUNET_ERROR_TYPE_DEBUG,
377 "Not installing a handler because $%s is empty\n",
378 GNUNET_OS_CONTROL_PIPE);
379 putenv ("GNUNET_OS_CONTROL_PIPE=");
383 npipe_open (env_buf, GNUNET_DISK_OPEN_READ);
384 if (NULL == control_pipe)
386 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
387 putenv ("GNUNET_OS_CONTROL_PIPE=");
390 LOG (GNUNET_ERROR_TYPE_DEBUG,
391 "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
392 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
393 &parent_control_handler, control_pipe);
394 putenv ("GNUNET_OS_CONTROL_PIPE=");
399 * Get process structure for current process
401 * The pointer it returns points to static memory location and must not be
404 * @return pointer to the process sturcutre for this process
406 struct GNUNET_OS_Process *
407 GNUNET_OS_process_current ()
410 current_process.pid = GetCurrentProcessId ();
411 current_process.handle = GetCurrentProcess ();
413 current_process.pid = 0;
415 return ¤t_process;
420 * Sends a signal to the process
422 * @param proc pointer to process structure
424 * @return 0 on success, -1 on error
427 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
434 if ( (NULL == proc->control_pipe) &&
435 (NULL != proc->childpipename) )
436 proc->control_pipe = npipe_open (proc->childpipename,
437 GNUNET_DISK_OPEN_WRITE);
439 if (NULL != proc->control_pipe)
441 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via pipe\n", sig, proc->pid);
442 ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
443 if (sizeof (csig) == ret)
446 /* pipe failed or non-existent, try other methods */
455 #if WINDOWS && !defined(__CYGWIN__)
458 int must_kill = GNUNET_YES;
459 if (0 != GetExitCodeProcess (proc->handle, &exitcode))
460 must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
461 if (GNUNET_YES == must_kill)
462 if (0 == SafeTerminateProcess (proc->handle, 0, 0))
464 DWORD error_code = GetLastError ();
465 if ((error_code != WAIT_TIMEOUT) && (error_code != ERROR_PROCESS_ABORTED))
467 LOG ((error_code == ERROR_ACCESS_DENIED) ?
468 GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
469 "SafeTermiateProcess failed with code %lu\n", error_code);
470 /* The problem here is that a process that is already dying
471 * might cause SafeTerminateProcess to fail with
472 * ERROR_ACCESS_DENIED, but the process WILL die eventually.
473 * If we really had a permissions problem, hanging up (which
474 * is what will happen in process_wait() in that case) is
477 if (ERROR_ACCESS_DENIED == error_code)
483 SetErrnoFromWinError (error_code);
491 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
492 return PLIBC_KILL (proc->pid, sig);
499 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
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 (GNUNET_SCHEDULER_PRIORITY_KEEP == prio)
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 (NULL == win32_env_table)
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 GNUNET_free (childpipename);
871 if (NULL != pipe_stdout)
873 GNUNET_assert (GNUNET_OK ==
874 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
876 GNUNET_DISK_PIPE_END_WRITE),
877 &fd_stdout_write, sizeof (int)));
878 GNUNET_assert (GNUNET_OK ==
879 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
880 (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
881 &fd_stdout_read, sizeof (int)));
883 if (NULL != pipe_stdin)
885 GNUNET_assert (GNUNET_OK ==
886 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
887 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
888 &fd_stdin_read, sizeof (int)));
889 GNUNET_assert (GNUNET_OK ==
890 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
891 (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
892 &fd_stdin_write, sizeof (int)));
899 while (-1 != (k = lsocks[i++]))
900 GNUNET_array_append (lscp, ls, k);
901 GNUNET_array_append (lscp, ls, -1);
908 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
909 GNUNET_free_non_null (childpipename);
910 GNUNET_array_grow (lscp, ls, 0);
916 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
917 gnunet_proc->pid = ret;
918 gnunet_proc->childpipename = childpipename;
919 GNUNET_array_grow (lscp, ls, 0);
922 if (NULL != childpipename)
924 setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
925 GNUNET_free (childpipename);
927 if (NULL != pipe_stdin)
929 GNUNET_break (0 == close (fd_stdin_write));
930 if (-1 == dup2 (fd_stdin_read, 0))
931 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
932 GNUNET_break (0 == close (fd_stdin_read));
934 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
936 GNUNET_break (0 == close (0));
937 open_dev_null (0, O_RDONLY);
939 if (NULL != pipe_stdout)
941 GNUNET_break (0 == close (fd_stdout_read));
942 if (-1 == dup2 (fd_stdout_write, 1))
943 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
944 GNUNET_break (0 == close (fd_stdout_write));
946 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
948 GNUNET_break (0 == close (1));
949 open_dev_null (1, O_WRONLY);
951 if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
953 GNUNET_break (0 == close (2));
954 open_dev_null (2, O_WRONLY);
958 /* read systemd documentation... */
959 GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
960 setenv ("LISTEN_PID", lpid, 1);
963 while (-1 != lscp[i])
966 while (-1 != lscp[j])
972 GNUNET_assert (-1 != k);
973 GNUNET_assert (0 == close (lscp[j]));
981 /* Bury any existing FD, no matter what; they should all be closed
982 * on exec anyway and the important onces have been dup'ed away */
984 GNUNET_assert (-1 != dup2 (lscp[i], tgt));
986 /* unset close-on-exec flag */
987 flags = fcntl (tgt, F_GETFD);
988 GNUNET_assert (flags >= 0);
989 flags &= ~FD_CLOEXEC;
991 (void) fcntl (tgt, F_SETFD, flags);
995 GNUNET_snprintf (fds, sizeof (fds), "%u", i);
996 setenv ("LISTEN_FDS", fds, 1);
998 GNUNET_array_grow (lscp, ls, 0);
999 execvp (filename, argv);
1000 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
1003 struct GNUNET_DISK_FileHandle *control_pipe;
1004 char *childpipename = NULL;
1006 char **non_const_argv;
1007 unsigned int cmdlen;
1011 PROCESS_INFORMATION proc;
1013 struct GNUNET_OS_Process *gnunet_proc;
1014 char path[MAX_PATH + 1];
1015 char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
1016 char *env_block = NULL;
1024 char *non_const_filename;
1025 char win_path[MAX_PATH + 1];
1026 struct GNUNET_DISK_PipeHandle *lsocks_pipe;
1027 const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
1029 HANDLE lsocks_write;
1037 HANDLE stdin_handle;
1038 HANDLE stdout_handle;
1039 HANDLE stdih, stdoh, stdeh;
1040 DWORD stdif, stdof, stdef;
1044 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
1045 return NULL; /* not executable */
1047 /* Search in prefix dir (hopefully - the directory from which
1048 * the current module was loaded), bindir and libdir, then in PATH
1050 self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
1051 bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
1052 libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
1054 pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
1057 pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
1060 pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
1063 ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
1064 GNUNET_free (self_prefix);
1065 GNUNET_free (bindir);
1066 GNUNET_free (libdir);
1068 alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
1069 if (alloc_len != pathbuf_len - 1)
1071 GNUNET_free (pathbuf);
1072 errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
1076 cmdlen = strlen (filename);
1077 if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
1078 GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
1080 GNUNET_asprintf (&non_const_filename, "%s", filename);
1082 /* It could be in POSIX form, convert it to a DOS path early on */
1083 if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
1085 SetErrnoFromWinError (lRet);
1086 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
1087 non_const_filename);
1088 GNUNET_free (non_const_filename);
1089 GNUNET_free (pathbuf);
1092 GNUNET_free (non_const_filename);
1093 non_const_filename = GNUNET_strdup (win_path);
1094 /* Check that this is the full path. If it isn't, search. */
1095 /* FIXME: convert it to wchar_t and use SearchPathW?
1096 * Remember: arguments to _start_process() are technically in UTF-8...
1098 if (non_const_filename[1] == ':')
1099 snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
1100 else if (!SearchPathA
1101 (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
1104 SetErrnoFromWinError (GetLastError ());
1105 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
1106 non_const_filename);
1107 GNUNET_free (non_const_filename);
1108 GNUNET_free (pathbuf);
1111 GNUNET_free (pathbuf);
1112 GNUNET_free (non_const_filename);
1114 /* Count the number of arguments */
1115 arg = (char **) argv;
1122 /* Allocate a copy argv */
1123 non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
1125 /* Copy all argv strings */
1127 arg = (char **) argv;
1131 non_const_argv[argcount] = GNUNET_strdup (path);
1133 non_const_argv[argcount] = GNUNET_strdup (*arg);
1137 non_const_argv[argcount] = NULL;
1141 arg = non_const_argv;
1144 cmdlen = cmdlen + strlen (*arg) + 4;
1148 /* Allocate and create cmd */
1149 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
1150 arg = non_const_argv;
1153 char arg_last_char = (*arg)[strlen (*arg) - 1];
1154 idx += sprintf (idx, "\"%s%s\"%s", *arg,
1155 arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
1159 while (argcount > 0)
1160 GNUNET_free (non_const_argv[--argcount]);
1161 GNUNET_free (non_const_argv);
1163 memset (&start, 0, sizeof (start));
1164 start.cb = sizeof (start);
1165 if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
1166 start.dwFlags |= STARTF_USESTDHANDLES;
1168 stdih = GetStdHandle (STD_INPUT_HANDLE);
1169 GetHandleInformation (stdih, &stdif);
1170 if (pipe_stdin != NULL)
1172 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1173 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
1174 &stdin_handle, sizeof (HANDLE));
1175 start.hStdInput = stdin_handle;
1179 if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1181 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
1182 if (pipe_stdin == NULL)
1183 start.hStdInput = stdih;
1186 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1190 stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1191 GetHandleInformation (stdoh, &stdof);
1192 if (NULL != pipe_stdout)
1194 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1196 GNUNET_DISK_PIPE_END_WRITE),
1197 &stdout_handle, sizeof (HANDLE));
1198 start.hStdOutput = stdout_handle;
1202 if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1204 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1205 if (pipe_stdout == NULL)
1206 start.hStdOutput = stdoh;
1209 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1212 stdeh = GetStdHandle (STD_ERROR_HANDLE);
1213 GetHandleInformation (stdeh, &stdef);
1216 if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1218 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1219 start.hStdError = stdeh;
1222 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1225 if (GNUNET_YES == pipe_control)
1228 npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
1229 GNUNET_DISK_PERM_USER_READ |
1230 GNUNET_DISK_PERM_USER_WRITE);
1231 if (control_pipe == NULL)
1239 control_pipe = NULL;
1240 if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1242 lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1244 if (lsocks_pipe == NULL)
1248 GNUNET_DISK_pipe_close (lsocks_pipe);
1251 lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1252 GNUNET_DISK_PIPE_END_WRITE);
1253 GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1254 &lsocks_write, sizeof (HANDLE));
1255 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1256 (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1257 &lsocks_read, sizeof (HANDLE));
1261 if (NULL != childpipename)
1263 LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
1265 GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1266 GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
1267 GNUNET_free (childpipename);
1269 if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1271 /*This will tell the child that we're going to send lsocks over the pipe*/
1272 GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1273 GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1275 our_env[env_off++] = NULL;
1276 env_block = CreateCustomEnvTable (our_env);
1278 GNUNET_free_non_null (our_env[--env_off]);
1281 if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1283 LOG (GNUNET_ERROR_TYPE_DEBUG,
1284 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1285 GNUNET_free (env_block);
1291 if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1293 LOG (GNUNET_ERROR_TYPE_DEBUG,
1294 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1295 GNUNET_free (env_block);
1301 bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
1302 DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1303 error_code = GetLastError ();
1305 if ((NULL == pipe_stdin) && (stdih))
1306 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1309 if ((NULL == pipe_stdout) && (stdoh))
1310 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1313 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1315 GNUNET_free (env_block);
1322 SetErrnoFromWinError (error_code);
1323 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1324 if (NULL != control_pipe)
1325 GNUNET_DISK_file_close (control_pipe);
1327 GNUNET_DISK_pipe_close (lsocks_pipe);
1331 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1332 gnunet_proc->pid = proc.dwProcessId;
1333 gnunet_proc->handle = proc.hProcess;
1334 gnunet_proc->control_pipe = control_pipe;
1336 CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1338 ResumeThread (proc.hThread);
1339 CloseHandle (proc.hThread);
1341 if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
1344 GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1346 /* This is a replacement for "goto error" that doesn't use goto */
1355 /* Tell the number of sockets */
1356 for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1358 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1359 if (sizeof (count) != wrote)
1361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1362 "Failed to write %u count bytes to the child: %u\n",
1363 sizeof (count), GetLastError ());
1366 for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1368 WSAPROTOCOL_INFOA pi;
1369 /* Get a socket duplication info */
1370 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1373 "Failed to duplicate an socket[%llu]: %u\n", i,
1377 /* Synchronous I/O is not nice, but we can't schedule this:
1378 * lsocks will be closed/freed by the caller soon, and until
1379 * the child creates a duplicate, closing a socket here will
1380 * close it for good.
1382 /* Send the size of the structure
1383 * (the child might be built with different headers...)
1386 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1387 if (sizeof (size) != wrote)
1389 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1390 "Failed to write %u size[%llu] bytes to the child: %u\n",
1391 sizeof (size), i, GetLastError ());
1394 /* Finally! Send the data */
1395 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1396 if (sizeof (pi) != wrote)
1398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1399 "Failed to write %u socket[%llu] bytes to the child: %u\n",
1400 sizeof (pi), i, GetLastError ());
1404 /* This will block us until the child makes a final read or closes
1405 * the pipe (hence no 'wrote' check), since we have to wait for it
1406 * to duplicate the last socket, before we return and start closing
1409 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1414 GNUNET_DISK_file_sync (lsocks_write_fd);
1415 GNUNET_DISK_pipe_close (lsocks_pipe);
1419 /* If we can't pass on the socket(s), the child will block forever,
1420 * better put it out of its misery.
1422 SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1423 CloseHandle (gnunet_proc->handle);
1424 if (NULL != gnunet_proc->control_pipe)
1425 GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1426 GNUNET_free (gnunet_proc);
1439 * @param pipe_control should a pipe be used to send signals to the child?
1440 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1441 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1442 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1443 * @param filename name of the binary
1444 * @param argv NULL-terminated array of arguments to the process
1445 * @return pointer to process structure of the new process, NULL on error
1447 struct GNUNET_OS_Process *
1448 GNUNET_OS_start_process_vap (int pipe_control,
1449 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1450 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1451 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1452 const char *filename,
1455 return start_process (pipe_control,
1468 * @param pipe_control should a pipe be used to send signals to the child?
1469 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1470 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1471 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1472 * @param filename name of the binary
1473 * @param va NULL-terminated list of arguments to the process
1474 * @return pointer to process structure of the new process, NULL on error
1476 struct GNUNET_OS_Process *
1477 GNUNET_OS_start_process_va (int pipe_control,
1478 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1479 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1480 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1481 const char *filename, va_list va)
1483 struct GNUNET_OS_Process *ret;
1490 while (NULL != va_arg (ap, char *))
1493 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1496 while (NULL != (argv[argc] = va_arg (ap, char *)))
1499 ret = GNUNET_OS_start_process_vap (pipe_control,
1513 * @param pipe_control should a pipe be used to send signals to the child?
1514 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1515 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1516 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1517 * @param filename name of the binary
1518 * @param ... NULL-terminated list of arguments to the process
1519 * @return pointer to process structure of the new process, NULL on error
1521 struct GNUNET_OS_Process *
1522 GNUNET_OS_start_process (int pipe_control,
1523 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1524 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1525 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1526 const char *filename, ...)
1528 struct GNUNET_OS_Process *ret;
1531 va_start (ap, filename);
1532 ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1533 pipe_stdout, filename, ap);
1542 * @param pipe_control should a pipe be used to send signals to the child?
1543 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
1544 * std handles of the parent are inherited by the child.
1545 * pipe_stdin and pipe_stdout take priority over std_inheritance
1546 * (when they are non-NULL).
1547 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1548 * must be NULL on platforms where dup is not supported
1549 * @param filename name of the binary
1550 * @param argv NULL-terminated list of arguments to the process
1551 * @return process ID of the new process, -1 on error
1553 struct GNUNET_OS_Process *
1554 GNUNET_OS_start_process_v (int pipe_control,
1555 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1556 const SOCKTYPE *lsocks,
1557 const char *filename,
1560 return start_process (pipe_control,
1571 * Retrieve the status of a process, waiting on him if dead.
1572 * Nonblocking version.
1574 * @param proc process ID
1575 * @param type status type
1576 * @param code return code/signal number
1577 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1580 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1581 enum GNUNET_OS_ProcessStatusType *type,
1582 unsigned long *code)
1588 GNUNET_assert (0 != proc);
1589 ret = waitpid (proc->pid, &status, WNOHANG);
1592 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1593 return GNUNET_SYSERR;
1597 *type = GNUNET_OS_PROCESS_RUNNING;
1601 if (proc->pid != ret)
1603 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1604 return GNUNET_SYSERR;
1606 if (WIFEXITED (status))
1608 *type = GNUNET_OS_PROCESS_EXITED;
1609 *code = WEXITSTATUS (status);
1611 else if (WIFSIGNALED (status))
1613 *type = GNUNET_OS_PROCESS_SIGNALED;
1614 *code = WTERMSIG (status);
1616 else if (WIFSTOPPED (status))
1618 *type = GNUNET_OS_PROCESS_SIGNALED;
1619 *code = WSTOPSIG (status);
1622 else if (WIFCONTINUED (status))
1624 *type = GNUNET_OS_PROCESS_RUNNING;
1630 *type = GNUNET_OS_PROCESS_UNKNOWN;
1635 DWORD c, error_code, ret;
1639 if (h == NULL || ret == 0)
1641 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1643 return GNUNET_SYSERR;
1646 h = GetCurrentProcess ();
1649 ret = GetExitCodeProcess (h, &c);
1650 error_code = GetLastError ();
1651 if (ret == 0 || error_code != NO_ERROR)
1653 SetErrnoFromWinError (error_code);
1654 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1655 return GNUNET_SYSERR;
1657 if (STILL_ACTIVE == c)
1659 *type = GNUNET_OS_PROCESS_RUNNING;
1663 *type = GNUNET_OS_PROCESS_EXITED;
1672 * Wait for a process
1674 * @param proc pointer to process structure
1675 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1678 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1681 pid_t pid = proc->pid;
1684 while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1685 (EINTR == errno) ) ;
1688 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1689 return GNUNET_SYSERR;
1698 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1700 return GNUNET_SYSERR;
1703 h = GetCurrentProcess ();
1705 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1707 SetErrnoFromWinError (GetLastError ());
1708 return GNUNET_SYSERR;
1716 * Handle to a command.
1718 struct GNUNET_OS_CommandHandle
1724 struct GNUNET_OS_Process *eip;
1727 * Handle to the output pipe.
1729 struct GNUNET_DISK_PipeHandle *opipe;
1732 * Read-end of output pipe.
1734 const struct GNUNET_DISK_FileHandle *r;
1737 * Function to call on each line of output.
1739 GNUNET_OS_LineProcessor proc;
1742 * Closure for 'proc'.
1747 * Buffer for the output.
1752 * Task reading from pipe.
1754 GNUNET_SCHEDULER_TaskIdentifier rtask;
1759 struct GNUNET_TIME_Absolute timeout;
1762 * Current read offset in buf.
1769 * Stop/kill a command. Must ONLY be called either from
1770 * the callback after 'NULL' was passed for 'line' *OR*
1771 * from an independent task (not within the line processor).
1773 * @param cmd handle to the process
1776 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1778 if (NULL != cmd->proc)
1780 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1781 GNUNET_SCHEDULER_cancel (cmd->rtask);
1783 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1784 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1785 GNUNET_OS_process_destroy (cmd->eip);
1786 GNUNET_DISK_pipe_close (cmd->opipe);
1792 * Read from the process and call the line processor.
1794 * @param cls the 'struct GNUNET_OS_CommandHandle'
1795 * @param tc scheduler context
1798 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1800 struct GNUNET_OS_CommandHandle *cmd = cls;
1801 GNUNET_OS_LineProcessor proc;
1805 cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1806 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1808 /* timeout, shutdown, etc. */
1811 proc (cmd->proc_cls, NULL);
1815 GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1816 sizeof (cmd->buf) - cmd->off);
1819 if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1821 cmd->buf[cmd->off] = '\0';
1822 cmd->proc (cmd->proc_cls, cmd->buf);
1826 proc (cmd->proc_cls, NULL);
1829 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1834 cmd->proc (cmd->proc_cls, cmd->buf);
1835 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1836 cmd->off -= (end + 1 - cmd->buf);
1837 end = memchr (cmd->buf, '\n', cmd->off);
1840 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1841 (cmd->timeout), cmd->r, &cmd_read, cmd);
1846 * Run the given command line and call the given function
1847 * for each line of the output.
1849 * @param proc function to call for each line of the output
1850 * @param proc_cls closure for proc
1851 * @param timeout when to time out
1852 * @param binary command to run
1853 * @param ... arguments to command
1854 * @return NULL on error
1856 struct GNUNET_OS_CommandHandle *
1857 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1858 struct GNUNET_TIME_Relative timeout, const char *binary,
1861 struct GNUNET_OS_CommandHandle *cmd;
1862 struct GNUNET_OS_Process *eip;
1863 struct GNUNET_DISK_PipeHandle *opipe;
1866 opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1869 va_start (ap, binary);
1870 /* redirect stdout, don't inherit stderr/stdin */
1871 eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1875 GNUNET_DISK_pipe_close (opipe);
1878 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1879 cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1880 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1884 cmd->proc_cls = proc_cls;
1885 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1886 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1891 /* end of os_priority.c */