mirror of
https://github.com/NixOS/nix
synced 2025-06-27 00:11:17 +02:00
runProgram(): Distinguish between empty input and no input
For example, if we call brotli with an empty input, it shouldn't read from the caller's stdin.
This commit is contained in:
parent
042975ea8e
commit
25dff2b7db
5 changed files with 30 additions and 15 deletions
|
@ -1,6 +1,7 @@
|
|||
#include "util.hh"
|
||||
#include "affinity.hh"
|
||||
#include "sync.hh"
|
||||
#include "finally.hh"
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
|
@ -10,6 +11,7 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
@ -837,23 +839,21 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
|
|||
|
||||
|
||||
string runProgram(Path program, bool searchPath, const Strings & args,
|
||||
const string & input)
|
||||
const std::experimental::optional<std::string> & input)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
/* Create a pipe. */
|
||||
Pipe out, in;
|
||||
out.create();
|
||||
if (!input.empty()) in.create();
|
||||
if (input) in.create();
|
||||
|
||||
/* Fork. */
|
||||
Pid pid = startProcess([&]() {
|
||||
if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
|
||||
throw SysError("dupping stdout");
|
||||
if (!input.empty()) {
|
||||
if (dup2(in.readSide.get(), STDIN_FILENO) == -1)
|
||||
throw SysError("dupping stdin");
|
||||
}
|
||||
if (input && dup2(in.readSide.get(), STDIN_FILENO) == -1)
|
||||
throw SysError("dupping stdin");
|
||||
|
||||
Strings args_(args);
|
||||
args_.push_front(program);
|
||||
|
@ -872,10 +872,23 @@ string runProgram(Path program, bool searchPath, const Strings & args,
|
|||
|
||||
std::thread writerThread;
|
||||
|
||||
if (!input.empty()) {
|
||||
std::promise<void> promise;
|
||||
|
||||
Finally doJoin([&]() {
|
||||
if (writerThread.joinable())
|
||||
writerThread.join();
|
||||
});
|
||||
|
||||
|
||||
if (input) {
|
||||
in.readSide = -1;
|
||||
writerThread = std::thread([&]() {
|
||||
writeFull(in.writeSide.get(), input);
|
||||
try {
|
||||
writeFull(in.writeSide.get(), *input);
|
||||
promise.set_value();
|
||||
} catch (...) {
|
||||
promise.set_exception(std::current_exception());
|
||||
}
|
||||
in.writeSide = -1;
|
||||
});
|
||||
}
|
||||
|
@ -888,8 +901,8 @@ string runProgram(Path program, bool searchPath, const Strings & args,
|
|||
throw ExecError(status, format("program ‘%1%’ %2%")
|
||||
% program % statusToString(status));
|
||||
|
||||
if (!input.empty())
|
||||
writerThread.join();
|
||||
/* Wait for the writer thread to finish. */
|
||||
if (input) promise.get_future().get();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue