Untitled
unknown
c_cpp
a year ago
5.0 kB
6
Indexable
class PipeExec { public: enum Mode { None = 0, Stdout = 1 << 0, Stderr = 1 << 1, Stdin = 1 << 2, RedirectErrToOut = 1 << 3, }; typedef std::function<void()> hook_t; public: ~PipeExec() { // Ensure the process is no longer running before cleanup if (m_pid > 0) { wait(); } closePipes(); } bool exec(const char *argv[], int mode) { assert(m_stdout_pipe[0] == -1 && m_stdout_pipe[1] == -1); assert(m_stderr_pipe[0] == -1 && m_stderr_pipe[1] == -1); assert(m_stdin_pipe[0] == -1 && m_stdin_pipe[1] == -1); if (mode & Mode::Stdout && pipe(m_stdout_pipe) == -1) { perror("pipe"); return false; } if (mode & Mode::Stderr && !(mode & RedirectErrToOut) && pipe(m_stderr_pipe) == -1) { perror("pipe"); return false; } if (mode & Mode::Stdin && pipe(m_stdin_pipe) == -1) { perror("pipe"); return false; } if ((m_pid = fork()) == -1) { perror("fork"); return false; } if (m_pid == 0) { setupChildPipes(mode); if (m_child_hook) { m_child_hook(); } execvpe(argv[0], const_cast<char* const*>(argv), m_envp ? m_envp : environ); perror("execvpe"); _exit(127); } else { closeParentPipes(); } return true; } int wait() { if (m_pid < 1) return -1; int ret; do { ret = waitpid(m_pid, &m_status, 0); } while (ret == -1 && errno == EINTR); if (ret == -1) { perror("waitpid failed"); m_status = -1; } m_pid = -1; closePipes(); return m_status; } int exitcode() const { return WIFEXITED(m_status) ? WEXITSTATUS(m_status) : 255; } int stdin_pipe() const { return m_stdin_pipe[1]; } int stdout_pipe() const { return m_stdout_pipe[0]; } int stderr_pipe() const { return m_stderr_pipe[0]; } void close_pipes(int mode) { if (mode & Mode::Stdin) { closePipe(m_stdin_pipe); } if (mode & Mode::Stdout || mode & RedirectErrToOut) { closePipe(m_stdin_pipe); } if (mode & Mode::Stderr) { closePipe(m_stdin_pipe); } } void set_environ(const char *envp[]) { m_envp = const_cast<char* const*>(envp); } void set_child_hook(const hook_t &cb) { m_child_hook = cb; } private: void setupChildPipes(int mode) { if (mode & Mode::Stdout) { close(m_stdout_pipe[0]); dup2(m_stdout_pipe[1], STDOUT_FILENO); close(m_stdout_pipe[1]); } if (mode & Mode::RedirectErrToOut) { dup2(STDOUT_FILENO, STDERR_FILENO); } else if (mode & Mode::Stderr) { close(m_stderr_pipe[0]); dup2(m_stderr_pipe[1], STDERR_FILENO); close(m_stderr_pipe[1]); } if (mode & Mode::Stdin) { close(m_stdin_pipe[1]); dup2(m_stdin_pipe[0], STDIN_FILENO); close(m_stdin_pipe[0]); } } void closeParentPipes() { close(m_stdin_pipe[0]); close(m_stderr_pipe[1]); close(m_stdout_pipe[1]); } void closePipes() { closePipe(m_stdin_pipe); closePipe(m_stdout_pipe); closePipe(m_stderr_pipe); } void closePipe(int (&pipe)[2]) { if (pipe[0] != -1) close(pipe[0]); if (pipe[1] != -1) close(pipe[1]); pipe[0] = -1; pipe[1] = -1; } private: pid_t m_pid = -1; int m_status = -1; int m_stdin_pipe[2] = {-1, -1}; int m_stdout_pipe[2] = {-1, -1}; int m_stderr_pipe[2] = {-1, -1}; char * const *m_envp = nullptr; hook_t m_child_hook; }; int main() { const char *argv[] = { "/bin/cat", "asd", NULL }; const char *env[] = { "Sooqua=1", NULL }; PipeExec pexec; //pexec.set_environ(env); pexec.set_child_hook([]() { printf("I'm in child process!\n"); }); pexec.exec(argv, PipeExec::Mode::Stdin | PipeExec::Mode::RedirectErrToOut); dprintf(pexec.stdin_pipe(), "Hello!\n"); pexec.close_pipes(PipeExec::Mode::Stdin); write(1, "Out: \n", 6); while (1) { char tmp[128]; int ret; if ((ret = read(pexec.stdout_pipe(), tmp, 128)) < 1) break; tmp[ret] = 0; write(1, tmp, ret); } write(2, "Err: \n", 6); while (1) { char tmp[128]; int ret; if ((ret = read(pexec.stderr_pipe(), tmp, 128)) < 1) break; tmp[ret] = 0; write(2, tmp, ret); } pexec.wait(); printf("retcode: %d\n", pexec.exitcode()); return 0; }
Editor is loading...
Leave a Comment