aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-20 14:56:23 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-21 14:58:17 +0100
commit6c8ec28a8dd13cdb76f2a367bd54ca1302894bec (patch)
tree790c09f63104a2aadff8166a21b714d722786665
parentb17e35dcdbd14c3a73511b19c0e82cd52d212499 (diff)
downloadpaludis-6c8ec28a8dd13cdb76f2a367bd54ca1302894bec.tar.gz
paludis-6c8ec28a8dd13cdb76f2a367bd54ca1302894bec.tar.xz
Process::capture_output_to_fd
-rw-r--r--paludis/util/process.cc85
-rw-r--r--paludis/util/process.hh4
-rw-r--r--paludis/util/process_TEST.cc30
3 files changed, 117 insertions, 2 deletions
diff --git a/paludis/util/process.cc b/paludis/util/process.cc
index ced2c2b..abcef46 100644
--- a/paludis/util/process.cc
+++ b/paludis/util/process.cc
@@ -96,6 +96,20 @@ ProcessCommand::exec()
throw ProcessError("execvp failed");
}
+void
+ProcessCommand::echo_command_to(std::ostream & s)
+{
+ for (auto v_begin(_imp->args.begin()), v(v_begin), v_end(_imp->args.end()) ;
+ v != v_end ; ++v)
+ {
+ if (v != v_begin)
+ s << " ";
+ s << *v;
+ }
+
+ s << std::endl;
+}
+
namespace paludis
{
struct RunningProcessThread
@@ -108,13 +122,17 @@ namespace paludis
std::ostream * capture_stderr;
std::unique_ptr<Channel> capture_stderr_pipe;
+ std::ostream * capture_output_to_fd;
+ std::unique_ptr<Pipe> capture_output_to_fd_pipe;
+
/* must be last, so the thread gets join()ed before its FDs vanish */
std::unique_ptr<Thread> thread;
RunningProcessThread() :
ctl_pipe(true),
capture_stdout(0),
- capture_stderr(0)
+ capture_stderr(0),
+ capture_output_to_fd(0)
{
}
@@ -150,6 +168,12 @@ RunningProcessThread::thread_func()
max_fd = std::max(max_fd, capture_stderr_pipe->read_fd());
}
+ if (capture_output_to_fd)
+ {
+ FD_SET(capture_output_to_fd_pipe->read_fd(), &read_fds);
+ max_fd = std::max(max_fd, capture_output_to_fd_pipe->read_fd());
+ }
+
int retval(::pselect(max_fd + 1, &read_fds, &write_fds, 0, 0, 0));
if (-1 == retval)
throw ProcessError("pselect() failed");
@@ -177,6 +201,16 @@ RunningProcessThread::thread_func()
done_anything = true;
}
+ if (capture_output_to_fd_pipe && FD_ISSET(capture_output_to_fd_pipe->read_fd(), &read_fds))
+ {
+ int n(::read(capture_output_to_fd_pipe->read_fd(), &buf, sizeof(buf)));
+ if (-1 == n)
+ throw ProcessError("read() capture_output_to_fd_pipe read_fd failed");
+ else if (0 != n)
+ capture_output_to_fd->write(buf, n);
+ done_anything = true;
+ }
+
if (done_anything)
continue;
@@ -210,11 +244,15 @@ namespace paludis
bool use_ptys;
std::ostream * capture_stdout;
std::ostream * capture_stderr;
+ std::ostream * capture_output_to_fd_stream;
+ int capture_output_to_fd_fd;
+ std::string capture_output_to_fd_env_var;
std::map<std::string, std::string> setenvs;
std::string chdir;
uid_t setuid;
gid_t setgid;
+ std::ostream * echo_command_to;
Imp(ProcessCommand && c) :
command(std::move(c)),
@@ -222,8 +260,11 @@ namespace paludis
use_ptys(false),
capture_stdout(0),
capture_stderr(0),
+ capture_output_to_fd_stream(0),
+ capture_output_to_fd_fd(-1),
setuid(getuid()),
- setgid(getgid())
+ setgid(getgid()),
+ echo_command_to(0)
{
}
};
@@ -241,6 +282,9 @@ Process::~Process()
RunningProcessHandle
Process::run()
{
+ if (_imp->echo_command_to)
+ _imp->command.echo_command_to(*_imp->echo_command_to);
+
std::unique_ptr<RunningProcessThread> thread;
if (_imp->need_thread)
{
@@ -263,6 +307,12 @@ Process::run()
else
thread->capture_stderr_pipe.reset(new Pipe(true));
}
+
+ if (_imp->capture_output_to_fd_stream)
+ {
+ thread->capture_output_to_fd = _imp->capture_output_to_fd_stream;
+ thread->capture_output_to_fd_pipe.reset(new Pipe(true));
+ }
}
pid_t child(fork());
@@ -284,6 +334,20 @@ Process::run()
throw ProcessError("dup2() failed");
}
+ if (thread && thread->capture_output_to_fd_pipe)
+ {
+ int fd(_imp->capture_output_to_fd_fd);
+ if (-1 == fd)
+ fd = ::dup(thread->capture_output_to_fd_pipe->write_fd());
+ else
+ fd = ::dup2(thread->capture_output_to_fd_pipe->write_fd(), fd);
+
+ if (-1 == fd)
+ throw ProcessError("dup failed");
+ else if (! _imp->capture_output_to_fd_env_var.empty())
+ ::setenv(_imp->capture_output_to_fd_env_var.c_str(), stringify(fd).c_str(), 1);
+ }
+
for (auto m(_imp->setenvs.begin()), m_end(_imp->setenvs.end()) ;
m != m_end ; ++m)
::setenv(m->first.c_str(), m->second.c_str(), 1);
@@ -347,6 +411,16 @@ Process::capture_stderr(std::ostream & s)
}
Process &
+Process::capture_output_to_fd(std::ostream & s, int fd_or_minus_one, const std::string & env_var_with_fd)
+{
+ _imp->need_thread = true;
+ _imp->capture_output_to_fd_stream = &s;
+ _imp->capture_output_to_fd_fd = fd_or_minus_one;
+ _imp->capture_output_to_fd_env_var = env_var_with_fd;
+ return *this;
+}
+
+Process &
Process::setenv(const std::string & a, const std::string & b)
{
_imp->setenvs.insert(std::make_pair(a, b)).first->second = b;
@@ -375,6 +449,13 @@ Process::setuid_setgid(uid_t u, gid_t g)
return *this;
}
+Process &
+Process::echo_command_to(std::ostream & s)
+{
+ _imp->echo_command_to = &s;
+ return *this;
+}
+
namespace paludis
{
template <>
diff --git a/paludis/util/process.hh b/paludis/util/process.hh
index 0cc62e8..3865911 100644
--- a/paludis/util/process.hh
+++ b/paludis/util/process.hh
@@ -58,6 +58,8 @@ namespace paludis
ProcessCommand(const ProcessCommand &) = delete;
ProcessCommand & operator= (const ProcessCommand &) = delete;
+ void echo_command_to(std::ostream &);
+
void exec() PALUDIS_ATTRIBUTE((noreturn));
};
@@ -75,10 +77,12 @@ namespace paludis
Process & capture_stdout(std::ostream &);
Process & capture_stderr(std::ostream &);
+ Process & capture_output_to_fd(std::ostream &, int fd_or_minus_one, const std::string & env_var_with_fd);
Process & setenv(const std::string &, const std::string &);
Process & chdir(const FSEntry &);
Process & use_ptys();
Process & setuid_setgid(uid_t, gid_t);
+ Process & echo_command_to(std::ostream &);
};
class PALUDIS_VISIBLE RunningProcessHandle :
diff --git a/paludis/util/process_TEST.cc b/paludis/util/process_TEST.cc
index a7361f3..fc57c19 100644
--- a/paludis/util/process_TEST.cc
+++ b/paludis/util/process_TEST.cc
@@ -232,5 +232,35 @@ namespace test_cases
}
}
} test_setuid;
+
+ struct GrabFDTest : TestCase
+ {
+ GrabFDTest() : TestCase("grab fd") { }
+
+ void run()
+ {
+ std::stringstream fd_stream;
+ Process echo_process(ProcessCommand({"sh", "-c", "echo monkey 1>&$MAGIC_FD"}));
+ echo_process.capture_output_to_fd(fd_stream, -1, "MAGIC_FD");
+
+ TEST_CHECK_EQUAL(echo_process.run().wait(), 0);
+ TEST_CHECK_EQUAL(fd_stream.str(), "monkey\n");
+ }
+ } test_grab_fd;
+
+ struct GrabFDFixedTest : TestCase
+ {
+ GrabFDFixedTest() : TestCase("grab fd fixed") { }
+
+ void run()
+ {
+ std::stringstream fd_stream;
+ Process echo_process(ProcessCommand({"sh", "-c", "echo monkey 1>&5"}));
+ echo_process.capture_output_to_fd(fd_stream, 5, "");
+
+ TEST_CHECK_EQUAL(echo_process.run().wait(), 0);
+ TEST_CHECK_EQUAL(fd_stream.str(), "monkey\n");
+ }
+ } test_grab_fd_fixed;
}