2 This file is part of GNUnet
3 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/os_priority.c
23 * @brief Methods to set process priority
28 #include "gnunet_util_lib.h"
32 #define LOG(kind, ...) GNUNET_log_from(kind, "util-os-priority", __VA_ARGS__)
34 #define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror(kind, "util-os-priority", syscall)
37 #define LOG_STRERROR_FILE(kind, syscall, filename) \
38 GNUNET_log_from_strerror_file(kind, "util-os-priority", syscall, filename)
40 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
43 struct GNUNET_OS_Process {
57 * Pipe we use to signal the process.
58 * NULL if unused, or if process was deemed uncontrollable.
60 struct GNUNET_DISK_FileHandle *control_pipe;
65 * Handle for 'this' process.
67 static struct GNUNET_OS_Process current_process;
70 * Handle for the #parent_control_handler() Task.
72 static struct GNUNET_SCHEDULER_Task *pch;
75 * Handle for the #shutdown_pch() Task.
77 static struct GNUNET_SCHEDULER_Task *spch;
81 * This handler is called on shutdown to remove the #pch.
83 * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
86 shutdown_pch(void *cls)
88 struct GNUNET_DISK_FileHandle *control_pipe = cls;
90 GNUNET_SCHEDULER_cancel(pch);
92 GNUNET_DISK_file_close(control_pipe);
98 * This handler is called when there are control data to be read on the pipe
100 * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
103 parent_control_handler(void *cls)
105 struct GNUNET_DISK_FileHandle *control_pipe = cls;
111 ret = GNUNET_DISK_file_read(control_pipe, &sig, sizeof(sig));
112 if (sizeof(sig) != ret)
115 LOG_STRERROR(GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
116 LOG(GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
117 GNUNET_DISK_file_close(control_pipe);
119 GNUNET_SCHEDULER_cancel(spch);
123 pipe_fd = getenv(GNUNET_OS_CONTROL_PIPE);
124 GNUNET_assert((NULL == pipe_fd) || (strlen(pipe_fd) <= 0));
125 LOG(GNUNET_ERROR_TYPE_DEBUG,
126 "Got control code %d from parent via pipe %s\n",
129 pch = GNUNET_SCHEDULER_add_read_file(GNUNET_TIME_UNIT_FOREVER_REL,
131 &parent_control_handler,
133 GNUNET_SIGNAL_raise((int)sig);
138 * Task that connects this process to its parent via pipe;
139 * essentially, the parent control handler will read signal numbers
140 * from the #GNUNET_OS_CONTROL_PIPE (as given in an environment
141 * variable) and raise those signals.
143 * @param cls closure (unused)
146 GNUNET_OS_install_parent_control_handler(void *cls)
150 struct GNUNET_DISK_FileHandle *control_pipe;
156 /* already done, we've been called twice... */
160 env_buf = getenv(GNUNET_OS_CONTROL_PIPE);
161 if ((NULL == env_buf) || (strlen(env_buf) <= 0))
163 LOG(GNUNET_ERROR_TYPE_DEBUG,
164 "Not installing a handler because $%s is empty\n",
165 GNUNET_OS_CONTROL_PIPE);
166 putenv(GNUNET_OS_CONTROL_PIPE "=");
170 pipe_fd = strtoull(env_buf, &env_buf_end, 16);
171 if ((0 != errno) || (env_buf == env_buf_end))
173 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
174 putenv(GNUNET_OS_CONTROL_PIPE "=");
177 #if !defined(WINDOWS)
178 if (pipe_fd >= FD_SETSIZE)
180 if ((FILE_TYPE_UNKNOWN == GetFileType((HANDLE)(uintptr_t)pipe_fd)) &&
181 (0 != GetLastError()))
184 LOG(GNUNET_ERROR_TYPE_ERROR,
185 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
187 putenv(GNUNET_OS_CONTROL_PIPE "=");
192 GNUNET_DISK_get_handle_from_w32_handle((HANDLE)(uintptr_t)pipe_fd);
194 control_pipe = GNUNET_DISK_get_handle_from_int_fd((int)pipe_fd);
196 if (NULL == control_pipe)
198 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
199 putenv(GNUNET_OS_CONTROL_PIPE "=");
202 LOG(GNUNET_ERROR_TYPE_DEBUG,
203 "Adding parent control handler pipe `%s' to the scheduler\n",
205 pch = GNUNET_SCHEDULER_add_read_file(GNUNET_TIME_UNIT_FOREVER_REL,
207 &parent_control_handler,
209 spch = GNUNET_SCHEDULER_add_shutdown(&shutdown_pch, control_pipe);
210 putenv(GNUNET_OS_CONTROL_PIPE "=");
215 * Get process structure for current process
217 * The pointer it returns points to static memory location and must
218 * not be deallocated/closed.
220 * @return pointer to the process sturcutre for this process
222 struct GNUNET_OS_Process *
223 GNUNET_OS_process_current()
226 current_process.pid = GetCurrentProcessId();
227 current_process.handle = GetCurrentProcess();
229 current_process.pid = 0;
231 return ¤t_process;
236 * Sends a signal to the process
238 * @param proc pointer to process structure
240 * @return 0 on success, -1 on error
243 GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
249 if (NULL != proc->control_pipe)
251 LOG(GNUNET_ERROR_TYPE_DEBUG,
252 "Sending signal %d to pid: %u via pipe\n",
255 ret = GNUNET_DISK_file_write(proc->control_pipe, &csig, sizeof(csig));
256 if (sizeof(csig) == ret)
259 /* pipe failed or non-existent, try other methods */
262 #if !defined(WINDOWS)
268 #if (SIGTERM != GNUNET_TERM_SIG)
269 case GNUNET_TERM_SIG:
271 #if defined(WINDOWS) && !defined(__CYGWIN__)
274 int must_kill = GNUNET_YES;
275 if (0 != GetExitCodeProcess(proc->handle, &exitcode))
276 must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
277 if (GNUNET_YES == must_kill)
279 if (0 == SafeTerminateProcess(proc->handle, 0, 0))
281 DWORD error_code = GetLastError();
282 if ((error_code != WAIT_TIMEOUT) &&
283 (error_code != ERROR_PROCESS_ABORTED))
285 LOG((error_code == ERROR_ACCESS_DENIED) ? GNUNET_ERROR_TYPE_INFO
286 : GNUNET_ERROR_TYPE_WARNING,
287 "SafeTermiateProcess failed with code %lu\n",
289 /* The problem here is that a process that is already dying
290 * might cause SafeTerminateProcess to fail with
291 * ERROR_ACCESS_DENIED, but the process WILL die eventually.
292 * If we really had a permissions problem, hanging up (which
293 * is what will happen in process_wait() in that case) is
296 if (ERROR_ACCESS_DENIED == error_code)
302 SetErrnoFromWinError(error_code);
311 LOG(GNUNET_ERROR_TYPE_DEBUG,
312 "Sending signal %d to pid: %u via system call\n",
315 return kill(proc->pid, sig);
322 LOG(GNUNET_ERROR_TYPE_DEBUG,
323 "Sending signal %d to pid: %u via system call\n",
326 return kill(proc->pid, sig);
333 * Get the pid of the process in question
335 * @param proc the process to get the pid of
337 * @return the current process id
340 GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
347 * Cleans up process structure contents (OS-dependent) and deallocates
350 * @param proc pointer to process structure
353 GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
355 if (NULL != proc->control_pipe)
356 GNUNET_DISK_file_close(proc->control_pipe);
358 if (NULL != proc->handle)
359 CloseHandle(proc->handle);
366 #include "gnunet_signal_lib.h"
368 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
371 * Make seaspider happy.
373 #define DWORD_WINAPI DWORD WINAPI
377 * @brief Waits for a process to terminate and invokes the SIGCHLD handler
378 * @param proc pointer to process structure
381 child_wait_thread(void *arg)
383 struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *)arg;
385 WaitForSingleObject(proc->handle, INFINITE);
387 if (w32_sigchld_handler)
388 w32_sigchld_handler();
397 CreateCustomEnvTable(char **vars)
399 char *win32_env_table;
404 size_t tablesize = 0;
405 size_t items_count = 0;
414 win32_env_table = GetEnvironmentStringsA();
415 if (NULL == win32_env_table)
417 for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++)
420 index = GNUNET_malloc(sizeof(char *) * n_var);
421 for (c = 0; c < n_var; c++)
423 for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
425 size_t len = strlen(ptr);
428 for (var_ptr = vars; *var_ptr; var_ptr++)
432 var_len = strlen(var);
433 if (strncmp(var, ptr, var_len) == 0)
437 tablesize += var_len + strlen(val) + 1;
442 tablesize += len + 1;
445 for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
450 n_found += strlen(var) + strlen(val) + 1;
452 result = GNUNET_malloc(tablesize + n_found + 1);
453 for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
455 size_t len = strlen(ptr);
458 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
462 var_len = strlen(var);
463 if (strncmp(var, ptr, var_len) == 0)
471 strcpy(result_ptr, ptr);
472 result_ptr += len + 1;
476 strcpy(result_ptr, var);
477 result_ptr += var_len;
478 strcpy(result_ptr, val);
479 result_ptr += strlen(val) + 1;
483 for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
487 var_len = strlen(var);
490 strcpy(result_ptr, var);
491 result_ptr += var_len;
492 strcpy(result_ptr, val);
493 result_ptr += strlen(val) + 1;
496 FreeEnvironmentStrings(win32_env_table);
505 * Open '/dev/null' and make the result the given
508 * @param target_fd desired FD to point to /dev/null
509 * @param flags open flags (O_RDONLY, O_WRONLY)
512 open_dev_null(int target_fd, int flags)
516 fd = open("/dev/null", flags);
519 GNUNET_log_strerror_file(GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
524 if (-1 == dup2(fd, target_fd))
526 GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "dup2");
530 GNUNET_break(0 == close(fd));
538 * @param pipe_control should a pipe be used to send signals to the child?
539 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
540 * std handles of the parent are inherited by the child.
541 * pipe_stdin and pipe_stdout take priority over std_inheritance
542 * (when they are non-NULL).
543 * @param pipe_stdin pipe to use to send input to child process (or NULL)
544 * @param pipe_stdout pipe to use to get output from child process (or NULL)
545 * @param pipe_stderr pipe to use for stderr for child process (or NULL)
546 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
547 * must be NULL on platforms where dup is not supported
548 * @param filename name of the binary
549 * @param argv NULL-terminated list of arguments to the process
550 * @return process ID of the new process, -1 on error
552 static struct GNUNET_OS_Process *
553 start_process(int pipe_control,
554 enum GNUNET_OS_InheritStdioFlags std_inheritance,
555 struct GNUNET_DISK_PipeHandle *pipe_stdin,
556 struct GNUNET_DISK_PipeHandle *pipe_stdout,
557 struct GNUNET_DISK_PipeHandle *pipe_stderr,
558 const SOCKTYPE *lsocks,
559 const char *filename,
565 struct GNUNET_OS_Process *gnunet_proc;
566 struct GNUNET_DISK_FileHandle *childpipe_read;
567 struct GNUNET_DISK_FileHandle *childpipe_write;
568 int childpipe_read_fd;
584 GNUNET_OS_check_helper_binary(filename, GNUNET_NO, NULL))
585 return NULL; /* not executable */
586 if (GNUNET_YES == pipe_control)
588 struct GNUNET_DISK_PipeHandle *childpipe;
589 int dup_childpipe_read_fd = -1;
591 childpipe = GNUNET_DISK_pipe(GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
592 if (NULL == childpipe)
595 GNUNET_DISK_pipe_detach_end(childpipe, GNUNET_DISK_PIPE_END_READ);
597 GNUNET_DISK_pipe_detach_end(childpipe, GNUNET_DISK_PIPE_END_WRITE);
598 GNUNET_DISK_pipe_close(childpipe);
599 if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
600 (GNUNET_OK != GNUNET_DISK_internal_file_handle_(childpipe_read,
603 (-1 == (dup_childpipe_read_fd = dup(childpipe_read_fd))))
605 if (NULL != childpipe_read)
606 GNUNET_DISK_file_close(childpipe_read);
607 if (NULL != childpipe_write)
608 GNUNET_DISK_file_close(childpipe_write);
609 if (0 <= dup_childpipe_read_fd)
610 close(dup_childpipe_read_fd);
613 childpipe_read_fd = dup_childpipe_read_fd;
614 GNUNET_DISK_file_close(childpipe_read);
618 childpipe_write = NULL;
619 childpipe_read_fd = -1;
621 if (NULL != pipe_stdin)
625 GNUNET_DISK_internal_file_handle_(
626 GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ),
631 GNUNET_DISK_internal_file_handle_(
632 GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
636 if (NULL != pipe_stdout)
640 GNUNET_DISK_internal_file_handle_(
641 GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE),
646 GNUNET_DISK_internal_file_handle_(
647 GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_READ),
651 if (NULL != pipe_stderr)
655 GNUNET_DISK_internal_file_handle_(
656 GNUNET_DISK_pipe_handle(pipe_stderr, GNUNET_DISK_PIPE_END_READ),
661 GNUNET_DISK_internal_file_handle_(
662 GNUNET_DISK_pipe_handle(pipe_stderr, GNUNET_DISK_PIPE_END_WRITE),
671 while (-1 != (k = lsocks[i++]))
672 GNUNET_array_append(lscp, ls, k);
673 GNUNET_array_append(lscp, ls, -1);
676 /* see https://gnunet.org/vfork */
684 LOG_STRERROR(GNUNET_ERROR_TYPE_ERROR, "fork");
685 GNUNET_array_grow(lscp, ls, 0);
686 if (NULL != childpipe_write)
687 GNUNET_DISK_file_close(childpipe_write);
688 if (0 <= childpipe_read_fd)
689 close(childpipe_read_fd);
695 unsetenv(GNUNET_OS_CONTROL_PIPE);
696 gnunet_proc = GNUNET_new(struct GNUNET_OS_Process);
697 gnunet_proc->pid = ret;
698 gnunet_proc->control_pipe = childpipe_write;
699 if (GNUNET_YES == pipe_control)
701 close(childpipe_read_fd);
703 GNUNET_array_grow(lscp, ls, 0);
706 if (0 <= childpipe_read_fd)
710 /* due to vfork, we must NOT free memory on DARWIN! */
711 GNUNET_DISK_file_close(childpipe_write);
713 snprintf(fdbuf, 100, "%x", childpipe_read_fd);
714 setenv(GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
717 unsetenv(GNUNET_OS_CONTROL_PIPE);
718 if (NULL != pipe_stdin)
720 GNUNET_break(0 == close(fd_stdin_write));
721 if (-1 == dup2(fd_stdin_read, 0))
722 LOG_STRERROR(GNUNET_ERROR_TYPE_ERROR, "dup2");
723 GNUNET_break(0 == close(fd_stdin_read));
725 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
727 GNUNET_break(0 == close(0));
728 open_dev_null(0, O_RDONLY);
730 if (NULL != pipe_stdout)
732 GNUNET_break(0 == close(fd_stdout_read));
733 if (-1 == dup2(fd_stdout_write, 1))
734 LOG_STRERROR(GNUNET_ERROR_TYPE_ERROR, "dup2");
735 GNUNET_break(0 == close(fd_stdout_write));
737 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
739 GNUNET_break(0 == close(1));
740 open_dev_null(1, O_WRONLY);
742 if (NULL != pipe_stderr)
744 GNUNET_break(0 == close(fd_stderr_read));
745 if (-1 == dup2(fd_stderr_write, 2))
746 LOG_STRERROR(GNUNET_ERROR_TYPE_ERROR, "dup2");
747 GNUNET_break(0 == close(fd_stderr_write));
749 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
751 GNUNET_break(0 == close(2));
752 open_dev_null(2, O_WRONLY);
756 /* read systemd documentation... */
759 while (-1 != lscp[i])
762 while (-1 != lscp[j])
768 GNUNET_assert(-1 != k);
769 GNUNET_assert(0 == close(lscp[j]));
777 /* Bury any existing FD, no matter what; they should all be closed
778 * on exec anyway and the important onces have been dup'ed away */
780 GNUNET_assert(-1 != dup2(lscp[i], tgt));
782 /* unset close-on-exec flag */
783 flags = fcntl(tgt, F_GETFD);
784 GNUNET_assert(flags >= 0);
785 flags &= ~FD_CLOEXEC;
787 (void)fcntl(tgt, F_SETFD, flags);
791 GNUNET_snprintf(fds, sizeof(fds), "%u", i);
792 setenv("LISTEN_FDS", fds, 1);
795 /* due to vfork, we must NOT free memory on DARWIN! */
796 GNUNET_array_grow(lscp, ls, 0);
798 execvp(filename, argv);
799 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
802 struct GNUNET_DISK_FileHandle *childpipe_read;
803 struct GNUNET_DISK_FileHandle *childpipe_write;
804 HANDLE childpipe_read_handle;
806 char **non_const_argv;
811 PROCESS_INFORMATION proc;
813 struct GNUNET_OS_Process *gnunet_proc;
814 char path[MAX_PATH + 1];
815 char *our_env[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
816 char *env_block = NULL;
824 char *non_const_filename;
825 char win_path[MAX_PATH + 1];
826 struct GNUNET_DISK_PipeHandle *lsocks_pipe;
827 const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
838 HANDLE stdout_handle;
839 HANDLE stdih, stdoh, stdeh;
840 DWORD stdif, stdof, stdef;
843 DWORD create_no_window;
846 GNUNET_OS_check_helper_binary(filename, GNUNET_NO, NULL))
847 return NULL; /* not executable */
849 /* Search in prefix dir (hopefully - the directory from which
850 * the current module was loaded), bindir and libdir, then in PATH
852 self_prefix = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_SELF_PREFIX);
853 bindir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_BINDIR);
854 libdir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_LIBDIR);
856 pathbuf_len = GetEnvironmentVariableA("PATH", (char *)&pathbuf, 0);
858 alloc_len = pathbuf_len + 1 + strlen(self_prefix) + 1 + strlen(bindir) + 1 +
861 pathbuf = GNUNET_malloc(alloc_len * sizeof(char));
864 ptr += sprintf(pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
865 GNUNET_free(self_prefix);
869 alloc_len = GetEnvironmentVariableA("PATH", ptr, pathbuf_len);
870 if (alloc_len != pathbuf_len - 1)
872 GNUNET_free(pathbuf);
873 errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
877 cmdlen = strlen(filename);
878 if ((cmdlen < 5) || (0 != strcmp(&filename[cmdlen - 4], ".exe")))
879 GNUNET_asprintf(&non_const_filename, "%s.exe", filename);
881 GNUNET_asprintf(&non_const_filename, "%s", filename);
883 /* It could be in POSIX form, convert it to a DOS path early on */
885 (lRet = plibc_conv_to_win_path(non_const_filename, win_path)))
887 SetErrnoFromWinError(lRet);
888 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_ERROR,
889 "plibc_conv_to_win_path",
891 GNUNET_free(non_const_filename);
892 GNUNET_free(pathbuf);
895 GNUNET_free(non_const_filename);
896 non_const_filename = GNUNET_strdup(win_path);
897 /* Check that this is the full path. If it isn't, search. */
898 /* FIXME: convert it to wchar_t and use SearchPathW?
899 * Remember: arguments to _start_process() are technically in UTF-8...
901 if (non_const_filename[1] == ':')
903 snprintf(path, sizeof(path) / sizeof(char), "%s", non_const_filename);
904 LOG(GNUNET_ERROR_TYPE_DEBUG,
905 "Using path `%s' as-is. PATH is %s\n",
909 else if (!SearchPathA(pathbuf,
912 sizeof(path) / sizeof(char),
916 SetErrnoFromWinError(GetLastError());
917 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_ERROR,
920 GNUNET_free(non_const_filename);
921 GNUNET_free(pathbuf);
925 LOG(GNUNET_ERROR_TYPE_DEBUG, "Found `%s' in PATH `%s'\n", path, pathbuf);
926 GNUNET_free(pathbuf);
927 GNUNET_free(non_const_filename);
929 /* Count the number of arguments */
937 /* Allocate a copy argv */
938 non_const_argv = GNUNET_malloc(sizeof(char *) * (argcount + 1));
940 /* Copy all argv strings */
946 non_const_argv[argcount] = GNUNET_strdup(path);
948 non_const_argv[argcount] = GNUNET_strdup(*arg);
952 non_const_argv[argcount] = NULL;
956 arg = non_const_argv;
959 cmdlen = cmdlen + strlen(*arg) + 4;
963 /* Allocate and create cmd */
964 cmd = idx = GNUNET_malloc(sizeof(char) * cmdlen);
965 arg = non_const_argv;
968 char arg_last_char = (*arg)[strlen(*arg) - 1];
972 arg_last_char == '\\' ? "\\" : "",
973 *(arg + 1) ? " " : "");
978 GNUNET_free(non_const_argv[--argcount]);
979 GNUNET_free(non_const_argv);
981 memset(&start, 0, sizeof(start));
982 start.cb = sizeof(start);
983 if ((pipe_stdin != NULL) || (pipe_stdout != NULL) || (std_inheritance != 0))
984 start.dwFlags |= STARTF_USESTDHANDLES;
986 stdih = GetStdHandle(STD_INPUT_HANDLE);
987 GetHandleInformation(stdih, &stdif);
988 if (pipe_stdin != NULL)
990 GNUNET_DISK_internal_file_handle_(
991 GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ),
994 start.hStdInput = stdin_handle;
998 if (std_inheritance & GNUNET_OS_INHERIT_STD_IN)
1000 SetHandleInformation(stdih, HANDLE_FLAG_INHERIT, 1);
1001 if (pipe_stdin == NULL)
1002 start.hStdInput = stdih;
1005 SetHandleInformation(stdih, HANDLE_FLAG_INHERIT, 0);
1009 stdoh = GetStdHandle(STD_OUTPUT_HANDLE);
1010 GetHandleInformation(stdoh, &stdof);
1011 if (NULL != pipe_stdout)
1013 GNUNET_DISK_internal_file_handle_(
1014 GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE),
1017 start.hStdOutput = stdout_handle;
1021 if (std_inheritance & GNUNET_OS_INHERIT_STD_OUT)
1023 SetHandleInformation(stdoh, HANDLE_FLAG_INHERIT, 1);
1024 if (pipe_stdout == NULL)
1025 start.hStdOutput = stdoh;
1028 SetHandleInformation(stdoh, HANDLE_FLAG_INHERIT, 0);
1031 stdeh = GetStdHandle(STD_ERROR_HANDLE);
1032 GetHandleInformation(stdeh, &stdef);
1035 if (std_inheritance & GNUNET_OS_INHERIT_STD_ERR)
1037 SetHandleInformation(stdeh, HANDLE_FLAG_INHERIT, 1);
1038 start.hStdError = stdeh;
1041 SetHandleInformation(stdeh, HANDLE_FLAG_INHERIT, 0);
1044 if (GNUNET_YES == pipe_control)
1046 struct GNUNET_DISK_PipeHandle *childpipe;
1047 childpipe = GNUNET_DISK_pipe(GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
1048 if (NULL == childpipe)
1051 GNUNET_DISK_pipe_detach_end(childpipe, GNUNET_DISK_PIPE_END_READ);
1053 GNUNET_DISK_pipe_detach_end(childpipe, GNUNET_DISK_PIPE_END_WRITE);
1054 GNUNET_DISK_pipe_close(childpipe);
1055 if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
1056 (GNUNET_OK != GNUNET_DISK_internal_file_handle_(childpipe_read,
1057 &childpipe_read_handle,
1061 GNUNET_DISK_file_close(childpipe_read);
1062 if (childpipe_write)
1063 GNUNET_DISK_file_close(childpipe_write);
1067 /* Unlike *nix variant, we don't dup the handle, so can't close
1068 * filehandle right now.
1070 SetHandleInformation(childpipe_read_handle, HANDLE_FLAG_INHERIT, 1);
1074 childpipe_read = NULL;
1075 childpipe_write = NULL;
1078 if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
1081 GNUNET_DISK_pipe(GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1083 if (lsocks_pipe == NULL)
1086 GNUNET_DISK_pipe_close(lsocks_pipe);
1087 if (GNUNET_YES == pipe_control)
1089 GNUNET_DISK_file_close(childpipe_write);
1090 GNUNET_DISK_file_close(childpipe_read);
1095 GNUNET_DISK_pipe_handle(lsocks_pipe, GNUNET_DISK_PIPE_END_WRITE);
1096 GNUNET_DISK_internal_file_handle_(lsocks_write_fd,
1099 GNUNET_DISK_internal_file_handle_(
1100 GNUNET_DISK_pipe_handle(lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
1107 lsocks_write_fd = NULL;
1111 if (GNUNET_YES == pipe_control)
1113 GNUNET_asprintf(&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE);
1114 GNUNET_asprintf(&our_env[env_off++], "%p", childpipe_read_handle);
1116 if ((lsocks != NULL) && (lsocks[0] != INVALID_SOCKET))
1118 /*This will tell the child that we're going to send lsocks over the pipe*/
1119 GNUNET_asprintf(&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS");
1120 GNUNET_asprintf(&our_env[env_off++], "%lu", lsocks_read);
1122 our_env[env_off++] = NULL;
1123 env_block = CreateCustomEnvTable(our_env);
1125 GNUNET_free_non_null(our_env[--env_off]);
1130 u8_to_u16((uint8_t *)path, 1 + strlen(path), NULL, &wpath_len)))
1132 LOG(GNUNET_ERROR_TYPE_DEBUG,
1133 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n",
1136 GNUNET_free(env_block);
1139 GNUNET_DISK_pipe_close(lsocks_pipe);
1140 if (GNUNET_YES == pipe_control)
1142 GNUNET_DISK_file_close(childpipe_write);
1143 GNUNET_DISK_file_close(childpipe_read);
1150 (wcmd = u8_to_u16((uint8_t *)cmd, 1 + strlen(cmd), NULL, &wcmd_len)))
1152 LOG(GNUNET_ERROR_TYPE_DEBUG,
1153 "Failed to convert `%s' from UTF-8 to UTF-16: %d\n",
1156 GNUNET_free(env_block);
1160 GNUNET_DISK_pipe_close(lsocks_pipe);
1161 if (GNUNET_YES == pipe_control)
1163 GNUNET_DISK_file_close(childpipe_write);
1164 GNUNET_DISK_file_close(childpipe_read);
1169 create_no_window = 0;
1171 HANDLE console_input = CreateFile("CONIN$",
1173 FILE_SHARE_READ | FILE_SHARE_WRITE,
1178 if (INVALID_HANDLE_VALUE == console_input)
1179 create_no_window = CREATE_NO_WINDOW;
1181 CloseHandle(console_input);
1184 bresult = CreateProcessW(wpath,
1189 create_no_window | CREATE_SUSPENDED,
1194 error_code = GetLastError();
1196 if ((NULL == pipe_stdin) && (stdih))
1197 SetHandleInformation(stdih, HANDLE_FLAG_INHERIT, stdif);
1200 if ((NULL == pipe_stdout) && (stdoh))
1201 SetHandleInformation(stdoh, HANDLE_FLAG_INHERIT, stdof);
1204 SetHandleInformation(stdeh, HANDLE_FLAG_INHERIT, stdef);
1207 LOG(GNUNET_ERROR_TYPE_ERROR,
1208 "CreateProcess(%s, %s) failed: %lu\n",
1213 GNUNET_free(env_block);
1217 if (GNUNET_YES == pipe_control)
1219 GNUNET_DISK_file_close(childpipe_read);
1224 if (GNUNET_YES == pipe_control)
1226 GNUNET_DISK_file_close(childpipe_write);
1229 GNUNET_DISK_pipe_close(lsocks_pipe);
1230 SetErrnoFromWinError(error_code);
1234 gnunet_proc = GNUNET_new(struct GNUNET_OS_Process);
1235 gnunet_proc->pid = proc.dwProcessId;
1236 gnunet_proc->handle = proc.hProcess;
1237 gnunet_proc->control_pipe = childpipe_write;
1239 CreateThread(NULL, 64000, &child_wait_thread, (void *)gnunet_proc, 0, NULL);
1241 ResumeThread(proc.hThread);
1242 CloseHandle(proc.hThread);
1244 if ((NULL == lsocks) || (INVALID_SOCKET == lsocks[0]))
1247 GNUNET_DISK_pipe_close_end(lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
1249 /* This is a replacement for "goto error" that doesn't use goto */
1258 /* Tell the number of sockets */
1259 for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++)
1262 wrote = GNUNET_DISK_file_write(lsocks_write_fd, &count, sizeof(count));
1263 if (sizeof(count) != wrote)
1265 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1266 "Failed to write %u count bytes to the child: %lu\n",
1271 for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
1273 WSAPROTOCOL_INFOA pi;
1274 /* Get a socket duplication info */
1276 WSADuplicateSocketA(lsocks[i], gnunet_proc->pid, &pi))
1278 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1279 "Failed to duplicate an socket[%u]: %lu\n",
1284 /* Synchronous I/O is not nice, but we can't schedule this:
1285 * lsocks will be closed/freed by the caller soon, and until
1286 * the child creates a duplicate, closing a socket here will
1287 * close it for good.
1289 /* Send the size of the structure
1290 * (the child might be built with different headers...)
1293 wrote = GNUNET_DISK_file_write(lsocks_write_fd, &size, sizeof(size));
1294 if (sizeof(size) != wrote)
1296 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1297 "Failed to write %u size[%u] bytes to the child: %lu\n",
1303 /* Finally! Send the data */
1304 wrote = GNUNET_DISK_file_write(lsocks_write_fd, &pi, sizeof(pi));
1305 if (sizeof(pi) != wrote)
1307 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1308 "Failed to write %u socket[%u] bytes to the child: %lu\n",
1315 /* This will block us until the child makes a final read or closes
1316 * the pipe (hence no 'wrote' check), since we have to wait for it
1317 * to duplicate the last socket, before we return and start closing
1320 wrote = GNUNET_DISK_file_write(lsocks_write_fd, &count, sizeof(count));
1325 GNUNET_DISK_file_sync(lsocks_write_fd);
1326 GNUNET_DISK_pipe_close(lsocks_pipe);
1330 /* If we can't pass on the socket(s), the child will block forever,
1331 * better put it out of its misery.
1333 SafeTerminateProcess(gnunet_proc->handle, 0, 0);
1334 CloseHandle(gnunet_proc->handle);
1335 if (NULL != gnunet_proc->control_pipe)
1336 GNUNET_DISK_file_close(gnunet_proc->control_pipe);
1337 GNUNET_free(gnunet_proc);
1348 * @param pipe_control should a pipe be used to send signals to the child?
1349 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1350 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1351 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1352 * @param pipe_stderr pipe to use to get output from child process (or NULL)
1353 * @param filename name of the binary
1354 * @param argv NULL-terminated array of arguments to the process
1355 * @return pointer to process structure of the new process, NULL on error
1357 struct GNUNET_OS_Process *
1358 GNUNET_OS_start_process_vap(int pipe_control,
1359 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1360 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1361 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1362 struct GNUNET_DISK_PipeHandle *pipe_stderr,
1363 const char *filename,
1366 return start_process(pipe_control,
1380 * @param pipe_control should a pipe be used to send signals to the child?
1381 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1382 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1383 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1384 * @param pipe_stderr pipe to use to get output from child process (or NULL)
1385 * @param filename name of the binary
1386 * @param va NULL-terminated list of arguments to the process
1387 * @return pointer to process structure of the new process, NULL on error
1389 struct GNUNET_OS_Process *
1390 GNUNET_OS_start_process_va(int pipe_control,
1391 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1392 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1393 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1394 struct GNUNET_DISK_PipeHandle *pipe_stderr,
1395 const char *filename,
1398 struct GNUNET_OS_Process *ret;
1405 while (NULL != va_arg(ap, char *))
1408 argv = GNUNET_malloc(sizeof(char *) * (argc + 1));
1411 while (NULL != (argv[argc] = va_arg(ap, char *)))
1414 ret = GNUNET_OS_start_process_vap(pipe_control,
1429 * @param pipe_control should a pipe be used to send signals to the child?
1430 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1431 * @param pipe_stdin pipe to use to send input to child process (or NULL)
1432 * @param pipe_stdout pipe to use to get output from child process (or NULL)
1433 * @param filename name of the binary
1434 * @param ... NULL-terminated list of arguments to the process
1435 * @return pointer to process structure of the new process, NULL on error
1437 struct GNUNET_OS_Process *
1438 GNUNET_OS_start_process(int pipe_control,
1439 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1440 struct GNUNET_DISK_PipeHandle *pipe_stdin,
1441 struct GNUNET_DISK_PipeHandle *pipe_stdout,
1442 struct GNUNET_DISK_PipeHandle *pipe_stderr,
1443 const char *filename,
1446 struct GNUNET_OS_Process *ret;
1449 va_start(ap, filename);
1450 ret = GNUNET_OS_start_process_va(pipe_control,
1465 * @param pipe_control should a pipe be used to send signals to the child?
1466 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
1467 * std handles of the parent are inherited by the child.
1468 * pipe_stdin and pipe_stdout take priority over std_inheritance
1469 * (when they are non-NULL).
1470 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1471 * must be NULL on platforms where dup is not supported
1472 * @param filename name of the binary
1473 * @param argv NULL-terminated list of arguments to the process
1474 * @return process ID of the new process, -1 on error
1476 struct GNUNET_OS_Process *
1477 GNUNET_OS_start_process_v(int pipe_control,
1478 enum GNUNET_OS_InheritStdioFlags std_inheritance,
1479 const SOCKTYPE *lsocks,
1480 const char *filename,
1483 return start_process(pipe_control,
1495 * Start a process. This function is similar to the GNUNET_OS_start_process_*
1496 * except that the filename and arguments can have whole strings which contain
1497 * the arguments. These arguments are to be separated by spaces and are parsed
1498 * in the order they appear. Arguments containing spaces can be used by
1499 * quoting them with @em ".
1501 * @param pipe_control should a pipe be used to send signals to the child?
1502 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
1503 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
1504 * must be NULL on platforms where dup is not supported
1505 * @param filename name of the binary. It is valid to have the arguments
1506 * in this string when they are separated by spaces.
1507 * @param ... more arguments. Should be of type `char *`. It is valid
1508 * to have the arguments in these strings when they are separated by
1509 * spaces. The last argument MUST be NULL.
1510 * @return pointer to process structure of the new process, NULL on error
1512 struct GNUNET_OS_Process *
1513 GNUNET_OS_start_process_s(int pipe_control,
1514 unsigned int std_inheritance,
1515 const SOCKTYPE *lsocks,
1516 const char *filename,
1521 unsigned int argv_size;
1527 struct GNUNET_OS_Process *proc;
1534 va_start(ap, filename);
1541 while ('\0' != *rpos)
1550 if ((' ' == *rpos) && (0 == quote_on))
1556 while (' ' == *rpos)
1559 if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
1567 while (NULL != (arg = (va_arg(ap, const char *))));
1570 argv = GNUNET_malloc(argv_size * sizeof(char *));
1572 va_start(ap, filename);
1577 cp = GNUNET_strdup(arg);
1580 while ('\0' != *pos)
1589 if ((' ' == *pos) && (0 == quote_on))
1593 argv[argv_size++] = GNUNET_strdup(last);
1599 if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
1605 argv[argv_size++] = GNUNET_strdup(last);
1609 while (NULL != (arg = (va_arg(ap, const char *))));
1611 argv[argv_size] = NULL;
1613 for (i = 0; i < argv_size; i++)
1615 len = strlen(argv[i]);
1616 if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
1618 memmove(&argv[i][0], &argv[i][1], len - 2);
1619 argv[i][len - 2] = '\0';
1622 binary_path = argv[0];
1623 proc = GNUNET_OS_start_process_v(pipe_control,
1628 while (argv_size > 0)
1629 GNUNET_free(argv[--argv_size]);
1636 * Retrieve the status of a process, waiting on it if dead.
1637 * Nonblocking version.
1639 * @param proc process ID
1640 * @param type status type
1641 * @param code return code/signal number
1642 * @param options WNOHANG if non-blocking is desired
1643 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
1646 process_status(struct GNUNET_OS_Process *proc,
1647 enum GNUNET_OS_ProcessStatusType *type,
1648 unsigned long *code,
1655 GNUNET_assert(0 != proc);
1656 ret = waitpid(proc->pid, &status, options);
1659 LOG_STRERROR(GNUNET_ERROR_TYPE_WARNING, "waitpid");
1660 return GNUNET_SYSERR;
1664 *type = GNUNET_OS_PROCESS_RUNNING;
1668 if (proc->pid != ret)
1670 LOG_STRERROR(GNUNET_ERROR_TYPE_WARNING, "waitpid");
1671 return GNUNET_SYSERR;
1673 if (WIFEXITED(status))
1675 *type = GNUNET_OS_PROCESS_EXITED;
1676 *code = WEXITSTATUS(status);
1678 else if (WIFSIGNALED(status))
1680 *type = GNUNET_OS_PROCESS_SIGNALED;
1681 *code = WTERMSIG(status);
1683 else if (WIFSTOPPED(status))
1685 *type = GNUNET_OS_PROCESS_SIGNALED;
1686 *code = WSTOPSIG(status);
1689 else if (WIFCONTINUED(status))
1691 *type = GNUNET_OS_PROCESS_RUNNING;
1697 *type = GNUNET_OS_PROCESS_UNKNOWN;
1702 #define WNOHANG 42 /* just a flag for W32, purely internal at this point */
1706 DWORD c, error_code, ret;
1710 if (h == NULL || ret == 0)
1712 LOG(GNUNET_ERROR_TYPE_WARNING,
1713 "Invalid process information {%d, %08X}\n",
1716 return GNUNET_SYSERR;
1719 h = GetCurrentProcess();
1721 if (WNOHANG != options)
1723 if (WAIT_OBJECT_0 != WaitForSingleObject(h, INFINITE))
1725 SetErrnoFromWinError(GetLastError());
1726 return GNUNET_SYSERR;
1730 ret = GetExitCodeProcess(h, &c);
1731 error_code = GetLastError();
1732 if (ret == 0 || error_code != NO_ERROR)
1734 SetErrnoFromWinError(error_code);
1735 LOG_STRERROR(GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
1736 return GNUNET_SYSERR;
1738 if (STILL_ACTIVE == c)
1740 *type = GNUNET_OS_PROCESS_RUNNING;
1744 *type = GNUNET_OS_PROCESS_EXITED;
1753 * Retrieve the status of a process, waiting on it if dead.
1754 * Nonblocking version.
1756 * @param proc process ID
1757 * @param type status type
1758 * @param code return code/signal number
1759 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
1762 GNUNET_OS_process_status(struct GNUNET_OS_Process *proc,
1763 enum GNUNET_OS_ProcessStatusType *type,
1764 unsigned long *code)
1766 return process_status(proc, type, code, WNOHANG);
1771 * Retrieve the status of a process, waiting on it if dead.
1774 * @param proc pointer to process structure
1775 * @param type status type
1776 * @param code return code/signal number
1777 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
1780 GNUNET_OS_process_wait_status(struct GNUNET_OS_Process *proc,
1781 enum GNUNET_OS_ProcessStatusType *type,
1782 unsigned long *code)
1784 return process_status(proc, type, code, 0);
1789 * Wait for a process to terminate. The return code is discarded.
1790 * You must not use #GNUNET_OS_process_status() on the same process
1791 * after calling this function! This function is blocking and should
1792 * thus only be used if the child process is known to have terminated
1793 * or to terminate very soon.
1795 * @param proc pointer to process structure
1796 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1799 GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
1802 pid_t pid = proc->pid;
1805 while ((pid != (ret = waitpid(pid, NULL, 0))) && (EINTR == errno))
1809 LOG_STRERROR(GNUNET_ERROR_TYPE_WARNING, "waitpid");
1810 return GNUNET_SYSERR;
1819 LOG(GNUNET_ERROR_TYPE_WARNING,
1820 "Invalid process information {%d, %08X}\n",
1823 return GNUNET_SYSERR;
1826 h = GetCurrentProcess();
1828 if (WAIT_OBJECT_0 != WaitForSingleObject(h, INFINITE))
1830 SetErrnoFromWinError(GetLastError());
1831 return GNUNET_SYSERR;
1839 * Handle to a command.
1841 struct GNUNET_OS_CommandHandle {
1845 struct GNUNET_OS_Process *eip;
1848 * Handle to the output pipe.
1850 struct GNUNET_DISK_PipeHandle *opipe;
1853 * Read-end of output pipe.
1855 const struct GNUNET_DISK_FileHandle *r;
1858 * Function to call on each line of output.
1860 GNUNET_OS_LineProcessor proc;
1863 * Closure for @e proc.
1868 * Buffer for the output.
1873 * Task reading from pipe.
1875 struct GNUNET_SCHEDULER_Task *rtask;
1880 struct GNUNET_TIME_Absolute timeout;
1883 * Current read offset in buf.
1890 * Stop/kill a command. Must ONLY be called either from
1891 * the callback after 'NULL' was passed for 'line' *OR*
1892 * from an independent task (not within the line processor).
1894 * @param cmd handle to the process
1897 GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
1899 if (NULL != cmd->proc)
1901 GNUNET_assert(NULL != cmd->rtask);
1902 GNUNET_SCHEDULER_cancel(cmd->rtask);
1904 (void)GNUNET_OS_process_kill(cmd->eip, SIGKILL);
1905 GNUNET_break(GNUNET_OK == GNUNET_OS_process_wait(cmd->eip));
1906 GNUNET_OS_process_destroy(cmd->eip);
1907 GNUNET_DISK_pipe_close(cmd->opipe);
1913 * Read from the process and call the line processor.
1915 * @param cls the `struct GNUNET_OS_CommandHandle *`
1920 struct GNUNET_OS_CommandHandle *cmd = cls;
1921 const struct GNUNET_SCHEDULER_TaskContext *tc;
1922 GNUNET_OS_LineProcessor proc;
1927 tc = GNUNET_SCHEDULER_get_task_context();
1928 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset(tc->read_ready, cmd->r))
1933 proc(cmd->proc_cls, NULL);
1936 ret = GNUNET_DISK_file_read(cmd->r,
1937 &cmd->buf[cmd->off],
1938 sizeof(cmd->buf) - cmd->off);
1941 if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1943 cmd->buf[cmd->off] = '\0';
1944 cmd->proc(cmd->proc_cls, cmd->buf);
1948 proc(cmd->proc_cls, NULL);
1951 end = memchr(&cmd->buf[cmd->off], '\n', ret);
1956 cmd->proc(cmd->proc_cls, cmd->buf);
1957 memmove(cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1958 cmd->off -= (end + 1 - cmd->buf);
1959 end = memchr(cmd->buf, '\n', cmd->off);
1962 GNUNET_SCHEDULER_add_read_file(GNUNET_TIME_absolute_get_remaining(
1971 * Run the given command line and call the given function
1972 * for each line of the output.
1974 * @param proc function to call for each line of the output
1975 * @param proc_cls closure for @a proc
1976 * @param timeout when to time out
1977 * @param binary command to run
1978 * @param ... arguments to command
1979 * @return NULL on error
1981 struct GNUNET_OS_CommandHandle *
1982 GNUNET_OS_command_run(GNUNET_OS_LineProcessor proc,
1984 struct GNUNET_TIME_Relative timeout,
1988 struct GNUNET_OS_CommandHandle *cmd;
1989 struct GNUNET_OS_Process *eip;
1990 struct GNUNET_DISK_PipeHandle *opipe;
1993 opipe = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1996 va_start(ap, binary);
1997 /* redirect stdout, don't inherit stderr/stdin */
1999 GNUNET_OS_start_process_va(GNUNET_NO, 0, NULL, opipe, NULL, binary, ap);
2003 GNUNET_DISK_pipe_close(opipe);
2006 GNUNET_DISK_pipe_close_end(opipe, GNUNET_DISK_PIPE_END_WRITE);
2007 cmd = GNUNET_new(struct GNUNET_OS_CommandHandle);
2008 cmd->timeout = GNUNET_TIME_relative_to_absolute(timeout);
2012 cmd->proc_cls = proc_cls;
2013 cmd->r = GNUNET_DISK_pipe_handle(opipe, GNUNET_DISK_PIPE_END_READ);
2014 cmd->rtask = GNUNET_SCHEDULER_add_read_file(timeout, cmd->r, &cmd_read, cmd);
2019 /* end of os_priority.c */