return errstr.str().c_str();
}
+class fd_buf : public std::streambuf {
+ int fd;
+public:
+ fd_buf (int fd) : fd(fd)
+ {}
+protected:
+ int_type overflow (int_type c) override {
+ if (c == EOF) return EOF;
+ char buf = c;
+ if (write (fd, &buf, 1) != 1) {
+ return EOF;
+ }
+ return c;
+ }
+ std::streamsize xsputn (const char* s, std::streamsize count) override {
+ return write(fd, s, count);
+ }
+};
+
int SubProcess::spawn() {
assert(!is_spawned());
assert(stdin_pipe_out_fd == -1);
if (opipe[OUT] != -1 && opipe[OUT] != STDOUT_FILENO) {
::dup2(opipe[OUT], STDOUT_FILENO);
close(opipe[OUT]);
+ static fd_buf buf(STDOUT_FILENO);
+ std::cout.rdbuf(&buf);
}
if (epipe[OUT] != -1 && epipe[OUT] != STDERR_FILENO) {
::dup2(epipe[OUT], STDERR_FILENO);
close(epipe[OUT]);
+ static fd_buf buf(STDERR_FILENO);
+ std::cerr.rdbuf(&buf);
}
int maxfd = sysconf(_SC_OPEN_MAX);
int ret = execvp(cmd.c_str(), (char * const *)&args[0]);
assert(ret == -1);
- std::ostringstream err;
- err << cmd << ": exec failed: " << cpp_strerror(errno) << "\n";
- write(STDERR_FILENO, err.str().c_str(), err.str().size());
+ std::cerr << cmd << ": exec failed: " << cpp_strerror(errno) << "\n";
_exit(EXIT_FAILURE);
}
}
sigset_t mask, oldmask;
- std::ostringstream err;
int pid;
// Restore default action for SIGTERM in case the parent process decided
// to ignore it.
if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
- err << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
// Because SIGCHLD is ignored by default, setup dummy handler for it,
// so we can mask it.
if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) {
- err << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
// Setup timeout handler.
if (signal(SIGALRM, timeout_sighandler) == SIG_ERR) {
- err << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": signal failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
// Block interesting signals.
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) {
- err << cmd << ": sigprocmask failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": sigprocmask failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
pid = fork();
if (pid == -1) {
- err << cmd << ": fork failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": fork failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
if (pid == 0) { // Child
// Restore old sigmask.
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) {
- err << cmd << ": sigprocmask failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": sigprocmask failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
(void)setpgid(0, 0); // Become process group leader.
for (;;) {
int signo;
if (sigwait(&mask, &signo) == -1) {
- err << cmd << ": sigwait failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": sigwait failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
switch (signo) {
case SIGCHLD:
int status;
if (waitpid(pid, &status, WNOHANG) == -1) {
- err << cmd << ": waitpid failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": waitpid failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
- write(STDERR_FILENO, err.str().c_str(), err.str().size());
if (WIFEXITED(status))
_exit(WEXITSTATUS(status));
if (WIFSIGNALED(status))
_exit(128 + WTERMSIG(status));
- err << cmd << ": unknown status returned\n";
+ std::cerr << cmd << ": unknown status returned\n";
goto fail_exit;
case SIGINT:
case SIGTERM:
// Pass SIGINT and SIGTERM, which are usually used to terminate
// a process, to the child.
if (::kill(pid, signo) == -1) {
- err << cmd << ": kill failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": kill failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
continue;
case SIGALRM:
- err << cmd << ": timed out (" << timeout << " sec)\n";
- write(STDERR_FILENO, err.str().c_str(), err.str().size());
+ std::cerr << cmd << ": timed out (" << timeout << " sec)\n";
if (::killpg(pid, sigkill) == -1) {
- err << cmd << ": kill failed: " << cpp_strerror(errno) << "\n";
+ std::cerr << cmd << ": kill failed: " << cpp_strerror(errno) << "\n";
goto fail_exit;
}
continue;
default:
- err << cmd << ": sigwait: invalid signal: " << signo << "\n";
+ std::cerr << cmd << ": sigwait: invalid signal: " << signo << "\n";
goto fail_exit;
}
}
fail_exit:
- write(STDERR_FILENO, err.str().c_str(), err.str().size());
_exit(EXIT_FAILURE);
}