aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-27 15:30:18 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-27 15:30:18 +0000
commit1bea8725f294a4b581bdba82902562e262b46eb6 (patch)
tree2ecf99be521bf4500931528eaa84420f2491d4d9
parentf51124da6d5dd1376c2c7963c59b7c63080bc5d3 (diff)
downloadpaludis-1bea8725f294a4b581bdba82902562e262b46eb6.tar.gz
paludis-1bea8725f294a4b581bdba82902562e262b46eb6.tar.xz
Don't use Log after a fork(). Fixes: ticket:326
-rw-r--r--paludis/util/pstream.cc124
-rw-r--r--paludis/util/system.cc139
-rw-r--r--paludis/util/system_TEST.cc47
3 files changed, 192 insertions, 118 deletions
diff --git a/paludis/util/pstream.cc b/paludis/util/pstream.cc
index 20d97fb..3f7092a 100644
--- a/paludis/util/pstream.cc
+++ b/paludis/util/pstream.cc
@@ -23,6 +23,7 @@
#include <libwrapiter/libwrapiter_forward_iterator.hh>
#include <cstring>
+#include <iostream>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/types.h>
@@ -71,76 +72,87 @@ PStreamInBuf::PStreamInBuf(const Command & cmd) :
{
Context context("When running command '" + stringify(cmd.command()) + "' asynchronously:");
- if (0 == child)
- {
- std::string extras;
+ std::string extras;
- if (! cmd.chdir().empty())
- {
- if (-1 == chdir(cmd.chdir().c_str()))
- throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
- extras.append(" [chdir " + cmd.chdir() + "]");
- }
+ if (! cmd.chdir().empty())
+ extras.append(" [chdir " + cmd.chdir() + "]");
- for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
- {
- setenv(s->first.c_str(), s->second.c_str(), 1);
- extras.append(" [setenv " + s->first + "=" + s->second + "]");
- }
+ for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
+ extras.append(" [setenv " + s->first + "=" + s->second + "]");
+
+ if (cmd.gid() && *cmd.gid() != getgid())
+ extras.append(" [setgid " + stringify(*cmd.gid()) + "]");
+
+ if (cmd.uid() && *cmd.uid() != getuid())
+ extras.append(" [setuid " + stringify(*cmd.uid()) + "]");
+
+ std::string c(cmd.command());
+
+ if ((! cmd.stdout_prefix().empty()) || (! cmd.stderr_prefix().empty()))
+ c = getenv_with_default("PALUDIS_OUTPUTWRAPPER_DIR", LIBEXECDIR "/paludis/utils") + "/outputwrapper --stdout-prefix '"
+ + cmd.stdout_prefix() + "' --stderr-prefix '" + cmd.stderr_prefix() + "' "
+ + (cmd.prefix_discard_blank_output() ? " --discard-blank-output " : "")
+ + (cmd.prefix_blank_lines() ? " --wrap-blanks " : "")
+ + " -- " + c;
- if (-1 == dup2(stdout_pipe.write_fd(), 1))
- throw PStreamError("dup2 failed");
- close(stdout_pipe.read_fd());
+ cmd.echo_to_stderr();
+ Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + c + " " + extras);
- if (-1 != PStream::stderr_fd)
+ if (0 == child)
+ {
+ try
{
- Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
- stringify(PStream::stderr_fd) + " 2");
+ if (! cmd.chdir().empty())
+ if (-1 == chdir(cmd.chdir().c_str()))
+ throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
+
+ for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
+ setenv(s->first.c_str(), s->second.c_str(), 1);
- if (-1 == dup2(PStream::stderr_fd, 2))
+ if (-1 == dup2(stdout_pipe.write_fd(), 1))
throw PStreamError("dup2 failed");
+ close(stdout_pipe.read_fd());
- if (-1 != PStream::stderr_close_fd)
+ if (-1 != PStream::stderr_fd)
+ {
+ if (-1 == dup2(PStream::stderr_fd, 2))
+ throw PStreamError("dup2 failed");
+
+ if (-1 != PStream::stderr_close_fd)
close(PStream::stderr_close_fd);
+ }
+
+ if (cmd.gid() && *cmd.gid() != getgid())
+ {
+ gid_t g(*cmd.gid());
+
+ if (0 != ::setgid(*cmd.gid()))
+ std::cerr << "setgid(" << *cmd.gid() << ") failed for exec of '" << c << "': "
+ << strerror(errno) << std::endl;
+ else if (0 != ::setgroups(1, &g))
+ std::cerr << "setgroups failed for exec of '" << c << "': " << strerror(errno) << std::endl;
+ }
+
+ if (cmd.uid() && *cmd.uid() != getuid())
+ if (0 != ::setuid(*cmd.uid()))
+ std::cerr << "setuid(" << *cmd.uid() << ") failed for exec of '" << c << "': "
+ << strerror(errno) << std::endl;
+
+ execl("/bin/sh", "sh", "-c", c.c_str(), static_cast<char *>(0));
+ throw PStreamError("execl /bin/sh -c '" + c + "' failed:"
+ + stringify(strerror(errno)));
}
-
- if (cmd.gid() && *cmd.gid() != getgid())
+ catch (const Exception & e)
{
- gid_t g(*cmd.gid());
-
- if (0 != ::setgid(*cmd.gid()))
- Log::get_instance()->message(ll_warning, lc_context, "setgid("
- + stringify(*cmd.gid()) + ") failed: " + stringify(strerror(errno)));
- else if (0 != ::setgroups(1, &g))
- Log::get_instance()->message(ll_warning, lc_context, "setgroups failed: "
- + stringify(strerror(errno)));
-
- extras.append(" [setgid " + stringify(*cmd.gid()) + "]");
+ std::cerr << "exec of '" << c << "' failed due to exception '" << e.message()
+ << "' (" << e.what() << ")" << std::endl;
+ exit(123);
}
-
- if (cmd.uid() && *cmd.uid() != getuid())
+ catch (...)
{
- if (0 != ::setuid(*cmd.uid()))
- Log::get_instance()->message(ll_warning, lc_context, "setuid("
- + stringify(*cmd.uid()) + ") failed: " + stringify(strerror(errno)));
- extras.append(" [setuid " + stringify(*cmd.uid()) + "]");
+ std::cerr << "exec of '" << c << "' failed due to unknown exception" << std::endl;
+ exit(124);
}
-
- std::string c(cmd.command());
-
- if ((! cmd.stdout_prefix().empty()) || (! cmd.stderr_prefix().empty()))
- c = getenv_with_default("PALUDIS_OUTPUTWRAPPER_DIR", LIBEXECDIR "/paludis/utils") + "/outputwrapper --stdout-prefix '"
- + cmd.stdout_prefix() + "' --stderr-prefix '" + cmd.stderr_prefix() + "' "
- + (cmd.prefix_discard_blank_output() ? " --discard-blank-output " : "")
- + (cmd.prefix_blank_lines() ? " --wrap-blanks " : "")
- + " -- " + c;
-
- cmd.echo_to_stderr();
- Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + c
- + " " + extras);
- execl("/bin/sh", "sh", "-c", c.c_str(), static_cast<char *>(0));
- throw PStreamError("execl /bin/sh -c '" + c + "' failed:"
- + stringify(strerror(errno)));
}
else if (-1 == child)
throw PStreamError("fork failed: " + stringify(strerror(errno)));
diff --git a/paludis/util/system.cc b/paludis/util/system.cc
index 2be7fe2..9b1b7eb 100644
--- a/paludis/util/system.cc
+++ b/paludis/util/system.cc
@@ -272,79 +272,94 @@ paludis::run_command(const Command & cmd)
{
Context context("When running command '" + stringify(cmd.command()) + "':");
- pid_t child(fork());
- if (0 == child)
- {
- std::string extras;
+ std::string extras;
- if (! cmd.chdir().empty())
- {
- if (-1 == chdir(stringify(cmd.chdir()).c_str()))
- throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
- extras.append(" [chdir " + cmd.chdir() + "]");
- }
+ if (! cmd.chdir().empty())
+ extras.append(" [chdir " + cmd.chdir() + "]");
- for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
- {
- setenv(s->first.c_str(), s->second.c_str(), 1);
- extras.append(" [setenv " + s->first + "=" + s->second + "]");
- }
+ for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
+ extras.append(" [setenv " + s->first + "=" + s->second + "]");
- if (-1 != stdout_write_fd)
- {
- if (-1 == dup2(stdout_write_fd, 1))
- throw RunCommandError("dup2 failed");
+ if (cmd.gid() && *cmd.gid() != getgid())
+ extras.append(" [setgid " + stringify(*cmd.gid()) + "]");
- if (-1 != stdout_close_fd)
- close(stdout_close_fd);
- }
+ if (cmd.uid() && *cmd.uid() != getuid())
+ extras.append(" [setuid " + stringify(*cmd.uid()) + "]");
- if (-1 != stderr_write_fd)
- {
- if (-1 == dup2(stderr_write_fd, 2))
- throw RunCommandError("dup2 failed");
+ std::string command(cmd.command());
- if (-1 != stderr_close_fd)
- close(stderr_close_fd);
- }
+ if ((! cmd.stdout_prefix().empty()) || (! cmd.stderr_prefix().empty()))
+ command = getenv_with_default("PALUDIS_OUTPUTWRAPPER_DIR", LIBEXECDIR "/paludis/utils") + "/outputwrapper --stdout-prefix '"
+ + cmd.stdout_prefix() + "' --stderr-prefix '" + cmd.stderr_prefix() + "' "
+ + (cmd.prefix_discard_blank_output() ? " --discard-blank-output " : "")
+ + (cmd.prefix_blank_lines() ? " --wrap-blanks " : "")
+ + " -- " + command;
- if (cmd.gid() && *cmd.gid() != getgid())
- {
- gid_t g(*cmd.gid());
-
- if (0 != ::setgid(*cmd.gid()))
- Log::get_instance()->message(ll_warning, lc_context, "setgid("
- + stringify(*cmd.gid()) + ") failed: " + stringify(strerror(errno)));
- else if (0 != ::setgroups(1, &g))
- Log::get_instance()->message(ll_warning, lc_context, "setgroups failed: "
- + stringify(strerror(errno)));
+ cmd.echo_to_stderr();
+ Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + command
+ + " " + extras);
- extras.append(" [setgid " + stringify(*cmd.gid()) + "]");
+ pid_t child(fork());
+ if (0 == child)
+ {
+ try
+ {
+ if (! cmd.chdir().empty())
+ if (-1 == chdir(stringify(cmd.chdir()).c_str()))
+ throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
+
+ for (Command::Iterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
+ setenv(s->first.c_str(), s->second.c_str(), 1);
+
+ if (-1 != stdout_write_fd)
+ {
+ if (-1 == dup2(stdout_write_fd, 1))
+ throw RunCommandError("dup2 failed");
+
+ if (-1 != stdout_close_fd)
+ close(stdout_close_fd);
+ }
+
+ if (-1 != stderr_write_fd)
+ {
+ if (-1 == dup2(stderr_write_fd, 2))
+ throw RunCommandError("dup2 failed");
+
+ if (-1 != stderr_close_fd)
+ close(stderr_close_fd);
+ }
+
+ if (cmd.gid() && *cmd.gid() != getgid())
+ {
+ gid_t g(*cmd.gid());
+
+ if (0 != ::setgid(*cmd.gid()))
+ std::cerr << "setgid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
+ << strerror(errno) << std::endl;
+ else if (0 != ::setgroups(1, &g))
+ std::cerr << "setgroups failed for exec of '" << command << "': " << strerror(errno) << std::endl;
+ }
+
+ if (cmd.uid() && *cmd.uid() != getuid())
+ if (0 != ::setuid(*cmd.uid()))
+ std::cerr << "setuid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
+ << strerror(errno) << std::endl;
+
+ execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char *>(0));
+ throw RunCommandError("execl /bin/sh -c '" + command + "' failed:"
+ + stringify(strerror(errno)));
}
-
- if (cmd.uid() && *cmd.uid() != getuid())
+ catch (const Exception & e)
{
- if (0 != ::setuid(*cmd.uid()))
- Log::get_instance()->message(ll_warning, lc_context, "setuid("
- + stringify(*cmd.uid()) + ") failed: " + stringify(strerror(errno)));
- extras.append(" [setuid " + stringify(*cmd.uid()) + "]");
+ std::cerr << "exec of '" << command << "' failed due to exception '" << e.message()
+ << "' (" << e.what() << ")" << std::endl;
+ exit(123);
+ }
+ catch (...)
+ {
+ std::cerr << "exec of '" << command << "' failed due to unknown exception" << std::endl;
+ exit(124);
}
-
- std::string command(cmd.command());
-
- if ((! cmd.stdout_prefix().empty()) || (! cmd.stderr_prefix().empty()))
- command = getenv_with_default("PALUDIS_OUTPUTWRAPPER_DIR", LIBEXECDIR "/paludis/utils") + "/outputwrapper --stdout-prefix '"
- + cmd.stdout_prefix() + "' --stderr-prefix '" + cmd.stderr_prefix() + "' "
- + (cmd.prefix_discard_blank_output() ? " --discard-blank-output " : "")
- + (cmd.prefix_blank_lines() ? " --wrap-blanks " : "")
- + " -- " + command;
-
- cmd.echo_to_stderr();
- Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + command
- + " " + extras);
- execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char *>(0));
- throw RunCommandError("execl /bin/sh -c '" + command + "' failed:"
- + stringify(strerror(errno)));
}
else if (-1 == child)
throw RunCommandError("fork failed: " + stringify(strerror(errno)));
diff --git a/paludis/util/system_TEST.cc b/paludis/util/system_TEST.cc
index 0367a7f..d9a3eba 100644
--- a/paludis/util/system_TEST.cc
+++ b/paludis/util/system_TEST.cc
@@ -20,9 +20,16 @@
#include <paludis/util/system.hh>
#include <paludis/util/pstream.hh>
#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/thread_pool.hh>
+#include <paludis/util/tr1_functional.hh>
#include <test/test_framework.hh>
#include <test/test_runner.hh>
+#ifdef PALUDIS_ENABLE_THREADS
+# include <sched.h>
+#endif
+
/** \file
* Test cases for system.hh .
*
@@ -31,6 +38,32 @@
using namespace test;
using namespace paludis;
+namespace
+{
+ void repeatedly_log(bool & b)
+ {
+#ifdef PALUDIS_ENABLE_THREADS
+ while (! b)
+ sched_yield();
+#endif
+
+ for (int i(0) ; i < 1000 ; ++i)
+ Log::get_instance()->message(ll_debug, lc_context) << "logging stuff";
+ }
+
+ void repeatedly_run_command(bool & b)
+ {
+#ifdef PALUDIS_ENABLE_THREADS
+ while (! b)
+ sched_yield();
+#endif
+
+ for (int i(0) ; i < 100 ; ++i)
+ if (0 != run_command("/bin/true"))
+ throw InternalError(PALUDIS_HERE, "true isn't");
+ }
+}
+
namespace test_cases
{
@@ -104,6 +137,20 @@ namespace test_cases
}
} test_run_command;
+ struct RunCommandMutexTest : TestCase
+ {
+ RunCommandMutexTest() : TestCase("run_command mutex") { }
+
+ void run()
+ {
+ ThreadPool pool;
+ bool b(false);
+ pool.create_thread(tr1::bind(&repeatedly_run_command, tr1::ref(b)));
+ pool.create_thread(tr1::bind(&repeatedly_log, tr1::ref(b)));
+ b = true;
+ }
+ } test_run_command_mutex;
+
/**
* \test Test run_command_in_directory.
*