36#ifndef BITCOIN_UTIL_SUBPROCESS_H
37#define BITCOIN_UTIL_SUBPROCESS_H
51#include <initializer_list>
60#if (defined _MSC_VER) || (defined __MINGW32__)
61 #define __USING_WINDOWS__
64#ifdef __USING_WINDOWS__
69#ifdef __USING_WINDOWS__
79 #include <sys/types.h>
87 #define subprocess_close _close
88 #define subprocess_fileno _fileno
89 #define subprocess_open _open
90 #define subprocess_write _write
92 #define subprocess_close close
93 #define subprocess_fileno fileno
94 #define subprocess_open open
95 #define subprocess_write write
168 OSError(
const std::string& err_msg,
int err_code):
176#ifdef __USING_WINDOWS__
177 inline void quote_argument(
const std::wstring &argument, std::wstring &command_line,
186 if (force ==
false && argument.empty() ==
false &&
187 argument.find_first_of(L
" \t\n\v") == argument.npos) {
188 command_line.append(argument);
191 command_line.push_back(L
'"');
193 for (
auto it = argument.begin();; ++it) {
194 unsigned number_backslashes = 0;
196 while (it != argument.end() && *it == L
'\\') {
198 ++number_backslashes;
201 if (it == argument.end()) {
209 command_line.append(number_backslashes * 2, L
'\\');
212 else if (*it == L
'"') {
219 command_line.append(number_backslashes * 2 + 1, L
'\\');
220 command_line.push_back(*it);
228 command_line.append(number_backslashes, L
'\\');
229 command_line.push_back(*it);
233 command_line.push_back(L
'"');
237 inline std::string get_last_error(DWORD errorMessageID)
239 if (errorMessageID == 0)
240 return std::string();
242 LPSTR messageBuffer =
nullptr;
243 size_t size = FormatMessageA(
244 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
245 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
246 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
247 (LPSTR)&messageBuffer, 0, NULL);
249 std::string message(messageBuffer, size);
251 LocalFree(messageBuffer);
256 inline FILE *file_from_handle(HANDLE h,
const char *mode)
260 throw OSError(
"invalid_mode", 0);
263 if (mode[0] ==
'w') {
266 else if (mode[0] ==
'r') {
270 throw OSError(
"file_from_handle", 0);
273 int os_fhandle = _open_osfhandle((intptr_t)h, md);
274 if (os_fhandle == -1) {
276 throw OSError(
"_open_osfhandle", 0);
279 FILE *fp = _fdopen(os_fhandle, mode);
288 inline void configure_pipe(HANDLE* read_handle, HANDLE* write_handle, HANDLE* child_handle)
290 SECURITY_ATTRIBUTES saAttr;
293 saAttr.nLength =
sizeof(SECURITY_ATTRIBUTES);
294 saAttr.bInheritHandle = TRUE;
295 saAttr.lpSecurityDescriptor = NULL;
298 if (!CreatePipe(read_handle, write_handle, &saAttr,0))
299 throw OSError(
"CreatePipe", 0);
302 if (!SetHandleInformation(*child_handle, HANDLE_FLAG_INHERIT, 0))
303 throw OSError(
"SetHandleInformation", 0);
316 static inline std::vector<std::string>
317 split(
const std::string& str,
const std::string& delims=
" \t")
319 std::vector<std::string> res;
323 auto pos = str.find_first_of(delims,
init);
324 if (pos == std::string::npos) {
325 res.emplace_back(str.substr(
init, str.length()));
328 res.emplace_back(str.substr(
init, pos -
init));
337#ifndef __USING_WINDOWS__
350 int flags = fcntl(fd, F_GETFD, 0);
352 throw OSError(
"fcntl F_GETFD failed", errno);
354 if (set)
flags |= FD_CLOEXEC;
355 else flags &= ~FD_CLOEXEC;
356 if (fcntl(fd, F_SETFD,
flags) == -1) {
357 throw OSError(
"fcntl F_SETFD failed", errno);
375 int res = pipe(pipe_fds);
377 throw OSError(
"pipe failure", errno);
383 return std::make_pair(pipe_fds[0], pipe_fds[1]);
400 int write_n(
int fd,
const char* buf,
size_t length)
403 while (nwritten < length) {
405 if (written == -1)
return -1;
429#ifdef __USING_WINDOWS__
430 return (
int)fread(buf, 1, read_upto, fp);
437 int read_bytes = read(fd, buf + rbytes, read_upto - rbytes);
438 if (read_bytes == -1) {
439 if (errno == EINTR) {
440 if (eintr_cnter >= 50)
return -1;
446 if (read_bytes == 0)
return rbytes;
448 rbytes += read_bytes;
468 static inline int read_all(FILE* fp, std::vector<char>& buf)
470 auto buffer = buf.data();
471 int total_bytes_read = 0;
472 int fill_sz = buf.size();
477 if (rd_bytes == -1) {
478 if (total_bytes_read == 0)
return -1;
481 }
else if (rd_bytes == fill_sz) {
482 const auto orig_sz = buf.size();
483 const auto new_sz = orig_sz * 2;
485 fill_sz = new_sz - orig_sz;
489 total_bytes_read += rd_bytes;
490 buffer += total_bytes_read;
493 total_bytes_read += rd_bytes;
498 buf.erase(buf.begin()+total_bytes_read, buf.end());
499 return total_bytes_read;
502#ifndef __USING_WINDOWS__
522 ret = waitpid(pid, &status, 0);
523 if (
ret == -1)
break;
524 if (
ret == 0)
continue;
525 return std::make_pair(
ret, status);
528 return std::make_pair(
ret, status);
576 template <
typename T>
610 explicit input(
const char* filename) {
612 if (fd == -1)
throw OSError(
"File not found: ", errno);
616 assert (typ ==
PIPE &&
"STDOUT/STDERR not allowed");
617#ifndef __USING_WINDOWS__
645 if (fd == -1)
throw OSError(
"File not found: ", errno);
649 assert (typ ==
PIPE &&
"STDOUT/STDERR not allowed");
650#ifndef __USING_WINDOWS__
674 explicit error(
const char* filename) {
676 if (fd == -1)
throw OSError(
"File not found: ", errno);
682#ifndef __USING_WINDOWS__
799 int send(
const char*
msg,
size_t length);
800 int send(
const std::vector<char>&
msg);
802 std::pair<OutBuffer, ErrBuffer>
communicate(
const char*
msg,
size_t length);
811 const char*
msg,
size_t length);
900#ifdef __USING_WINDOWS__
901 HANDLE g_hChildStd_IN_Rd =
nullptr;
902 HANDLE g_hChildStd_IN_Wr =
nullptr;
903 HANDLE g_hChildStd_OUT_Rd =
nullptr;
904 HANDLE g_hChildStd_OUT_Wr =
nullptr;
905 HANDLE g_hChildStd_ERR_Rd =
nullptr;
906 HANDLE g_hChildStd_ERR_Wr =
nullptr;
954 template <
typename... Args>
967 template <
typename... Args>
968 Popen(std::initializer_list<const char*> cmd_args, Args&& ...
args)
970 vargs_.insert(
vargs_.end(), cmd_args.begin(), cmd_args.end());
979 template <
typename... Args>
992 int wait() noexcept(false);
1032 template <
typename F,
typename... Args>
1041#ifdef __USING_WINDOWS__
1042 HANDLE process_handle_;
1043 std::future<void> cleanup_future_;
1066template <
typename F,
typename... Args>
1079 cargv_.push_back(
nullptr);
1084#ifdef __USING_WINDOWS__
1085 int ret = WaitForSingleObject(process_handle_, INFINITE);
1088 if (
ret != WAIT_OBJECT_0) {
1089 throw OSError(
"Unexpected return code from WaitForSingleObject", 0);
1094 if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_))
1095 throw OSError(
"Failed during call to GetExitCodeProcess", 0);
1097 CloseHandle(process_handle_);
1099 return (
int)dretcode_;
1104 if (errno != ECHILD)
throw OSError(
"waitpid failed", errno);
1107 if (WIFEXITED(status))
return WEXITSTATUS(status);
1108 if (WIFSIGNALED(status))
return WTERMSIG(status);
1117#ifdef __USING_WINDOWS__
1119 this->
vargs_.insert(this->
vargs_.begin(), this->exe_name_);
1124 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
1125 std::wstring argument;
1126 std::wstring command_line;
1127 bool first_arg =
true;
1129 for (
auto arg : this->
vargs_) {
1131 command_line += L
" ";
1135 argument = converter.from_bytes(arg);
1136 util::quote_argument(argument, command_line,
false);
1140 wchar_t *szCmdline =
new wchar_t[command_line.size() + 1];
1141 wcscpy_s(szCmdline, command_line.size() + 1, command_line.c_str());
1142 PROCESS_INFORMATION piProcInfo;
1143 STARTUPINFOW siStartInfo;
1144 BOOL bSuccess = FALSE;
1145 DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
1148 ZeroMemory(&piProcInfo,
sizeof(PROCESS_INFORMATION));
1153 ZeroMemory(&siStartInfo,
sizeof(STARTUPINFOW));
1154 siStartInfo.cb =
sizeof(STARTUPINFOW);
1156 siStartInfo.hStdError = this->
stream_.g_hChildStd_ERR_Wr;
1157 siStartInfo.hStdOutput = this->
stream_.g_hChildStd_OUT_Wr;
1158 siStartInfo.hStdInput = this->
stream_.g_hChildStd_IN_Rd;
1160 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
1163 bSuccess = CreateProcessW(NULL,
1176 DWORD errorMessageID = ::GetLastError();
1177 throw CalledProcessError(
"CreateProcess failed: " + util::get_last_error(errorMessageID), errorMessageID);
1180 CloseHandle(piProcInfo.hThread);
1186 this->process_handle_ = piProcInfo.hProcess;
1188 this->cleanup_future_ = std::async(std::launch::async, [
this] {
1189 WaitForSingleObject(this->process_handle_, INFINITE);
1191 CloseHandle(this->
stream_.g_hChildStd_ERR_Wr);
1192 CloseHandle(this->
stream_.g_hChildStd_OUT_Wr);
1193 CloseHandle(this->
stream_.g_hChildStd_IN_Rd);
1205 int err_rd_pipe, err_wr_pipe;
1219 throw OSError(
"fork failed", errno);
1242 FILE* err_fp = fdopen(err_rd_pipe,
"r");
1245 throw OSError(
"fdopen failed", errno);
1250 if (read_bytes || strlen(err_buf)) {
1259 }
catch (std::exception& exp) {
1285 if (err.deferred_) {
1289 throw std::runtime_error(
"Set output before redirecting error to output");
1302#ifndef __USING_WINDOWS__
1307 if (stream.write_to_parent_ == 0)
1310 if (stream.err_write_ == 0 || stream.err_write_ == 1)
1311 stream.err_write_ = dup(stream.err_write_);
1315 auto _dup2_ = [](
int fd,
int to_fd) {
1325 }
else if(fd != -1) {
1326 int res = dup2(fd, to_fd);
1327 if (res == -1)
throw OSError(
"dup2 failed", errno);
1332 _dup2_(stream.read_from_parent_, 0);
1333 _dup2_(stream.write_to_parent_, 1);
1334 _dup2_(stream.err_write_, 2);
1337 if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2)
1340 if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2)
1343 if (stream.err_write_ != -1 && stream.err_write_ > 2)
1354 std::vector<int> fds_to_close;
1355 for (
const auto& it : fs::directory_iterator(
strprintf(
"/proc/%d/fd", getpid()))) {
1356 auto fd{ToIntegral<uint64_t>(it.path().filename().native())};
1357 if (!fd || *fd > std::numeric_limits<int>::max())
continue;
1358 if (*fd <= 2)
continue;
1359 if (*fd ==
static_cast<uint64_t
>(
err_wr_pipe_))
continue;
1360 fds_to_close.push_back(*fd);
1362 for (
const int fd : fds_to_close) {
1365 }
catch (
const fs::filesystem_error &e) {
1366 throw OSError(
"/proc/<pid>/fd iteration failed", e.code().value());
1371 int max_fd = sysconf(_SC_OPEN_MAX);
1372 if (max_fd == -1)
throw OSError(
"sysconf failed", errno);
1374 for (
int i = 3; i < max_fd; i++) {
1384 if (sys_ret == -1)
throw OSError(
"execve failed", errno);
1386 }
catch (
const OSError& exp) {
1389 std::string err_msg(exp.what());
1396 _exit (EXIT_FAILURE);
1403#ifdef __USING_WINDOWS__
1404 util::configure_pipe(&this->g_hChildStd_IN_Rd, &this->g_hChildStd_IN_Wr, &this->g_hChildStd_IN_Wr);
1405 this->
input(util::file_from_handle(this->g_hChildStd_IN_Wr,
"w"));
1408 util::configure_pipe(&this->g_hChildStd_OUT_Rd, &this->g_hChildStd_OUT_Wr, &this->g_hChildStd_OUT_Rd);
1409 this->
output(util::file_from_handle(this->g_hChildStd_OUT_Rd,
"r"));
1412 util::configure_pipe(&this->g_hChildStd_ERR_Rd, &this->g_hChildStd_ERR_Wr, &this->g_hChildStd_ERR_Rd);
1413 this->
error(util::file_from_handle(this->g_hChildStd_ERR_Rd,
"r"));
1423 for (
auto& h : handles) {
1424 if (h ==
nullptr)
continue;
1425 setvbuf(h,
nullptr, _IONBF, BUFSIZ);
1441 inline std::pair<OutBuffer, ErrBuffer>
1449 const int len_conv = length;
1456 int wbytes = std::fwrite(
msg,
sizeof(
char), length,
stream_->
input());
1457 if (wbytes < len_conv) {
1458 if (errno != EPIPE && errno != EINVAL) {
1459 throw OSError(
"fwrite error", errno);
1476 throw OSError(
"read to obuf failed", errno);
1493 throw OSError(
"read to ebuf failed", errno);
1500 return std::make_pair(std::move(obuf), std::move(ebuf));
1507 inline std::pair<OutBuffer, ErrBuffer>
1512 std::future<int> out_fut, err_fut;
1513 const int length_conv = length;
1518 out_fut = std::async(std::launch::async,
1526 err_fut = std::async(std::launch::async,
1533 int wbytes = std::fwrite(
msg,
sizeof(
char), length,
stream_->
input());
1534 if (wbytes < length_conv) {
1535 if (errno != EPIPE && errno != EINVAL) {
1536 throw OSError(
"fwrite error", errno);
1543 if (out_fut.valid()) {
1544 int res = out_fut.get();
1545 if (res != -1) obuf.
length = res;
1548 if (err_fut.valid()) {
1549 int res = err_fut.get();
1550 if (res != -1) ebuf.
length = res;
1554 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
Popen(const std::string &cmd_args, Args &&...args)
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)
static const size_t SP_MAX_ERR_BUF_SIZ
static const size_t DEFAULT_BUF_CAP_BYTES
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.