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 GNUNET_DISK_file_close (control_pipe);
347 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig);
348 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
349 control_pipe, &parent_control_handler,
356 * Task that connects this process to its parent via pipe;
357 * essentially, the parent control handler will read signal numbers
358 * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment
359 * variable) and raise those signals.
361 * @param cls closure (unused)
362 * @param tc scheduler context (unused)
365 GNUNET_OS_install_parent_control_handler (void *cls,
367 GNUNET_SCHEDULER_TaskContext *tc)
370 struct GNUNET_DISK_FileHandle *control_pipe;
372 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
373 if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
375 LOG (GNUNET_ERROR_TYPE_DEBUG,
376 "Not installing a handler because $%s is empty\n",
377 GNUNET_OS_CONTROL_PIPE);
378 putenv ("GNUNET_OS_CONTROL_PIPE=");
382 npipe_open (env_buf, GNUNET_DISK_OPEN_READ);
383 if (NULL == control_pipe)
385 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
386 putenv ("GNUNET_OS_CONTROL_PIPE=");
389 LOG (GNUNET_ERROR_TYPE_DEBUG,
390 "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
391 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
392 &parent_control_handler, control_pipe);
393 putenv ("GNUNET_OS_CONTROL_PIPE=");
398 * Get process structure for current process
400 * The pointer it returns points to static memory location and must not be
403 * @return pointer to the process sturcutre for this process
405 struct GNUNET_OS_Process *
406 GNUNET_OS_process_current ()
409 current_process.pid = GetCurrentProcessId ();
410 current_process.handle = GetCurrentProcess ();
412 current_process.pid = 0;
414 return ¤t_process;
419 * Sends a signal to the process
421 * @param proc pointer to process structure
423 * @return 0 on success, -1 on error
426 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
433 if ( (NULL == proc->control_pipe) &&
434 (NULL != proc->childpipename) )
435 proc->control_pipe = npipe_open (proc->childpipename,
436 GNUNET_DISK_OPEN_WRITE);
438 if (NULL != proc->control_pipe)
440 ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
441 if (sizeof (csig) == ret)
444 /* pipe failed or non-existent, try other methods */
453 #if WINDOWS && !defined(__CYGWIN__)
456 int must_kill = GNUNET_YES;
457 if (0 != GetExitCodeProcess (proc->handle, &exitcode))
458 must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
459 if (GNUNET_YES == must_kill)
460 if (0 == SafeTerminateProcess (proc->handle, 0, 0))
462 DWORD error_code = GetLastError ();
463 if ((error_code != WAIT_TIMEOUT) && (error_code != ERROR_PROCESS_ABORTED))
465 LOG ((error_code == ERROR_ACCESS_DENIED) ?
466 GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
467 "SafeTermiateProcess failed with code %lu\n", error_code);
468 /* The problem here is that a process that is already dying
469 * might cause SafeTerminateProcess to fail with
470 * ERROR_ACCESS_DENIED, but the process WILL die eventually.
471 * If we really had a permissions problem, hanging up (which
472 * is what will happen in process_wait() in that case) is
475 if (ERROR_ACCESS_DENIED == error_code)
481 SetErrnoFromWinError (error_code);
489 return PLIBC_KILL (proc->pid, sig);
496 return PLIBC_KILL (proc->pid, sig);
502 * Get the pid of the process in question
504 * @param proc the process to get the pid of
506 * @return the current process id
509 GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
516 * Cleans up process structure contents (OS-dependent) and deallocates it
518 * @param proc pointer to process structure
521 GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
523 if (NULL != proc->control_pipe)
524 GNUNET_DISK_file_close (proc->control_pipe);
527 if (proc->handle != NULL)
528 CloseHandle (proc->handle);
530 if (NULL != proc->childpipename)
533 cleanup_npipe (proc->childpipename);
535 GNUNET_free (proc->childpipename);
542 #include "gnunet_signal_lib.h"
544 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
547 * Make seaspider happy.
549 #define DWORD_WINAPI DWORD WINAPI
552 * @brief Waits for a process to terminate and invokes the SIGCHLD handler
553 * @param proc pointer to process structure
556 child_wait_thread (void *arg)
558 struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
560 WaitForSingleObject (proc->handle, INFINITE);
562 if (w32_sigchld_handler)
563 w32_sigchld_handler ();
571 * Set process priority
573 * @param proc pointer to process structure
574 * @param prio priority value
575 * @return GNUNET_OK on success, GNUNET_SYSERR on error
578 GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
579 enum GNUNET_SCHEDULER_Priority prio)
583 GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
584 if (GNUNET_SCHEDULER_PRIORITY_KEEP == prio)
587 /* convert to MINGW/Unix values */
590 case GNUNET_SCHEDULER_PRIORITY_UI:
591 case GNUNET_SCHEDULER_PRIORITY_URGENT:
593 rprio = HIGH_PRIORITY_CLASS;
599 case GNUNET_SCHEDULER_PRIORITY_HIGH:
601 rprio = ABOVE_NORMAL_PRIORITY_CLASS;
607 case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
609 rprio = NORMAL_PRIORITY_CLASS;
615 case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
617 rprio = BELOW_NORMAL_PRIORITY_CLASS;
623 case GNUNET_SCHEDULER_PRIORITY_IDLE:
625 rprio = IDLE_PRIORITY_CLASS;
632 return GNUNET_SYSERR;
635 /* Set process priority */
638 HANDLE h = proc->handle;
640 GNUNET_assert (h != NULL);
641 SetPriorityClass (h, rprio);
647 if ((0 == pid) || (pid == getpid ()))
650 int delta = rprio - have;
653 if ((delta != 0) && (rprio == nice (delta)) && (errno != 0))
655 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice");
656 return GNUNET_SYSERR;
661 if (0 != setpriority (PRIO_PROCESS, pid, rprio))
663 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
665 return GNUNET_SYSERR;
669 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
670 "Priority management not availabe for this platform\n");
678 CreateCustomEnvTable (char **vars)
680 char *win32_env_table;
685 size_t tablesize = 0;
686 size_t items_count = 0;
695 win32_env_table = GetEnvironmentStringsA ();
696 if (NULL == win32_env_table)
698 for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ;
700 index = GNUNET_malloc (sizeof (char *) * n_var);
701 for (c = 0; c < n_var; c++)
703 for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
705 size_t len = strlen (ptr);
708 for (var_ptr = vars; *var_ptr; var_ptr++)
712 var_len = strlen (var);
713 if (strncmp (var, ptr, var_len) == 0)
717 tablesize += var_len + strlen (val) + 1;
722 tablesize += len + 1;
725 for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
730 n_found += strlen (var) + strlen (val) + 1;
732 result = GNUNET_malloc (tablesize + n_found + 1);
733 for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
735 size_t len = strlen (ptr);
738 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
742 var_len = strlen (var);
743 if (strncmp (var, ptr, var_len) == 0)
751 strcpy (result_ptr, ptr);
752 result_ptr += len + 1;
756 strcpy (result_ptr, var);
757 result_ptr += var_len;
758 strcpy (result_ptr, val);
759 result_ptr += strlen (val) + 1;
763 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
767 var_len = strlen (var);
770 strcpy (result_ptr, var);
771 result_ptr += var_len;
772 strcpy (result_ptr, val);
773 result_ptr += strlen (val) + 1;
776 FreeEnvironmentStrings (win32_env_table);
785 * Open '/dev/null' and make the result the given
788 * @param target_fd desired FD to point to /dev/null
789 * @param flags open flags (O_RDONLY, O_WRONLY)
792 open_dev_null (int target_fd,
797 fd = open ("/dev/null", flags);
800 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
805 if (-1 == dup2 (fd, target_fd))
807 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
811 GNUNET_break (0 == close (fd));
819 * @param pipe_control should a pipe be used to send signals to the child?
820 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
821 * std handles of the parent are inherited by the child.
822 * pipe_stdin and pipe_stdout take priority over std_inheritance
823 * (when they are non-NULL).
824 * @param pipe_stdin pipe to use to send input to child process (or NULL)
825 * @param pipe_stdout pipe to use to get output from child process (or NULL)
826 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
827 * must be NULL on platforms where dup is not supported
828 * @param filename name of the binary
829 * @param argv NULL-terminated list of arguments to the process
830 * @return process ID of the new process, -1 on error
832 static struct GNUNET_OS_Process *
833 start_process (int pipe_control,
834 enum GNUNET_OS_InheritStdioFlags std_inheritance,
835 struct GNUNET_DISK_PipeHandle *pipe_stdin,
836 struct GNUNET_DISK_PipeHandle *pipe_stdout,
837 const SOCKTYPE *lsocks,
838 const char *filename,
845 struct GNUNET_OS_Process *gnunet_proc;
846 char *childpipename = NULL;
859 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
860 return NULL; /* not executable */
861 if ( (GNUNET_YES == pipe_control) &&
862 (GNUNET_OK != npipe_setup (&childpipename)) )
864 GNUNET_free (childpipename);
867 if (NULL != pipe_stdout)
869 GNUNET_assert (GNUNET_OK ==
870 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
872 GNUNET_DISK_PIPE_END_WRITE),
873 &fd_stdout_write, sizeof (int)));
874 GNUNET_assert (GNUNET_OK ==
875 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
876 (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
877 &fd_stdout_read, sizeof (int)));
879 if (NULL != pipe_stdin)
881 GNUNET_assert (GNUNET_OK ==
882 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
883 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
884 &fd_stdin_read, sizeof (int)));
885 GNUNET_assert (GNUNET_OK ==
886 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
887 (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
888 &fd_stdin_write, sizeof (int)));
895 while (-1 != (k = lsocks[i++]))
896 GNUNET_array_append (lscp, ls, k);
897 GNUNET_array_append (lscp, ls, -1);
904 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
905 GNUNET_free_non_null (childpipename);
906 GNUNET_array_grow (lscp, ls, 0);
912 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
913 gnunet_proc->pid = ret;
914 gnunet_proc->childpipename = childpipename;
915 GNUNET_array_grow (lscp, ls, 0);
918 if (NULL != childpipename)
920 setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
921 GNUNET_free (childpipename);
923 if (NULL != pipe_stdin)
925 GNUNET_break (0 == close (fd_stdin_write));
926 if (-1 == dup2 (fd_stdin_read, 0))
927 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
928 GNUNET_break (0 == close (fd_stdin_read));
930 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
932 GNUNET_break (0 == close (0));
933 open_dev_null (0, O_RDONLY);
935 if (NULL != pipe_stdout)
937 GNUNET_break (0 == close (fd_stdout_read));
938 if (-1 == dup2 (fd_stdout_write, 1))
939 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
940 GNUNET_break (0 == close (fd_stdout_write));
942 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
944 GNUNET_break (0 == close (1));
945 open_dev_null (1, O_WRONLY);
947 if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
949 GNUNET_break (0 == close (2));
950 open_dev_null (2, O_WRONLY);
954 /* read systemd documentation... */
955 GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ());
956 setenv ("LISTEN_PID", lpid, 1);
959 while (-1 != lscp[i])
962 while (-1 != lscp[j])
968 GNUNET_assert (-1 != k);
969 GNUNET_assert (0 == close (lscp[j]));
977 /* Bury any existing FD, no matter what; they should all be closed
978 * on exec anyway and the important onces have been dup'ed away */
980 GNUNET_assert (-1 != dup2 (lscp[i], tgt));
982 /* unset close-on-exec flag */
983 flags = fcntl (tgt, F_GETFD);
984 GNUNET_assert (flags >= 0);
985 flags &= ~FD_CLOEXEC;
987 (void) fcntl (tgt, F_SETFD, flags);
991 GNUNET_snprintf (fds, sizeof (fds), "%u", i);
992 setenv ("LISTEN_FDS", fds, 1);
994 GNUNET_array_grow (lscp, ls, 0);
995 execvp (filename, argv);
996 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
999 struct GNUNET_DISK_FileHandle *control_pipe;
1000 char *childpipename = NULL;
1002 char **non_const_argv;
1003 unsigned int cmdlen;
1007 PROCESS_INFORMATION proc;
1009 struct GNUNET_OS_Process *gnunet_proc;
1010 char path[MAX_PATH + 1];
1011 char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
1012 char *env_block = NULL;
1020 char *non_const_filename;
1021 char win_path[MAX_PATH + 1];
1022 struct GNUNET_DISK_PipeHandle *lsocks_pipe;
1023 const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
1025 HANDLE lsocks_write;
1033 HANDLE stdin_handle;
1034 HANDLE stdout_handle;
1035 HANDLE stdih, stdoh, stdeh;
1036 DWORD stdif, stdof, stdef;
1040 if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename))
1041 return NULL; /* not executable */
1043 /* Search in prefix dir (hopefully - the directory from which
1044 * the current module was loaded), bindir and libdir, then in PATH
1046 self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
1047 bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
1048 libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
1050 pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
1053 pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 +
1056 pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
1059 ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
1060 GNUNET_free (self_prefix);
1061 GNUNET_free (bindir);
1062 GNUNET_free (libdir);
1064 alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
1065 if (alloc_len != pathbuf_len - 1)
1067 GNUNET_free (pathbuf);
1068 errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
1072 cmdlen = strlen (filename);
1073 if ( (cmdlen < 5) || (0 != strcmp (&filename[cmdlen - 4], ".exe")) )
1074 GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
1076 GNUNET_asprintf (&non_const_filename, "%s", filename);
1078 /* It could be in POSIX form, convert it to a DOS path early on */
1079 if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path)))
1081 SetErrnoFromWinError (lRet);
1082 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path",
1083 non_const_filename);
1084 GNUNET_free (non_const_filename);
1085 GNUNET_free (pathbuf);
1088 GNUNET_free (non_const_filename);
1089 non_const_filename = GNUNET_strdup (win_path);
1090 /* Check that this is the full path. If it isn't, search. */
1091 /* FIXME: convert it to wchar_t and use SearchPathW?
1092 * Remember: arguments to _start_process() are technically in UTF-8...
1094 if (non_const_filename[1] == ':')
1095 snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
1096 else if (!SearchPathA
1097 (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char),
1100 SetErrnoFromWinError (GetLastError ());
1101 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
1102 non_const_filename);
1103 GNUNET_free (non_const_filename);
1104 GNUNET_free (pathbuf);
1107 GNUNET_free (pathbuf);
1108 GNUNET_free (non_const_filename);
1110 /* Count the number of arguments */
1111 arg = (char **) argv;
1118 /* Allocate a copy argv */
1119 non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
1121 /* Copy all argv strings */
1123 arg = (char **) argv;
1127 non_const_argv[argcount] = GNUNET_strdup (path);
1129 non_const_argv[argcount] = GNUNET_strdup (*arg);
1133 non_const_argv[argcount] = NULL;
1137 arg = non_const_argv;
1140 cmdlen = cmdlen + strlen (*arg) + 4;
1144 /* Allocate and create cmd */
1145 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
1146 arg = non_const_argv;
1149 char arg_last_char = (*arg)[strlen (*arg) - 1];
1150 idx += sprintf (idx, "\"%s%s\"%s", *arg,
1151 arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : "");
1155 while (argcount > 0)
1156 GNUNET_free (non_const_argv[--argcount]);
1157 GNUNET_free (non_const_argv);
1159 memset (&start, 0, sizeof (start));
1160 start.cb = sizeof (start);
1161 if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
1162 start.dwFlags |= STARTF_USESTDHANDLES;
1164 stdih = GetStdHandle (STD_INPUT_HANDLE);
1165 GetHandleInformation (stdih, &stdif);
1166 if (pipe_stdin != NULL)
1168 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1169 (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
1170 &stdin_handle, sizeof (HANDLE));
1171 start.hStdInput = stdin_handle;
1175 if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1177 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 1);
1178 if (pipe_stdin == NULL)
1179 start.hStdInput = stdih;
1182 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
1186 stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
1187 GetHandleInformation (stdoh, &stdof);
1188 if (NULL != pipe_stdout)
1190 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1192 GNUNET_DISK_PIPE_END_WRITE),
1193 &stdout_handle, sizeof (HANDLE));
1194 start.hStdOutput = stdout_handle;
1198 if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1200 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 1);
1201 if (pipe_stdout == NULL)
1202 start.hStdOutput = stdoh;
1205 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, 0);
1208 stdeh = GetStdHandle (STD_ERROR_HANDLE);
1209 GetHandleInformation (stdeh, &stdef);
1212 if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1214 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 1);
1215 start.hStdError = stdeh;
1218 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, 0);
1221 if (GNUNET_YES == pipe_control)
1224 npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
1225 GNUNET_DISK_PERM_USER_READ |
1226 GNUNET_DISK_PERM_USER_WRITE);
1227 if (control_pipe == NULL)
1235 control_pipe = NULL;
1236 if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1238 lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1240 if (lsocks_pipe == NULL)
1244 GNUNET_DISK_pipe_close (lsocks_pipe);
1247 lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
1248 GNUNET_DISK_PIPE_END_WRITE);
1249 GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
1250 &lsocks_write, sizeof (HANDLE));
1251 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
1252 (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1253 &lsocks_read, sizeof (HANDLE));
1257 if (NULL != childpipename)
1259 LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
1261 GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1262 GNUNET_asprintf (&our_env[env_off++], "%s", childpipename);
1263 GNUNET_free (childpipename);
1265 if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1267 /*This will tell the child that we're going to send lsocks over the pipe*/
1268 GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1269 GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read);
1271 our_env[env_off++] = NULL;
1272 env_block = CreateCustomEnvTable (our_env);
1274 GNUNET_free_non_null (our_env[--env_off]);
1277 if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len)))
1279 LOG (GNUNET_ERROR_TYPE_DEBUG,
1280 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno);
1281 GNUNET_free (env_block);
1287 if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len)))
1289 LOG (GNUNET_ERROR_TYPE_DEBUG,
1290 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno);
1291 GNUNET_free (env_block);
1297 bresult = CreateProcessW (wpath, wcmd, NULL, NULL, TRUE,
1298 DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
1299 error_code = GetLastError ();
1301 if ((NULL == pipe_stdin) && (stdih))
1302 SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
1305 if ((NULL == pipe_stdout) && (stdoh))
1306 SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
1309 SetHandleInformation (stdeh, HANDLE_FLAG_INHERIT, stdef);
1311 GNUNET_free (env_block);
1318 SetErrnoFromWinError (error_code);
1319 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
1320 if (NULL != control_pipe)
1321 GNUNET_DISK_file_close (control_pipe);
1323 GNUNET_DISK_pipe_close (lsocks_pipe);
1327 gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
1328 gnunet_proc->pid = proc.dwProcessId;
1329 gnunet_proc->handle = proc.hProcess;
1330 gnunet_proc->control_pipe = control_pipe;
1332 CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
1334 ResumeThread (proc.hThread);
1335 CloseHandle (proc.hThread);
1337 if ( (NULL == lsocks) || (INVALID_SOCKET == lsocks[0]) )
1340 GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1342 /* This is a replacement for "goto error" that doesn't use goto */
1351 /* Tell the number of sockets */
1352 for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
1354 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1355 if (sizeof (count) != wrote)
1357 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1358 "Failed to write %u count bytes to the child: %u\n",
1359 sizeof (count), GetLastError ());
1362 for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1364 WSAPROTOCOL_INFOA pi;
1365 /* Get a socket duplication info */
1366 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1369 "Failed to duplicate an socket[%llu]: %u\n", i,
1373 /* Synchronous I/O is not nice, but we can't schedule this:
1374 * lsocks will be closed/freed by the caller soon, and until
1375 * the child creates a duplicate, closing a socket here will
1376 * close it for good.
1378 /* Send the size of the structure
1379 * (the child might be built with different headers...)
1382 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
1383 if (sizeof (size) != wrote)
1385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1386 "Failed to write %u size[%llu] bytes to the child: %u\n",
1387 sizeof (size), i, GetLastError ());
1390 /* Finally! Send the data */
1391 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
1392 if (sizeof (pi) != wrote)
1394 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1395 "Failed to write %u socket[%llu] bytes to the child: %u\n",
1396 sizeof (pi), i, GetLastError ());
1400 /* This will block us until the child makes a final read or closes
1401 * the pipe (hence no 'wrote' check), since we have to wait for it
1402 * to duplicate the last socket, before we return and start closing
1405 wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
1410 GNUNET_DISK_file_sync (lsocks_write_fd);
1411 GNUNET_DISK_pipe_close (lsocks_pipe);
1415 /* If we can't pass on the socket(s), the child will block forever,
1416 * better put it out of its misery.
1418 SafeTerminateProcess (gnunet_proc->handle, 0, 0);
1419 CloseHandle (gnunet_proc->handle);
1420 if (NULL != gnunet_proc->control_pipe)
1421 GNUNET_DISK_file_close (gnunet_proc->control_pipe);
1422 GNUNET_free (gnunet_proc);
1435 * @param pipe_control should a pipe be used to send signals to the child?
1436 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1437 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1438 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1439 * @param filename name of the binary
1440 * @param argv NULL-terminated array of arguments to the process
1441 * @return pointer to process structure of the new process, NULL on error
1443 struct GNUNET_OS_Process *
1444 GNUNET_OS_start_process_vap (int pipe_control,
1445 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1446 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1447 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1448 const char *filename,
1451 return start_process (pipe_control,
1464 * @param pipe_control should a pipe be used to send signals to the child?
1465 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1466 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1467 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1468 * @param filename name of the binary
1469 * @param va NULL-terminated list of arguments to the process
1470 * @return pointer to process structure of the new process, NULL on error
1472 struct GNUNET_OS_Process *
1473 GNUNET_OS_start_process_va (int pipe_control,
1474 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1475 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1476 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1477 const char *filename, va_list va)
1479 struct GNUNET_OS_Process *ret;
1486 while (NULL != va_arg (ap, char *))
1489 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
1492 while (NULL != (argv[argc] = va_arg (ap, char *)))
1495 ret = GNUNET_OS_start_process_vap (pipe_control,
1509 * @param pipe_control should a pipe be used to send signals to the child?
1510 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1511 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1512 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1513 * @param filename name of the binary
1514 * @param ... NULL-terminated list of arguments to the process
1515 * @return pointer to process structure of the new process, NULL on error
1517 struct GNUNET_OS_Process *
1518 GNUNET_OS_start_process (int pipe_control,
1519 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1520 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1521 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1522 const char *filename, ...)
1524 struct GNUNET_OS_Process *ret;
1527 va_start (ap, filename);
1528 ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
1529 pipe_stdout, filename, ap);
1538 * @param pipe_control should a pipe be used to send signals to the child?
1539 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
1540 * std handles of the parent are inherited by the child.
1541 * pipe_stdin and pipe_stdout take priority over std_inheritance
1542 * (when they are non-NULL).
1543 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1544 * must be NULL on platforms where dup is not supported
1545 * @param filename name of the binary
1546 * @param argv NULL-terminated list of arguments to the process
1547 * @return process ID of the new process, -1 on error
1549 struct GNUNET_OS_Process *
1550 GNUNET_OS_start_process_v (int pipe_control,
1551 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1552 const SOCKTYPE *lsocks,
1553 const char *filename,
1556 return start_process (pipe_control,
1567 * Retrieve the status of a process, waiting on him if dead.
1568 * Nonblocking version.
1570 * @param proc process ID
1571 * @param type status type
1572 * @param code return code/signal number
1573 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
1576 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
1577 enum GNUNET_OS_ProcessStatusType *type,
1578 unsigned long *code)
1584 GNUNET_assert (0 != proc);
1585 ret = waitpid (proc->pid, &status, WNOHANG);
1588 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1589 return GNUNET_SYSERR;
1593 *type = GNUNET_OS_PROCESS_RUNNING;
1597 if (proc->pid != ret)
1599 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1600 return GNUNET_SYSERR;
1602 if (WIFEXITED (status))
1604 *type = GNUNET_OS_PROCESS_EXITED;
1605 *code = WEXITSTATUS (status);
1607 else if (WIFSIGNALED (status))
1609 *type = GNUNET_OS_PROCESS_SIGNALED;
1610 *code = WTERMSIG (status);
1612 else if (WIFSTOPPED (status))
1614 *type = GNUNET_OS_PROCESS_SIGNALED;
1615 *code = WSTOPSIG (status);
1618 else if (WIFCONTINUED (status))
1620 *type = GNUNET_OS_PROCESS_RUNNING;
1626 *type = GNUNET_OS_PROCESS_UNKNOWN;
1631 DWORD c, error_code, ret;
1635 if (h == NULL || ret == 0)
1637 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1639 return GNUNET_SYSERR;
1642 h = GetCurrentProcess ();
1645 ret = GetExitCodeProcess (h, &c);
1646 error_code = GetLastError ();
1647 if (ret == 0 || error_code != NO_ERROR)
1649 SetErrnoFromWinError (error_code);
1650 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1651 return GNUNET_SYSERR;
1653 if (STILL_ACTIVE == c)
1655 *type = GNUNET_OS_PROCESS_RUNNING;
1659 *type = GNUNET_OS_PROCESS_EXITED;
1668 * Wait for a process
1670 * @param proc pointer to process structure
1671 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1674 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
1677 pid_t pid = proc->pid;
1680 while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
1681 (EINTR == errno) ) ;
1684 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
1685 return GNUNET_SYSERR;
1694 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
1696 return GNUNET_SYSERR;
1699 h = GetCurrentProcess ();
1701 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
1703 SetErrnoFromWinError (GetLastError ());
1704 return GNUNET_SYSERR;
1712 * Handle to a command.
1714 struct GNUNET_OS_CommandHandle
1720 struct GNUNET_OS_Process *eip;
1723 * Handle to the output pipe.
1725 struct GNUNET_DISK_PipeHandle *opipe;
1728 * Read-end of output pipe.
1730 const struct GNUNET_DISK_FileHandle *r;
1733 * Function to call on each line of output.
1735 GNUNET_OS_LineProcessor proc;
1738 * Closure for 'proc'.
1743 * Buffer for the output.
1748 * Task reading from pipe.
1750 GNUNET_SCHEDULER_TaskIdentifier rtask;
1755 struct GNUNET_TIME_Absolute timeout;
1758 * Current read offset in buf.
1765 * Stop/kill a command. Must ONLY be called either from
1766 * the callback after 'NULL' was passed for 'line' *OR*
1767 * from an independent task (not within the line processor).
1769 * @param cmd handle to the process
1772 GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1774 if (NULL != cmd->proc)
1776 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask);
1777 GNUNET_SCHEDULER_cancel (cmd->rtask);
1779 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1780 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1781 GNUNET_OS_process_destroy (cmd->eip);
1782 GNUNET_DISK_pipe_close (cmd->opipe);
1788 * Read from the process and call the line processor.
1790 * @param cls the 'struct GNUNET_OS_CommandHandle'
1791 * @param tc scheduler context
1794 cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1796 struct GNUNET_OS_CommandHandle *cmd = cls;
1797 GNUNET_OS_LineProcessor proc;
1801 cmd->rtask = GNUNET_SCHEDULER_NO_TASK;
1802 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1804 /* timeout, shutdown, etc. */
1807 proc (cmd->proc_cls, NULL);
1811 GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
1812 sizeof (cmd->buf) - cmd->off);
1815 if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
1817 cmd->buf[cmd->off] = '\0';
1818 cmd->proc (cmd->proc_cls, cmd->buf);
1822 proc (cmd->proc_cls, NULL);
1825 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1830 cmd->proc (cmd->proc_cls, cmd->buf);
1831 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1832 cmd->off -= (end + 1 - cmd->buf);
1833 end = memchr (cmd->buf, '\n', cmd->off);
1836 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
1837 (cmd->timeout), cmd->r, &cmd_read, cmd);
1842 * Run the given command line and call the given function
1843 * for each line of the output.
1845 * @param proc function to call for each line of the output
1846 * @param proc_cls closure for proc
1847 * @param timeout when to time out
1848 * @param binary command to run
1849 * @param ... arguments to command
1850 * @return NULL on error
1852 struct GNUNET_OS_CommandHandle *
1853 GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
1854 struct GNUNET_TIME_Relative timeout, const char *binary,
1857 struct GNUNET_OS_CommandHandle *cmd;
1858 struct GNUNET_OS_Process *eip;
1859 struct GNUNET_DISK_PipeHandle *opipe;
1862 opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1865 va_start (ap, binary);
1866 /* redirect stdout, don't inherit stderr/stdin */
1867 eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
1871 GNUNET_DISK_pipe_close (opipe);
1874 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1875 cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
1876 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1880 cmd->proc_cls = proc_cls;
1881 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1882 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1887 /* end of os_priority.c */