Do not close stderr/stdout before program finish

Programs like grep called in '$' command will fail due to SIGPIPE
for example. So we need to keep the pipe open.
This commit is contained in:
Maxime Coste 2015-06-08 22:42:51 +01:00
parent 6cb7e20d54
commit 409d804ee8
6 changed files with 18 additions and 17 deletions

View File

@ -271,7 +271,7 @@ String expand_token(const Token& token, const Context& context,
{ {
case Token::Type::ShellExpand: case Token::Type::ShellExpand:
return ShellManager::instance().eval(content, context, {}, return ShellManager::instance().eval(content, context, {},
ShellManager::Flags::ReadOutput, ShellManager::Flags::WaitForStdout,
shell_params, env_vars).first; shell_params, env_vars).first;
case Token::Type::RegisterExpand: case Token::Type::RegisterExpand:
return context.main_sel_register_value(content).str(); return context.main_sel_register_value(content).str();

View File

@ -787,7 +787,7 @@ void define_command(const ParametersParser& parser, Context& context)
{ "pos_in_token", to_string(pos_in_token) } { "pos_in_token", to_string(pos_in_token) }
}; };
String output = ShellManager::instance().eval(shell_cmd, context, {}, String output = ShellManager::instance().eval(shell_cmd, context, {},
ShellManager::Flags::ReadOutput, ShellManager::Flags::WaitForStdout,
params, vars).first; params, vars).first;
return Completions{ 0_byte, pos_in_token, split(output, '\n', 0) }; return Completions{ 0_byte, pos_in_token, split(output, '\n', 0) };
}; };

View File

@ -24,10 +24,13 @@ void FDWatcher::run(EventMode mode)
} }
void FDWatcher::close_fd() void FDWatcher::close_fd()
{
if (m_fd != -1)
{ {
close(m_fd); close(m_fd);
m_fd = -1; m_fd = -1;
} }
}
Timer::Timer(TimePoint date, Callback callback, EventMode mode) Timer::Timer(TimePoint date, Callback callback, EventMode mode)
: m_date{date}, m_callback{std::move(callback)}, m_mode(mode) : m_date{date}, m_callback{std::move(callback)}, m_mode(mode)

View File

@ -396,7 +396,7 @@ void pipe(Context& context, NormalParams)
str += '\n'; str += '\n';
str = ShellManager::instance().eval( str = ShellManager::instance().eval(
real_cmd, context, str, real_cmd, context, str,
ShellManager::Flags::ReadOutput, ShellManager::Flags::WaitForStdout,
{}, EnvVarMap{}).first; {}, EnvVarMap{}).first;
if ((insert_eol or sel.max() == buffer.back_coord()) and if ((insert_eol or sel.max() == buffer.back_coord()) and
@ -441,7 +441,7 @@ void insert_output(Context& context, NormalParams)
return; return;
auto str = ShellManager::instance().eval(real_cmd, context, {}, auto str = ShellManager::instance().eval(real_cmd, context, {},
ShellManager::Flags::ReadOutput, ShellManager::Flags::WaitForStdout,
{}, EnvVarMap{}).first; {}, EnvVarMap{}).first;
ScopedEdition edition(context); ScopedEdition edition(context);
context.selections().insert(str, mode); context.selections().insert(str, mode);

View File

@ -60,20 +60,18 @@ std::pair<String, int> ShellManager::eval(
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(child_stdout)}; FDWatcher stdout_watcher{read_pipe[0], pipe_reader(child_stdout)};
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(child_stderr)}; FDWatcher stderr_watcher{error_pipe[0], pipe_reader(child_stderr)};
if (not (flags & Flags::ReadOutput)) while (not terminated or
{ ((flags & Flags::WaitForStdout) and
stdout_watcher.close_fd(); (not stdout_watcher.closed() or
stderr_watcher.close_fd(); not stderr_watcher.closed())))
}
while (not stdout_watcher.closed() or
not stderr_watcher.closed() or
not terminated)
{ {
EventManager::instance().handle_next_events(EventMode::Urgent); EventManager::instance().handle_next_events(EventMode::Urgent);
if (not terminated) if (not terminated)
terminated = waitpid(pid, &status, WNOHANG); terminated = waitpid(pid, &status, WNOHANG);
} }
stdout_watcher.close_fd();
stderr_watcher.close_fd();
} }
if (not child_stderr.empty()) if (not child_stderr.empty())

View File

@ -24,12 +24,12 @@ public:
enum class Flags enum class Flags
{ {
None = 0, None = 0,
ReadOutput = 1 WaitForStdout = 1
}; };
std::pair<String, int> eval(StringView cmdline, const Context& context, std::pair<String, int> eval(StringView cmdline, const Context& context,
StringView input = {}, StringView input = {},
Flags flags = Flags::ReadOutput, Flags flags = Flags::WaitForStdout,
ConstArrayView<String> params = {}, ConstArrayView<String> params = {},
const EnvVarMap& env_vars = EnvVarMap{}); const EnvVarMap& env_vars = EnvVarMap{});