aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-07-25 15:30:25 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-07-25 15:30:25 +0000
commit64ae2fa8ece3b69fd0bd5865b28344f8dd89af5f (patch)
treec48f3212762aec907e71c1b2561114b9eb69e0a2
parentfe9810cece507e934cbf82975442f6a96cf7e797 (diff)
downloadpaludis-64ae2fa8ece3b69fd0bd5865b28344f8dd89af5f.tar.gz
paludis-64ae2fa8ece3b69fd0bd5865b28344f8dd89af5f.tar.xz
Allow stderr for PStream commands to be redirected. Make the message window auto scroll and display PStream stderr output.
-rw-r--r--paludis/util/pstream.cc78
-rw-r--r--paludis/util/pstream.hh27
-rw-r--r--src/gtkpaludis/message_window.cc27
-rw-r--r--src/gtkpaludis/message_window.hh1
4 files changed, 114 insertions, 19 deletions
diff --git a/paludis/util/pstream.cc b/paludis/util/pstream.cc
index 940b4d2..c292861 100644
--- a/paludis/util/pstream.cc
+++ b/paludis/util/pstream.cc
@@ -17,11 +17,15 @@
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <cstring>
-#include <errno.h>
#include <paludis/util/log.hh>
#include <paludis/util/pstream.hh>
+#include <cstring>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
/** \file
* Implementation for PStream.
*
@@ -38,9 +42,6 @@ PStreamError::PStreamError(const std::string & message) throw () :
PStreamInBuf::int_type
PStreamInBuf::underflow()
{
- if (0 == fd)
- return EOF;
-
if (gptr() < egptr())
return *gptr();
@@ -50,7 +51,7 @@ PStreamInBuf::underflow()
std::memmove(buffer + putback_size - num_putback,
gptr() - num_putback, num_putback);
- size_t n = fread(buffer + putback_size, 1, buffer_size - putback_size, fd);
+ ssize_t n = read(fd, buffer + putback_size, buffer_size - putback_size);
if (n <= 0)
return EOF;
@@ -60,16 +61,42 @@ PStreamInBuf::underflow()
return *gptr();
}
-PStreamInBuf::PStreamInBuf(const std::string & command) :
- _command(command),
- fd(popen(command.c_str(), "r"))
+PStreamInBuf::PStreamInBuf(const std::string & cmd) :
+ _command(cmd),
+ child(fork())
{
- Log::get_instance()->message(ll_debug, lc_no_context,
- "popen " + command + " -> " + stringify(fileno(fd)));
-
- if (0 == fd)
- throw PStreamError("popen('" + _command + "', 'r') failed: " +
- std::strerror(errno));
+ if (0 == child)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(stdout_pipe.write_fd()) + " 1");
+ if (-1 == dup2(stdout_pipe.write_fd(), 1))
+ throw PStreamError("dup2 failed");
+ close(stdout_pipe.read_fd());
+
+ if (-1 != PStream::stderr_fd)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(PStream::stderr_fd) + " 2");
+
+ if (-1 == dup2(PStream::stderr_fd, 2))
+ throw PStreamError("dup2 failed");
+
+ if (-1 != PStream::stderr_close_fd)
+ close(PStream::stderr_close_fd);
+ }
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + cmd);
+ execl("/bin/sh", "sh", "-c", cmd.c_str(), static_cast<char *>(0));
+ throw PStreamError("execl /bin/sh -c '" + cmd + "' failed:"
+ + stringify(strerror(errno)));
+ }
+ else if (-1 == child)
+ throw PStreamError("fork failed: " + stringify(strerror(errno)));
+ else
+ {
+ close(stdout_pipe.write_fd());
+ fd = stdout_pipe.read_fd();
+ }
setg(buffer + putback_size, buffer + putback_size, buffer + putback_size);
}
@@ -78,7 +105,8 @@ PStreamInBuf::~PStreamInBuf()
{
if (0 != fd)
{
- int fdn = fileno(fd), x = pclose(fd);
+ int fdn(fd), x;
+ waitpid(child, &x, 0);
Log::get_instance()->message(ll_debug, lc_no_context,
"pclose " + stringify(fdn) + " -> " + stringify(x));
}
@@ -89,11 +117,25 @@ PStreamInBuf::exit_status()
{
if (0 != fd)
{
- int fdn = fileno(fd);
- _exit_status = pclose(fd);
+ int fdn(fd);
+ waitpid(child, &_exit_status, 0);
fd = 0;
Log::get_instance()->message(ll_debug, lc_no_context,
"manual pclose " + stringify(fdn) + " -> " + stringify(_exit_status));
}
return _exit_status;
}
+
+void
+PStream::set_stderr_fd(const int fd, const int fd2)
+{
+ _stderr_fd = fd;
+ _stderr_close_fd = fd2;
+}
+
+int PStream::_stderr_fd(-1);
+const int & PStream::stderr_fd(_stderr_fd);
+
+int PStream::_stderr_close_fd(-1);
+const int & PStream::stderr_close_fd(_stderr_close_fd);
+
diff --git a/paludis/util/pstream.hh b/paludis/util/pstream.hh
index f6fe15d..8cd86ab 100644
--- a/paludis/util/pstream.hh
+++ b/paludis/util/pstream.hh
@@ -25,6 +25,7 @@
#include <limits>
#include <paludis/util/exception.hh>
#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/pipe.hh>
#include <streambuf>
#include <string>
@@ -70,15 +71,19 @@ namespace paludis
private InstantiationPolicy<PStreamInBuf, instantiation_method::NonCopyableTag>
{
private:
+ Pipe stdout_pipe;
+
const std::string _command;
int _exit_status;
+ pid_t child;
+
protected:
/**
* Our file descriptor.
*/
- FILE * fd;
+ int fd;
/**
* At most how many characters can we put back?
@@ -170,6 +175,10 @@ namespace paludis
protected pstream_internals::PStreamInBufBase,
public std::istream
{
+ private:
+ static int _stderr_fd;
+ static int _stderr_close_fd;
+
public:
///\name Basic operations
///\{
@@ -196,6 +205,22 @@ namespace paludis
{
return buf.exit_status();
}
+
+ /**
+ * Set a file descriptors to use for stderr and close on stderr
+ * (for all PStream instances).
+ */
+ static void set_stderr_fd(const int, const int);
+
+ /**
+ * File descriptor to use for stderr.
+ */
+ static const int & stderr_fd;
+
+ /**
+ * File descriptor to close for stderr.
+ */
+ static const int & stderr_close_fd;
};
}
diff --git a/src/gtkpaludis/message_window.cc b/src/gtkpaludis/message_window.cc
index f8dc2ef..61ab344 100644
--- a/src/gtkpaludis/message_window.cc
+++ b/src/gtkpaludis/message_window.cc
@@ -20,7 +20,9 @@
#include "message_window.hh"
#include <gtkmm/main.h>
#include <paludis/util/fd_output_stream.hh>
+#include <paludis/util/iterator.hh>
#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
#include <paludis/util/pipe.hh>
#include <paludis/util/system.hh>
#include <unistd.h>
@@ -39,9 +41,11 @@ namespace paludis
InternalCounted<Implementation<MessageWindow> >
{
Pipe log_pipe;
+ Pipe cmd_stderr_pipe;
MessageWindow * const owner;
Glib::RefPtr<Glib::IOChannel> log_connection;
+ Glib::RefPtr<Glib::IOChannel> cmd_stderr_connection;
FDOutputStream stream;
Implementation(MessageWindow * const o);
@@ -50,11 +54,17 @@ namespace paludis
Implementation<MessageWindow>::Implementation(MessageWindow * const o) :
owner(o),
log_connection(Glib::IOChannel::create_from_fd(log_pipe.read_fd())),
+ cmd_stderr_connection(Glib::IOChannel::create_from_fd(cmd_stderr_pipe.read_fd())),
stream(log_pipe.write_fd())
{
Glib::signal_io().connect(sigc::mem_fun(*owner, &MessageWindow::on_log_read),
log_pipe.read_fd(), Glib::IO_IN);
+ Glib::signal_io().connect(sigc::mem_fun(*owner, &MessageWindow::on_cmd_stderr_read),
+ cmd_stderr_pipe.read_fd(), Glib::IO_IN);
+
+ PStream::set_stderr_fd(cmd_stderr_pipe.write_fd(), cmd_stderr_pipe.read_fd());
+
Log::get_instance()->set_log_stream(&stream);
Log::get_instance()->message(ll_debug, lc_no_context, "Message window initialised");
}
@@ -78,7 +88,24 @@ MessageWindow::on_log_read(Glib::IOCondition io_condition)
Glib::ustring buf;
_imp->log_connection->read_line(buf);
+
+ get_buffer()->insert(get_buffer()->end(), buf);
+ scroll_to(get_buffer()->create_mark(get_buffer()->end()), 0.0, 0.0, 1.0);
+
+ return true;
+}
+
+bool
+MessageWindow::on_cmd_stderr_read(Glib::IOCondition io_condition)
+{
+ if (0 == io_condition & Glib::IO_IN)
+ return false;
+
+ Glib::ustring buf;
+ _imp->cmd_stderr_connection->read_line(buf);
+
get_buffer()->insert(get_buffer()->end(), buf);
+ scroll_to(get_buffer()->create_mark(get_buffer()->end()), 0.0, 0.0, 1.0);
return true;
}
diff --git a/src/gtkpaludis/message_window.hh b/src/gtkpaludis/message_window.hh
index 7540535..551146f 100644
--- a/src/gtkpaludis/message_window.hh
+++ b/src/gtkpaludis/message_window.hh
@@ -35,6 +35,7 @@ namespace paludis
virtual ~MessageWindow();
bool on_log_read(Glib::IOCondition);
+ bool on_cmd_stderr_read(Glib::IOCondition);
};
}