Untitled
unknown
c_cpp
a year ago
5.0 kB
11
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