I'd like to write a function that would take a command array, one input stream and two output streams and execute that command using the given streams as input, output and error output respectively. (Returns the return value of the command or -1). This should be implemented using unix system calls.
int exec_with_streams (const std::vector<std::string>& args, std::istream& in, std::ostream& out, std::ostream& err)
Question: how can I implement it?
As for the fork, exec and the outputs it is more or less obvious what to do but the problem comes with the input since we don't know when and how much the process wants to read. So here is a not-working example, where we need to adjust the reading part. (The code is adapted from https://github.com/ericcurtin/execxx/blob/master/execxx.hpp)
int exec_with_streams (const std::vector<std::string>& args,
std::istream& in,
std::ostream& out,
std::ostream& err)
{
int in_fds[2];
pipe(in_fds);
int out_fds[2];
pipe(out_fds);
int err_fds[2];
pipe(err_fds);
const pid_t pid = fork();
if (pid == 0) {
close(in_fds[1]);
close(out_fds[0]);
close(err_fds[0]);
dup2(in_fds[0], 0);
dup2(out_fds[1], 1);
dup2(err_fds[1], 2);
std::vector<char*> vc(args.size() + 1, nullptr);
for (size_t i = 0; i < args.size(); ++i) {
vc[i] = const_cast<char*>(args[i].c_str());
}
int ret = execvp(vc[0], &vc[0]);
exit(ret);
}
close(in_fds[0]);
close(out_fds[1]);
close(err_fds[1]);
const int buf_size = 4096;
char buffer[buf_size];
char inbuf[buf_size];
ssize_t in_b = 0;
ssize_t out_b = 0;
ssize_t err_b = 0;
do {
out_b = read(out_fds[0], buffer, buf_size);
if (out_b > 0) {
out.write(buffer, out_b);
}
err_b = read(err_fds[0], buffer, buf_size);
if (err_b > 0) {
out.write(buffer, err_b);
}
in_b = in.read(inbuf, buf_size).gcount();
if (in_b > 0) {
in_b = write(in_fds[1], inbuf, in_b);
}
} while (in_b != 0 || out_b != 0 || err_b !=0);
close(in_fds[1]);
close(out_fds[0]);
close(err_fds[0]);
int r, status;
do {
r = waitpid(pid, &status, 0);
} while (r == -1);
return status;
}
Thanks a lot in advance
Update - some more clarification: I need a way to check if the child process created by fork() is paused and waits for input. If so the parent could in turn extract characters from the input stream and feed it into the child via the pipe.