13 #ifndef __PROCESS_POSIX_SUBPROCESS_HPP__ 14 #define __PROCESS_POSIX_SUBPROCESS_HPP__ 17 #include <sys/prctl.h> 18 #include <sys/syscall.h> 20 #include <sys/types.h> 24 #include <glog/logging.h> 50 static void close(std::initializer_list<int_fd> fds);
59 #if defined(__linux__) && defined(SYS_getdents64) 62 static int convertStringToInt(
const char *
name)
65 while (*name >=
'0' && *name <=
'9') {
66 num = num * 10 + (*name -
'0');
77 #endif // __linux__ && SYS_getdents64 84 static void handleWhitelistFds(
const std::vector<int_fd>& whitelist_fds)
90 #if defined(__linux__) && defined(SYS_getdents64) 91 int fdDir =
::open(
"/dev/fd", O_RDONLY);
96 struct linux_dirent64 {
99 unsigned short d_reclen;
100 unsigned char d_type;
108 bytes = ::syscall(SYS_getdents64, fdDir, buffer,
sizeof(buffer));
117 struct linux_dirent64 *entry;
118 for (
int offset = 0; offset < bytes; offset += entry->d_reclen) {
119 entry =
reinterpret_cast<struct linux_dirent64 *
>(buffer + offset);
120 int_fd fd = convertStringToInt(entry->d_name);
127 foreach (
int_fd whitelist_fd, whitelist_fds) {
128 if (whitelist_fd == fd) {
135 int flags = ::fcntl(fd, F_GETFD);
140 "Failed to get file descriptor flags: " +
os::strerror(errno));
144 if ((flags & FD_CLOEXEC) == 0){
153 #endif // __linux__ && SYS_getdents64 155 foreach (
int_fd fd, whitelist_fds) {
156 int flags = ::fcntl(fd, F_GETFD);
161 if (::fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) == -1) {
170 pid_t pid = ::fork();
173 }
else if (pid == 0) {
200 foreach (
int fd, fds) {
217 const std::string&
path,
223 const std::vector<int_fd>& whitelist_fds,
226 const std::vector<Subprocess::ChildHook>& child_hooks)
262 ::close(stdinfds.
read);
268 ::close(stdoutfds.
write);
275 ::close(stderrfds.
write);
283 while ((length = ::
read(pipes[0], &dummy,
sizeof(dummy))) == -1 &&
286 if (length !=
sizeof(dummy)) {
287 ABORT(
"Failed to synchronize with parent");
300 ABORT(
"Failed to execute Subprocess::ChildHook: " + callback.
error());
304 handleWhitelistFds(whitelist_fds);
309 errno,
"Failed to os::execvpe on path '%s': %d", path.c_str(), errno);
314 const std::string&
path,
315 std::vector<std::string> argv,
317 const Option<lambda::function<
318 pid_t(
const lambda::function<
int()>&)>>& _clone,
319 const std::vector<Subprocess::ParentHook>& parent_hooks,
320 const std::vector<Subprocess::ChildHook>& child_hooks,
324 const std::vector<int_fd>& whitelist_fds)
329 char** _argv =
new char*[argv.size() + 1];
330 for (
size_t i = 0; i < argv.size(); i++) {
331 _argv[i] = (
char*) argv[i].c_str();
333 _argv[argv.size()] =
nullptr;
346 const std::string& key,
348 std::string entry = key +
"=" + value;
349 envp[
index] =
new char[entry.size() + 1];
350 strncpy(envp[index], entry.c_str(), entry.size() + 1);
354 envp[
index] =
nullptr;
359 lambda::function<pid_t(const lambda::function<int()>&)>
clone =
364 std::array<int, 2> pipes;
365 const bool blocking = !parent_hooks.empty();
399 delete[] envp[
index];
408 internal::close(stdinfds, stdoutfds, stderrfds);
420 internal::close({stdinfds.
read, stdoutfds.
write, stderrfds.
write});
433 <<
"Failed to execute Subprocess::ParentHook in parent for child '" 434 << pid <<
"': " << parentSetup.
error();
442 "Failed to execute Subprocess::ParentHook in parent for child '" +
451 while ((length = ::
write(pipes[1], &dummy,
sizeof(dummy))) == -1 &&
456 if (length !=
sizeof(dummy)) {
460 return Error(
"Failed to synchronize child process");
470 #endif // __PROCESS_POSIX_SUBPROCESS_HPP__ Try< Nothing > dup2(int oldFd, int newFd)
Definition: os.hpp:413
SSIZE_T ssize_t
Definition: windows.hpp:186
std::string strerror(int errno_)
A thread-safe version of strerror.
Definition: strerror.hpp:30
Definition: nothing.hpp:16
Try< std::array< int, 2 > > pipe()
Definition: pipe.hpp:33
Definition: errorbase.hpp:36
Definition: option.hpp:29
Try< pid_t > clone(pid_t target, int nstypes, const lambda::function< int()> &f, int flags)
Performs an os::clone after entering a set of namespaces for the specified target process...
#define ABORT(...)
Definition: abort.hpp:40
T getOrElse(U &&u) const &
Definition: option.hpp:133
Subprocess::IO::OutputFileDescriptors OutputFileDescriptors
Definition: subprocess.hpp:339
T & get()&
Definition: try.hpp:80
const mode_t SIGKILL
Definition: windows.hpp:335
A ChildHook can be passed to a subprocess call.
Definition: subprocess.hpp:191
Definition: hashset.hpp:53
Try< int_fd > open(const std::string &path, int oflag, mode_t mode=0)
Definition: open.hpp:35
For output file descriptors a child writes to the write file descriptor and a parent may read from th...
Definition: subprocess.hpp:89
int childMain(const std::string &path, char **argv, char **envp, const InputFileDescriptors &stdinfds, const OutputFileDescriptors &stdoutfds, const OutputFileDescriptors &stderrfds, const std::vector< int_fd > &whitelist_fds, bool blocking, int pipes[2], const std::vector< Subprocess::ChildHook > &child_hooks)
Definition: subprocess.hpp:216
pid_t defaultClone(const lambda::function< int()> &func)
Definition: subprocess.hpp:168
Definition: errorbase.hpp:50
#define STDERR_FILENO
Definition: windows.hpp:155
Try< Nothing > cloexec(const InputFileDescriptors &stdinfds, const OutputFileDescriptors &stdoutfds, const OutputFileDescriptors &stderrfds)
Definition: subprocess.hpp:186
bool isSome() const
Definition: option.hpp:116
Subprocess::IO::InputFileDescriptors InputFileDescriptors
Definition: subprocess.hpp:338
Environment * environment
DWORD pid_t
Definition: windows.hpp:181
Result< int > index(const std::string &link)
#define CHECK_SOME(expression)
Definition: check.hpp:50
#define STDOUT_FILENO
Definition: windows.hpp:154
int_fd write
Definition: subprocess.hpp:92
Try< Nothing > close(int fd)
Definition: close.hpp:24
Try< Nothing > cloexec(int fd)
Definition: fcntl.hpp:27
const T & get() const &
Definition: option.hpp:119
#define foreachpair(KEY, VALUE, ELEMS)
Definition: foreach.hpp:51
#define STDIN_FILENO
Definition: windows.hpp:153
static Try error(const E &e)
Definition: try.hpp:43
#define UNREACHABLE()
Definition: unreachable.hpp:22
const lambda::function< Try< Nothing >pid_t)> parent_setup
The callback that must be specified for execution after the child has been cloned, but before it starts executing the new process.
Definition: subprocess.hpp:164
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
Result< Credentials > read(const Path &path)
Definition: credentials.hpp:35
std::string error(const std::string &msg, uint32_t code)
Definition: executor.hpp:48
Protocol< WriteRequest, WriteResponse > write
Option< int_fd > read
Definition: subprocess.hpp:91
Try< Nothing > kill(const std::string &hierarchy, const std::string &cgroup, int signal)
Try< Nothing > bind(int_fd s, const Address &address)
Definition: network.hpp:46
A hook can be passed to a subprocess call.
Definition: subprocess.hpp:153
int int_fd
Definition: int_fd.hpp:35
std::string stringify(int flags)
int execvpe(const char *file, char **argv, char **envp)
Definition: exec.hpp:64
#define SAFE_EXIT(status, fmt,...)
Definition: exit.hpp:42
constexpr const char * name
Definition: shell.hpp:41
Try< pid_t > cloneChild(const std::string &path, std::vector< std::string > argv, const Option< std::map< std::string, std::string >> &environment, const Option< lambda::function< pid_t(const lambda::function< int()> &)>> &_clone, const std::vector< Subprocess::ParentHook > &parent_hooks, const std::vector< Subprocess::ChildHook > &child_hooks, const InputFileDescriptors stdinfds, const OutputFileDescriptors stdoutfds, const OutputFileDescriptors stderrfds, const std::vector< int_fd > &whitelist_fds)
Definition: subprocess.hpp:313
char ** environment()
Definition: environment.hpp:66