36#ifndef BITCOIN_UTIL_SUBPROCESS_H
37#define BITCOIN_UTIL_SUBPROCESS_H
49#include <initializer_list>
67 #include <sys/types.h>
75 #define subprocess_close _close
76 #define subprocess_fileno _fileno
77 #define subprocess_open _open
78 #define subprocess_write _write
80 #define subprocess_close close
81 #define subprocess_fileno fileno
82 #define subprocess_open open
83 #define subprocess_write write
168 constexpr char quote =
'"';
184 for (
auto it =
argument.begin();; ++it) {
203 else if (*it ==
quote) {
231 return std::string();
251 throw OSError(
"invalid_mode", 0);
254 if (mode[0] ==
'w') {
257 else if (mode[0] ==
'r') {
261 throw OSError(
"file_from_handle", 0);
267 throw OSError(
"_open_osfhandle", 0);
290 throw OSError(
"CreatePipe", 0);
294 throw OSError(
"SetHandleInformation", 0);
307 static inline std::vector<std::string>
310 std::vector<std::string>
res;
315 if (pos == std::string::npos) {
316 res.emplace_back(str.substr(
init, str.length()));
391 int write_n(
int fd,
const char* buf,
size_t length)
461 auto buffer = buf.data();
473 const auto orig_sz = buf.size();
514 if (
ret == -1)
break;
515 if (
ret == 0)
continue;
516 return std::make_pair(
ret, status);
519 return std::make_pair(
ret, status);
553 template <
typename T>
587 explicit input(
const char* filename) {
593 assert (typ ==
PIPE &&
"STDOUT/STDERR not allowed");
626 assert (typ ==
PIPE &&
"STDOUT/STDERR not allowed");
651 explicit error(
const char* filename) {
777 int send(
const char* msg,
size_t length);
778 int send(
const std::vector<char>& msg);
780 std::pair<OutBuffer, ErrBuffer>
communicate(
const char* msg,
size_t length);
781 std::pair<OutBuffer, ErrBuffer>
communicate(
const std::vector<char>& msg)
789 const char* msg,
size_t length);
859 int send(
const char* msg,
size_t length)
862 int send(
const std::vector<char>& msg)
865 std::pair<OutBuffer, ErrBuffer>
communicate(
const char* msg,
size_t length)
868 std::pair<OutBuffer, ErrBuffer>
communicate(
const std::vector<char>& msg)
932 template <
typename... Args>
944 template <
typename... Args>
963 int send(
const char* msg,
size_t length)
966 int send(
const std::string& msg)
967 {
return send(msg.c_str(), msg.size()); }
969 int send(
const std::vector<char>& msg)
972 std::pair<OutBuffer, ErrBuffer>
communicate(
const char* msg,
size_t length)
979 std::pair<OutBuffer, ErrBuffer>
communicate(
const std::string& msg)
984 std::pair<OutBuffer, ErrBuffer>
communicate(
const std::vector<char>& msg)
997 template <
typename F,
typename... Args>
1027template <
typename F,
typename... Args>
1031 argd.set_option(std::forward<F>(
farg));
1040 cargv_.push_back(
nullptr);
1050 throw OSError(
"Unexpected return code from WaitForSingleObject", 0);
1056 throw OSError(
"Failed during call to GetExitCodeProcess", 0);
1089 for (
auto arg : this->
vargs_) {
1114 siStartInfo.hStdOutput = this->
stream_.g_hChildStd_OUT_Wr;
1115 siStartInfo.hStdInput = this->
stream_.g_hChildStd_IN_Rd;
1188 chld.execute_child();
1216 }
catch (std::exception&) {
1242 if (err.deferred_) {
1246 throw std::runtime_error(
"Set output before redirecting error to output");
1260 if (
stream.write_to_parent_ == 0)
1278 }
else if(fd != -1) {
1290 if (
stream.read_from_parent_ != -1 &&
stream.read_from_parent_ > 2)
1293 if (
stream.write_to_parent_ != -1 &&
stream.write_to_parent_ > 2)
1307 std::string err_msg(
exp.what());
1342 if (h ==
nullptr)
continue;
1351 return std::fwrite(msg,
sizeof(
char), length,
stream_->
input());
1356 return send(msg.data(), msg.size());
1359 inline std::pair<OutBuffer, ErrBuffer>
1418 return std::make_pair(std::move(
obuf), std::move(
ebuf));
1425 inline std::pair<OutBuffer, ErrBuffer>
1436 out_fut = std::async(std::launch::async,
1444 err_fut = std::async(std::launch::async,
1464 else obuf.length = 0;
1469 else ebuf.length = 0;
1472 return std::make_pair(std::move(
obuf), std::move(
ebuf));
CalledProcessError(const std::string &error_msg, int retcode)
OSError(const std::string &err_msg, int err_code)
std::pair< OutBuffer, ErrBuffer > communicate(const char *msg, size_t length)
std::pair< OutBuffer, ErrBuffer > communicate(const std::string &msg)
void set_out_buf_cap(size_t cap)
Popen(std::initializer_list< const char * > cmd_args, Args &&...args)
std::vector< char * > cargv_
Popen(std::vector< std::string > vargs_, Args &&... args)
void execute_process() noexcept(false)
std::vector< std::string > vargs_
int send(const std::vector< char > &msg)
int send(const std::string &msg)
std::pair< OutBuffer, ErrBuffer > communicate()
std::pair< OutBuffer, ErrBuffer > communicate(const std::vector< char > &msg)
int retcode() const noexcept
int wait() noexcept(false)
void set_err_buf_cap(size_t cap)
int send(const char *msg, size_t length)
Child(Popen *p, int err_wr_pipe)
void set_err_buf_cap(size_t cap)
Communication(Streams *stream)
Communication(Communication &&)=default
void set_out_buf_cap(size_t cap)
int send(const char *msg, size_t length)
std::pair< OutBuffer, ErrBuffer > communicate(const char *msg, size_t length)
std::pair< OutBuffer, ErrBuffer > communicate_threaded(const char *msg, size_t length)
Communication & operator=(const Communication &)=delete
Communication(const Communication &)=delete
Communication & operator=(Communication &&)=default
std::pair< OutBuffer, ErrBuffer > communicate(const std::vector< char > &msg)
std::pair< OutBuffer, ErrBuffer > communicate(const std::vector< char > &msg)
int send(const std::vector< char > &msg)
void set_out_buf_cap(size_t cap)
void setup_comm_channels()
Streams(Streams &&)=default
std::pair< OutBuffer, ErrBuffer > communicate(const char *msg, size_t length)
void set_err_buf_cap(size_t cap)
std::shared_ptr< FILE > output_
std::shared_ptr< FILE > error_
Streams & operator=(const Streams &)=delete
int send(const char *msg, size_t length)
Streams(const Streams &)=delete
Streams & operator=(Streams &&)=default
std::shared_ptr< FILE > input_
#define T(expected, seed, data)
static int read_all(FILE *fp, std::vector< char > &buf)
static int read_atmost_n(FILE *fp, char *buf, size_t read_upto)
static void set_clo_on_exec(int fd, bool set=true)
static std::vector< std::string > split(const std::string &str, const std::string &delims=" \t")
static std::pair< int, int > wait_for_child_exit(int pid)
static std::pair< int, int > pipe_cloexec() noexcept(false)
static int write_n(int fd, const char *buf, size_t length)
constexpr size_t DEFAULT_BUF_CAP_BYTES
constexpr size_t SP_MAX_ERR_BUF_SIZ
void set_option(executable &&exe)
ArgumentDeducer(Popen *p)
error(const char *filename)
output(const char *filename)
string_arg(const char *arg)
string_arg(std::string &&arg)
string_arg(const std::string &arg)
#define subprocess_fileno
std::string SysErrorString(int err)
Return system error string from errno value.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.