subprocess.h
1 // Based on the https://github.com/arun11299/cpp-subprocess project. 2 3 /*! 4 5 Documentation for C++ subprocessing library. 6 7 @copyright The code is licensed under the [MIT 8 License](http://opensource.org/licenses/MIT): 9 <br> 10 Copyright © 2016-2018 Arun Muralidharan. 11 <br> 12 Permission is hereby granted, free of charge, to any person obtaining a copy 13 of this software and associated documentation files (the "Software"), to deal 14 in the Software without restriction, including without limitation the rights 15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 copies of the Software, and to permit persons to whom the Software is 17 furnished to do so, subject to the following conditions: 18 <br> 19 The above copyright notice and this permission notice shall be included in 20 all copies or substantial portions of the Software. 21 <br> 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 SOFTWARE. 29 30 @author [Arun Muralidharan] 31 @see https://github.com/arun11299/cpp-subprocess to download the source code 32 33 @version 1.0.0 34 */ 35 36 #ifndef BITCOIN_UTIL_SUBPROCESS_H 37 #define BITCOIN_UTIL_SUBPROCESS_H 38 39 #include <util/syserror.h> 40 41 #include <algorithm> 42 #include <cassert> 43 #include <csignal> 44 #include <cstdio> 45 #include <cstdlib> 46 #include <cstring> 47 #include <exception> 48 #include <future> 49 #include <initializer_list> 50 #include <iostream> 51 #include <locale> 52 #include <map> 53 #include <memory> 54 #include <sstream> 55 #include <string> 56 #include <vector> 57 58 #if (defined _MSC_VER) || (defined __MINGW32__) 59 #define __USING_WINDOWS__ 60 #endif 61 62 #ifdef __USING_WINDOWS__ 63 #include <codecvt> 64 #endif 65 66 extern "C" { 67 #ifdef __USING_WINDOWS__ 68 #include <windows.h> 69 #include <io.h> 70 #include <cwchar> 71 #else 72 #include <sys/wait.h> 73 #include <unistd.h> 74 #endif 75 #include <csignal> 76 #include <fcntl.h> 77 #include <sys/types.h> 78 } 79 80 // The Microsoft C++ compiler issues deprecation warnings 81 // for the standard POSIX function names. 82 // Its preferred implementations have a leading underscore. 83 // See: https://learn.microsoft.com/en-us/cpp/c-runtime-library/compatibility. 84 #if (defined _MSC_VER) 85 #define subprocess_close _close 86 #define subprocess_fileno _fileno 87 #define subprocess_open _open 88 #define subprocess_write _write 89 #else 90 #define subprocess_close close 91 #define subprocess_fileno fileno 92 #define subprocess_open open 93 #define subprocess_write write 94 #endif 95 96 /*! 97 * Getting started with reading this source code. 98 * The source is mainly divided into four parts: 99 * 1. Exception Classes: 100 * These are very basic exception classes derived from 101 * runtime_error exception. 102 * There are two types of exception thrown from subprocess 103 * library: OSError and CalledProcessError 104 * 105 * 2. Popen Class 106 * This is the main class the users will deal with. It 107 * provides with all the API's to deal with processes. 108 * 109 * 3. Util namespace 110 * It includes some helper functions to split/join a string, 111 * reading from file descriptors, waiting on a process, fcntl 112 * options on file descriptors etc. 113 * 114 * 4. Detail namespace 115 * This includes some metaprogramming and helper classes. 116 */ 117 118 119 namespace subprocess { 120 121 // Max buffer size allocated on stack for read error 122 // from pipe 123 static const size_t SP_MAX_ERR_BUF_SIZ = 1024; 124 125 // Default buffer capacity for OutBuffer and ErrBuffer. 126 // If the data exceeds this capacity, the buffer size is grown 127 // by 1.5 times its previous capacity 128 static const size_t DEFAULT_BUF_CAP_BYTES = 8192; 129 130 131 /*----------------------------------------------- 132 * EXCEPTION CLASSES 133 *----------------------------------------------- 134 */ 135 136 /*! 137 * class: CalledProcessError 138 * Thrown when there was error executing the command. 139 * Check Popen class API's to know when this exception 140 * can be thrown. 141 * 142 */ 143 class CalledProcessError: public std::runtime_error 144 { 145 public: 146 int retcode; 147 CalledProcessError(const std::string& error_msg, int retcode): 148 std::runtime_error(error_msg), retcode(retcode) 149 {} 150 }; 151 152 153 /*! 154 * class: OSError 155 * Thrown when some system call fails to execute or give result. 156 * The exception message contains the name of the failed system call 157 * with the stringisized errno code. 158 * Check Popen class API's to know when this exception would be 159 * thrown. 160 * Its usual that the API exception specification would have 161 * this exception together with CalledProcessError. 162 */ 163 class OSError: public std::runtime_error 164 { 165 public: 166 OSError(const std::string& err_msg, int err_code): 167 std::runtime_error(err_msg + ": " + SysErrorString(err_code)) 168 {} 169 }; 170 171 //-------------------------------------------------------------------- 172 namespace util 173 { 174 #ifdef __USING_WINDOWS__ 175 inline void quote_argument(const std::wstring &argument, std::wstring &command_line, 176 bool force) 177 { 178 // 179 // Unless we're told otherwise, don't quote unless we actually 180 // need to do so --- hopefully avoid problems if programs won't 181 // parse quotes properly 182 // 183 184 if (force == false && argument.empty() == false && 185 argument.find_first_of(L" \t\n\v") == argument.npos) { 186 command_line.append(argument); 187 } 188 else { 189 command_line.push_back(L'"'); 190 191 for (auto it = argument.begin();; ++it) { 192 unsigned number_backslashes = 0; 193 194 while (it != argument.end() && *it == L'\\') { 195 ++it; 196 ++number_backslashes; 197 } 198 199 if (it == argument.end()) { 200 201 // 202 // Escape all backslashes, but let the terminating 203 // double quotation mark we add below be interpreted 204 // as a metacharacter. 205 // 206 207 command_line.append(number_backslashes * 2, L'\\'); 208 break; 209 } 210 else if (*it == L'"') { 211 212 // 213 // Escape all backslashes and the following 214 // double quotation mark. 215 // 216 217 command_line.append(number_backslashes * 2 + 1, L'\\'); 218 command_line.push_back(*it); 219 } 220 else { 221 222 // 223 // Backslashes aren't special here. 224 // 225 226 command_line.append(number_backslashes, L'\\'); 227 command_line.push_back(*it); 228 } 229 } 230 231 command_line.push_back(L'"'); 232 } 233 } 234 235 inline std::string get_last_error(DWORD errorMessageID) 236 { 237 if (errorMessageID == 0) 238 return std::string(); 239 240 LPSTR messageBuffer = nullptr; 241 size_t size = FormatMessageA( 242 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 243 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, 244 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 245 (LPSTR)&messageBuffer, 0, NULL); 246 247 std::string message(messageBuffer, size); 248 249 LocalFree(messageBuffer); 250 251 return message; 252 } 253 254 inline FILE *file_from_handle(HANDLE h, const char *mode) 255 { 256 int md; 257 if (!mode) { 258 throw OSError("invalid_mode", 0); 259 } 260 261 if (mode[0] == 'w') { 262 md = _O_WRONLY; 263 } 264 else if (mode[0] == 'r') { 265 md = _O_RDONLY; 266 } 267 else { 268 throw OSError("file_from_handle", 0); 269 } 270 271 int os_fhandle = _open_osfhandle((intptr_t)h, md); 272 if (os_fhandle == -1) { 273 CloseHandle(h); 274 throw OSError("_open_osfhandle", 0); 275 } 276 277 FILE *fp = _fdopen(os_fhandle, mode); 278 if (fp == 0) { 279 subprocess_close(os_fhandle); 280 throw OSError("_fdopen", 0); 281 } 282 283 return fp; 284 } 285 286 inline void configure_pipe(HANDLE* read_handle, HANDLE* write_handle, HANDLE* child_handle) 287 { 288 SECURITY_ATTRIBUTES saAttr; 289 290 // Set the bInheritHandle flag so pipe handles are inherited. 291 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 292 saAttr.bInheritHandle = TRUE; 293 saAttr.lpSecurityDescriptor = NULL; 294 295 // Create a pipe for the child process's STDIN. 296 if (!CreatePipe(read_handle, write_handle, &saAttr,0)) 297 throw OSError("CreatePipe", 0); 298 299 // Ensure the write handle to the pipe for STDIN is not inherited. 300 if (!SetHandleInformation(*child_handle, HANDLE_FLAG_INHERIT, 0)) 301 throw OSError("SetHandleInformation", 0); 302 } 303 #endif 304 305 /*! 306 * Function: split 307 * Parameters: 308 * [in] str : Input string which needs to be split based upon the 309 * delimiters provided. 310 * [in] deleims : Delimiter characters based upon which the string needs 311 * to be split. Default constructed to ' '(space) and '\t'(tab) 312 * [out] vector<string> : Vector of strings split at deleimiter. 313 */ 314 static inline std::vector<std::string> 315 split(const std::string& str, const std::string& delims=" \t") 316 { 317 std::vector<std::string> res; 318 size_t init = 0; 319 320 while (true) { 321 auto pos = str.find_first_of(delims, init); 322 if (pos == std::string::npos) { 323 res.emplace_back(str.substr(init, str.length())); 324 break; 325 } 326 res.emplace_back(str.substr(init, pos - init)); 327 pos++; 328 init = pos; 329 } 330 331 return res; 332 } 333 334 335 #ifndef __USING_WINDOWS__ 336 /*! 337 * Function: set_clo_on_exec 338 * Sets/Resets the FD_CLOEXEC flag on the provided file descriptor 339 * based upon the `set` parameter. 340 * Parameters: 341 * [in] fd : The descriptor on which FD_CLOEXEC needs to be set/reset. 342 * [in] set : If 'true', set FD_CLOEXEC. 343 * If 'false' unset FD_CLOEXEC. 344 */ 345 static inline 346 void set_clo_on_exec(int fd, bool set = true) 347 { 348 int flags = fcntl(fd, F_GETFD, 0); 349 if (flags == -1) { 350 throw OSError("fcntl F_GETFD failed", errno); 351 } 352 if (set) flags |= FD_CLOEXEC; 353 else flags &= ~FD_CLOEXEC; 354 if (fcntl(fd, F_SETFD, flags) == -1) { 355 throw OSError("fcntl F_SETFD failed", errno); 356 } 357 } 358 359 360 /*! 361 * Function: pipe_cloexec 362 * Creates a pipe and sets FD_CLOEXEC flag on both 363 * read and write descriptors of the pipe. 364 * Parameters: 365 * [out] : A pair of file descriptors. 366 * First element of pair is the read descriptor of pipe. 367 * Second element is the write descriptor of pipe. 368 */ 369 static inline 370 std::pair<int, int> pipe_cloexec() noexcept(false) 371 { 372 int pipe_fds[2]; 373 int res = pipe(pipe_fds); 374 if (res) { 375 throw OSError("pipe failure", errno); 376 } 377 378 set_clo_on_exec(pipe_fds[0]); 379 set_clo_on_exec(pipe_fds[1]); 380 381 return std::make_pair(pipe_fds[0], pipe_fds[1]); 382 } 383 #endif 384 385 386 /*! 387 * Function: write_n 388 * Writes `length` bytes to the file descriptor `fd` 389 * from the buffer `buf`. 390 * Parameters: 391 * [in] fd : The file descriptotr to write to. 392 * [in] buf: Buffer from which data needs to be written to fd. 393 * [in] length: The number of bytes that needs to be written from 394 * `buf` to `fd`. 395 * [out] int : Number of bytes written or -1 in case of failure. 396 */ 397 static inline 398 int write_n(int fd, const char* buf, size_t length) 399 { 400 size_t nwritten = 0; 401 while (nwritten < length) { 402 int written = subprocess_write(fd, buf + nwritten, length - nwritten); 403 if (written == -1) return -1; 404 nwritten += written; 405 } 406 return nwritten; 407 } 408 409 410 /*! 411 * Function: read_atmost_n 412 * Reads at the most `read_upto` bytes from the 413 * file object `fp` before returning. 414 * Parameters: 415 * [in] fp : The file object from which it needs to read. 416 * [in] buf : The buffer into which it needs to write the data. 417 * [in] read_upto: Max number of bytes which must be read from `fd`. 418 * [out] int : Number of bytes written to `buf` or read from `fd` 419 * OR -1 in case of error. 420 * NOTE: In case of EINTR while reading from socket, this API 421 * will retry to read from `fd`, but only till the EINTR counter 422 * reaches 50 after which it will return with whatever data it read. 423 */ 424 static inline 425 int read_atmost_n(FILE* fp, char* buf, size_t read_upto) 426 { 427 #ifdef __USING_WINDOWS__ 428 return (int)fread(buf, 1, read_upto, fp); 429 #else 430 int fd = subprocess_fileno(fp); 431 int rbytes = 0; 432 int eintr_cnter = 0; 433 434 while (1) { 435 int read_bytes = read(fd, buf + rbytes, read_upto - rbytes); 436 if (read_bytes == -1) { 437 if (errno == EINTR) { 438 if (eintr_cnter >= 50) return -1; 439 eintr_cnter++; 440 continue; 441 } 442 return -1; 443 } 444 if (read_bytes == 0) return rbytes; 445 446 rbytes += read_bytes; 447 } 448 return rbytes; 449 #endif 450 } 451 452 453 /*! 454 * Function: read_all 455 * Reads all the available data from `fp` into 456 * `buf`. Internally calls read_atmost_n. 457 * Parameters: 458 * [in] fp : The file object from which to read from. 459 * [in] buf : The buffer of type `class Buffer` into which 460 * the read data is written to. 461 * [out] int: Number of bytes read OR -1 in case of failure. 462 * 463 * NOTE: `class Buffer` is a exposed public class. See below. 464 */ 465 466 static inline int read_all(FILE* fp, std::vector<char>& buf) 467 { 468 auto buffer = buf.data(); 469 int total_bytes_read = 0; 470 int fill_sz = buf.size(); 471 472 while (1) { 473 const int rd_bytes = read_atmost_n(fp, buffer, fill_sz); 474 475 if (rd_bytes == -1) { // Read finished 476 if (total_bytes_read == 0) return -1; 477 break; 478 479 } else if (rd_bytes == fill_sz) { // Buffer full 480 const auto orig_sz = buf.size(); 481 const auto new_sz = orig_sz * 2; 482 buf.resize(new_sz); 483 fill_sz = new_sz - orig_sz; 484 485 //update the buffer pointer 486 buffer = buf.data(); 487 total_bytes_read += rd_bytes; 488 buffer += total_bytes_read; 489 490 } else { // Partial data ? Continue reading 491 total_bytes_read += rd_bytes; 492 fill_sz -= rd_bytes; 493 break; 494 } 495 } 496 buf.erase(buf.begin()+total_bytes_read, buf.end()); // remove extra nulls 497 return total_bytes_read; 498 } 499 500 #ifndef __USING_WINDOWS__ 501 /*! 502 * Function: wait_for_child_exit 503 * Waits for the process with pid `pid` to exit 504 * and returns its status. 505 * Parameters: 506 * [in] pid : The pid of the process. 507 * [out] pair<int, int>: 508 * pair.first : Return code of the waitpid call. 509 * pair.second : Exit status of the process. 510 * 511 * NOTE: This is a blocking call as in, it will loop 512 * till the child is exited. 513 */ 514 static inline 515 std::pair<int, int> wait_for_child_exit(int pid) 516 { 517 int status = 0; 518 int ret = -1; 519 while (1) { 520 ret = waitpid(pid, &status, 0); 521 if (ret == -1) break; 522 if (ret == 0) continue; 523 return std::make_pair(ret, status); 524 } 525 526 return std::make_pair(ret, status); 527 } 528 #endif 529 530 } // end namespace util 531 532 533 534 /* ------------------------------- 535 * Popen Arguments 536 * ------------------------------- 537 */ 538 539 /*! 540 * Base class for all arguments involving string value. 541 */ 542 struct string_arg 543 { 544 string_arg(const char* arg): arg_value(arg) {} 545 string_arg(std::string&& arg): arg_value(std::move(arg)) {} 546 string_arg(const std::string& arg): arg_value(arg) {} 547 std::string arg_value; 548 }; 549 550 /*! 551 * Option to specify the executable name separately 552 * from the args sequence. 553 * In this case the cmd args must only contain the 554 * options required for this executable. 555 * 556 * Eg: executable{"ls"} 557 */ 558 struct executable: string_arg 559 { 560 template <typename T> 561 executable(T&& arg): string_arg(std::forward<T>(arg)) {} 562 }; 563 564 /*! 565 * Used for redirecting input/output/error 566 */ 567 enum IOTYPE { 568 STDOUT = 1, 569 STDERR, 570 PIPE, 571 }; 572 573 //TODO: A common base/interface for below stream structures ?? 574 575 /*! 576 * Option to specify the input channel for the child 577 * process. It can be: 578 * 1. An already open file descriptor. 579 * 2. A file name. 580 * 3. IOTYPE. Usual a PIPE 581 * 582 * Eg: input{PIPE} 583 * OR in case of redirection, output of another Popen 584 * input{popen.output()} 585 */ 586 struct input 587 { 588 // For an already existing file descriptor. 589 explicit input(int fd): rd_ch_(fd) {} 590 591 // FILE pointer. 592 explicit input (FILE* fp):input(subprocess_fileno(fp)) { assert(fp); } 593 594 explicit input(const char* filename) { 595 int fd = subprocess_open(filename, O_RDONLY); 596 if (fd == -1) throw OSError("File not found: ", errno); 597 rd_ch_ = fd; 598 } 599 explicit input(IOTYPE typ) { 600 assert (typ == PIPE && "STDOUT/STDERR not allowed"); 601 #ifndef __USING_WINDOWS__ 602 std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec(); 603 #endif 604 } 605 606 int rd_ch_ = -1; 607 int wr_ch_ = -1; 608 }; 609 610 611 /*! 612 * Option to specify the output channel for the child 613 * process. It can be: 614 * 1. An already open file descriptor. 615 * 2. A file name. 616 * 3. IOTYPE. Usually a PIPE. 617 * 618 * Eg: output{PIPE} 619 * OR output{"output.txt"} 620 */ 621 struct output 622 { 623 explicit output(int fd): wr_ch_(fd) {} 624 625 explicit output (FILE* fp):output(subprocess_fileno(fp)) { assert(fp); } 626 627 explicit output(const char* filename) { 628 int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); 629 if (fd == -1) throw OSError("File not found: ", errno); 630 wr_ch_ = fd; 631 } 632 explicit output(IOTYPE typ) { 633 assert (typ == PIPE && "STDOUT/STDERR not allowed"); 634 #ifndef __USING_WINDOWS__ 635 std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec(); 636 #endif 637 } 638 639 int rd_ch_ = -1; 640 int wr_ch_ = -1; 641 }; 642 643 644 /*! 645 * Option to specify the error channel for the child 646 * process. It can be: 647 * 1. An already open file descriptor. 648 * 2. A file name. 649 * 3. IOTYPE. Usually a PIPE or STDOUT 650 * 651 */ 652 struct error 653 { 654 explicit error(int fd): wr_ch_(fd) {} 655 656 explicit error(FILE* fp):error(subprocess_fileno(fp)) { assert(fp); } 657 658 explicit error(const char* filename) { 659 int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); 660 if (fd == -1) throw OSError("File not found: ", errno); 661 wr_ch_ = fd; 662 } 663 explicit error(IOTYPE typ) { 664 assert ((typ == PIPE || typ == STDOUT) && "STDERR not allowed"); 665 if (typ == PIPE) { 666 #ifndef __USING_WINDOWS__ 667 std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec(); 668 #endif 669 } else { 670 // Need to defer it till we have checked all arguments 671 deferred_ = true; 672 } 673 } 674 675 bool deferred_ = false; 676 int rd_ch_ = -1; 677 int wr_ch_ = -1; 678 }; 679 680 // ~~~~ End Popen Args ~~~~ 681 682 683 /*! 684 * class: Buffer 685 * This class is a very thin wrapper around std::vector<char> 686 * This is basically used to determine the length of the actual 687 * data stored inside the dynamically resized vector. 688 * 689 * This is what is returned as the output to the communicate 690 * function, so, users must know about this class. 691 * 692 * OutBuffer and ErrBuffer are just different typedefs to this class. 693 */ 694 class Buffer 695 { 696 public: 697 Buffer() = default; 698 explicit Buffer(size_t cap) { buf.resize(cap); } 699 void add_cap(size_t cap) { buf.resize(cap); } 700 701 public: 702 std::vector<char> buf; 703 size_t length = 0; 704 }; 705 706 // Buffer for storing output written to output fd 707 using OutBuffer = Buffer; 708 // Buffer for storing output written to error fd 709 using ErrBuffer = Buffer; 710 711 712 // Fwd Decl. 713 class Popen; 714 715 /*--------------------------------------------------- 716 * DETAIL NAMESPACE 717 *--------------------------------------------------- 718 */ 719 720 namespace detail { 721 /*! 722 * A helper class to Popen class for setting 723 * options as provided in the Popen constructor. 724 * This design allows us to _not_ have any fixed position 725 * to any arguments and specify them in a way similar to what 726 * can be done in python. 727 */ 728 struct ArgumentDeducer 729 { 730 ArgumentDeducer(Popen* p): popen_(p) {} 731 732 void set_option(executable&& exe); 733 void set_option(input&& inp); 734 void set_option(output&& out); 735 void set_option(error&& err); 736 737 private: 738 Popen* popen_ = nullptr; 739 }; 740 741 /*! 742 * A helper class to Popen. 743 * This takes care of all the fork-exec logic 744 * in the execute_child API. 745 */ 746 class Child 747 { 748 public: 749 Child(Popen* p, int err_wr_pipe): 750 parent_(p), 751 err_wr_pipe_(err_wr_pipe) 752 {} 753 754 void execute_child(); 755 756 private: 757 // Lets call it parent even though 758 // technically a bit incorrect 759 Popen* parent_ = nullptr; 760 int err_wr_pipe_ = -1; 761 }; 762 763 // Fwd Decl. 764 class Streams; 765 766 /*! 767 * A helper class to Streams. 768 * This takes care of management of communicating 769 * with the child process with the means of the correct 770 * file descriptor. 771 */ 772 class Communication 773 { 774 public: 775 Communication(Streams* stream): stream_(stream) 776 {} 777 Communication(const Communication&) = delete; 778 Communication& operator=(const Communication&) = delete; 779 Communication(Communication&&) = default; 780 Communication& operator=(Communication&&) = default; 781 public: 782 int send(const char* msg, size_t length); 783 int send(const std::vector<char>& msg); 784 785 std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length); 786 std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg) 787 { return communicate(msg.data(), msg.size()); } 788 789 void set_out_buf_cap(size_t cap) { out_buf_cap_ = cap; } 790 void set_err_buf_cap(size_t cap) { err_buf_cap_ = cap; } 791 792 private: 793 std::pair<OutBuffer, ErrBuffer> communicate_threaded( 794 const char* msg, size_t length); 795 796 private: 797 Streams* stream_; 798 size_t out_buf_cap_ = DEFAULT_BUF_CAP_BYTES; 799 size_t err_buf_cap_ = DEFAULT_BUF_CAP_BYTES; 800 }; 801 802 803 804 /*! 805 * This is a helper class to Popen. 806 * It takes care of management of all the file descriptors 807 * and file pointers. 808 * It dispatches of the communication aspects to the 809 * Communication class. 810 * Read through the data members to understand about the 811 * various file descriptors used. 812 */ 813 class Streams 814 { 815 public: 816 Streams():comm_(this) {} 817 Streams(const Streams&) = delete; 818 Streams& operator=(const Streams&) = delete; 819 Streams(Streams&&) = default; 820 Streams& operator=(Streams&&) = default; 821 822 public: 823 void setup_comm_channels(); 824 825 void cleanup_fds() 826 { 827 if (write_to_child_ != -1 && read_from_parent_ != -1) { 828 subprocess_close(write_to_child_); 829 } 830 if (write_to_parent_ != -1 && read_from_child_ != -1) { 831 subprocess_close(read_from_child_); 832 } 833 if (err_write_ != -1 && err_read_ != -1) { 834 subprocess_close(err_read_); 835 } 836 } 837 838 void close_parent_fds() 839 { 840 if (write_to_child_ != -1) subprocess_close(write_to_child_); 841 if (read_from_child_ != -1) subprocess_close(read_from_child_); 842 if (err_read_ != -1) subprocess_close(err_read_); 843 } 844 845 void close_child_fds() 846 { 847 if (write_to_parent_ != -1) subprocess_close(write_to_parent_); 848 if (read_from_parent_ != -1) subprocess_close(read_from_parent_); 849 if (err_write_ != -1) subprocess_close(err_write_); 850 } 851 852 FILE* input() { return input_.get(); } 853 FILE* output() { return output_.get(); } 854 FILE* error() { return error_.get(); } 855 856 void input(FILE* fp) { input_.reset(fp, fclose); } 857 void output(FILE* fp) { output_.reset(fp, fclose); } 858 void error(FILE* fp) { error_.reset(fp, fclose); } 859 860 void set_out_buf_cap(size_t cap) { comm_.set_out_buf_cap(cap); } 861 void set_err_buf_cap(size_t cap) { comm_.set_err_buf_cap(cap); } 862 863 public: /* Communication forwarding API's */ 864 int send(const char* msg, size_t length) 865 { return comm_.send(msg, length); } 866 867 int send(const std::vector<char>& msg) 868 { return comm_.send(msg); } 869 870 std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length) 871 { return comm_.communicate(msg, length); } 872 873 std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg) 874 { return comm_.communicate(msg); } 875 876 877 public:// Yes they are public 878 879 std::shared_ptr<FILE> input_ = nullptr; 880 std::shared_ptr<FILE> output_ = nullptr; 881 std::shared_ptr<FILE> error_ = nullptr; 882 883 #ifdef __USING_WINDOWS__ 884 HANDLE g_hChildStd_IN_Rd = nullptr; 885 HANDLE g_hChildStd_IN_Wr = nullptr; 886 HANDLE g_hChildStd_OUT_Rd = nullptr; 887 HANDLE g_hChildStd_OUT_Wr = nullptr; 888 HANDLE g_hChildStd_ERR_Rd = nullptr; 889 HANDLE g_hChildStd_ERR_Wr = nullptr; 890 #endif 891 892 // Pipes for communicating with child 893 894 // Emulates stdin 895 int write_to_child_ = -1; // Parent owned descriptor 896 int read_from_parent_ = -1; // Child owned descriptor 897 898 // Emulates stdout 899 int write_to_parent_ = -1; // Child owned descriptor 900 int read_from_child_ = -1; // Parent owned descriptor 901 902 // Emulates stderr 903 int err_write_ = -1; // Write error to parent (Child owned) 904 int err_read_ = -1; // Read error from child (Parent owned) 905 906 private: 907 Communication comm_; 908 }; 909 910 } // end namespace detail 911 912 913 914 /*! 915 * class: Popen 916 * This is the single most important class in the whole library 917 * and glues together all the helper classes to provide a common 918 * interface to the client. 919 * 920 * API's provided by the class: 921 * Popen({"cmd"}, output{..}, error{..}, ....) 922 * Command provided as a sequence. 923 * Popen("cmd arg1", output{..}, error{..}, ....) 924 * Command provided in a single string. 925 * wait() - Wait for the child to exit. 926 * retcode() - The return code of the exited child. 927 * send(...) - Send input to the input channel of the child. 928 * communicate(...) - Get the output/error from the child and close the channels 929 * from the parent side. 930 */ 931 class Popen 932 { 933 public: 934 friend struct detail::ArgumentDeducer; 935 friend class detail::Child; 936 937 template <typename... Args> 938 Popen(const std::string& cmd_args, Args&& ...args): 939 args_(cmd_args) 940 { 941 vargs_ = util::split(cmd_args); 942 init_args(std::forward<Args>(args)...); 943 944 // Setup the communication channels of the Popen class 945 stream_.setup_comm_channels(); 946 947 execute_process(); 948 } 949 950 template <typename... Args> 951 Popen(std::initializer_list<const char*> cmd_args, Args&& ...args) 952 { 953 vargs_.insert(vargs_.end(), cmd_args.begin(), cmd_args.end()); 954 init_args(std::forward<Args>(args)...); 955 956 // Setup the communication channels of the Popen class 957 stream_.setup_comm_channels(); 958 959 execute_process(); 960 } 961 962 template <typename... Args> 963 Popen(std::vector<std::string> vargs_, Args &&... args) : vargs_(vargs_) 964 { 965 init_args(std::forward<Args>(args)...); 966 967 // Setup the communication channels of the Popen class 968 stream_.setup_comm_channels(); 969 970 execute_process(); 971 } 972 973 int retcode() const noexcept { return retcode_; } 974 975 int wait() noexcept(false); 976 977 void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); } 978 979 void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); } 980 981 int send(const char* msg, size_t length) 982 { return stream_.send(msg, length); } 983 984 int send(const std::string& msg) 985 { return send(msg.c_str(), msg.size()); } 986 987 int send(const std::vector<char>& msg) 988 { return stream_.send(msg); } 989 990 std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length) 991 { 992 auto res = stream_.communicate(msg, length); 993 retcode_ = wait(); 994 return res; 995 } 996 997 std::pair<OutBuffer, ErrBuffer> communicate(const std::string& msg) 998 { 999 return communicate(msg.c_str(), msg.size()); 1000 } 1001 1002 std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg) 1003 { 1004 auto res = stream_.communicate(msg); 1005 retcode_ = wait(); 1006 return res; 1007 } 1008 1009 std::pair<OutBuffer, ErrBuffer> communicate() 1010 { 1011 return communicate(nullptr, 0); 1012 } 1013 1014 private: 1015 template <typename F, typename... Args> 1016 void init_args(F&& farg, Args&&... args); 1017 void init_args(); 1018 void populate_c_argv(); 1019 void execute_process() noexcept(false); 1020 1021 private: 1022 detail::Streams stream_; 1023 1024 #ifdef __USING_WINDOWS__ 1025 HANDLE process_handle_; 1026 std::future<void> cleanup_future_; 1027 #endif 1028 1029 std::string exe_name_; 1030 1031 // Command in string format 1032 std::string args_; 1033 // Command provided as sequence 1034 std::vector<std::string> vargs_; 1035 std::vector<char*> cargv_; 1036 1037 // Pid of the child process 1038 int child_pid_ = -1; 1039 1040 int retcode_ = -1; 1041 }; 1042 1043 inline void Popen::init_args() { 1044 populate_c_argv(); 1045 } 1046 1047 template <typename F, typename... Args> 1048 inline void Popen::init_args(F&& farg, Args&&... args) 1049 { 1050 detail::ArgumentDeducer argd(this); 1051 argd.set_option(std::forward<F>(farg)); 1052 init_args(std::forward<Args>(args)...); 1053 } 1054 1055 inline void Popen::populate_c_argv() 1056 { 1057 cargv_.clear(); 1058 cargv_.reserve(vargs_.size() + 1); 1059 for (auto& arg : vargs_) cargv_.push_back(&arg[0]); 1060 cargv_.push_back(nullptr); 1061 } 1062 1063 inline int Popen::wait() noexcept(false) 1064 { 1065 #ifdef __USING_WINDOWS__ 1066 int ret = WaitForSingleObject(process_handle_, INFINITE); 1067 1068 // WaitForSingleObject with INFINITE should only return when process has signaled 1069 if (ret != WAIT_OBJECT_0) { 1070 throw OSError("Unexpected return code from WaitForSingleObject", 0); 1071 } 1072 1073 DWORD dretcode_; 1074 1075 if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_)) 1076 throw OSError("Failed during call to GetExitCodeProcess", 0); 1077 1078 CloseHandle(process_handle_); 1079 1080 return (int)dretcode_; 1081 #else 1082 int ret, status; 1083 std::tie(ret, status) = util::wait_for_child_exit(child_pid_); 1084 if (ret == -1) { 1085 if (errno != ECHILD) throw OSError("waitpid failed", errno); 1086 return 0; 1087 } 1088 if (WIFEXITED(status)) return WEXITSTATUS(status); 1089 if (WIFSIGNALED(status)) return WTERMSIG(status); 1090 else return 255; 1091 1092 return 0; 1093 #endif 1094 } 1095 1096 inline void Popen::execute_process() noexcept(false) 1097 { 1098 #ifdef __USING_WINDOWS__ 1099 if (exe_name_.length()) { 1100 this->vargs_.insert(this->vargs_.begin(), this->exe_name_); 1101 this->populate_c_argv(); 1102 } 1103 this->exe_name_ = vargs_[0]; 1104 1105 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; 1106 std::wstring argument; 1107 std::wstring command_line; 1108 bool first_arg = true; 1109 1110 for (auto arg : this->vargs_) { 1111 if (!first_arg) { 1112 command_line += L" "; 1113 } else { 1114 first_arg = false; 1115 } 1116 argument = converter.from_bytes(arg); 1117 util::quote_argument(argument, command_line, false); 1118 } 1119 1120 // CreateProcessW can modify szCmdLine so we allocate needed memory 1121 wchar_t *szCmdline = new wchar_t[command_line.size() + 1]; 1122 wcscpy_s(szCmdline, command_line.size() + 1, command_line.c_str()); 1123 PROCESS_INFORMATION piProcInfo; 1124 STARTUPINFOW siStartInfo; 1125 BOOL bSuccess = FALSE; 1126 DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW; 1127 1128 // Set up members of the PROCESS_INFORMATION structure. 1129 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); 1130 1131 // Set up members of the STARTUPINFOW structure. 1132 // This structure specifies the STDIN and STDOUT handles for redirection. 1133 1134 ZeroMemory(&siStartInfo, sizeof(STARTUPINFOW)); 1135 siStartInfo.cb = sizeof(STARTUPINFOW); 1136 1137 siStartInfo.hStdError = this->stream_.g_hChildStd_ERR_Wr; 1138 siStartInfo.hStdOutput = this->stream_.g_hChildStd_OUT_Wr; 1139 siStartInfo.hStdInput = this->stream_.g_hChildStd_IN_Rd; 1140 1141 siStartInfo.dwFlags |= STARTF_USESTDHANDLES; 1142 1143 // Create the child process. 1144 bSuccess = CreateProcessW(NULL, 1145 szCmdline, // command line 1146 NULL, // process security attributes 1147 NULL, // primary thread security attributes 1148 TRUE, // handles are inherited 1149 creation_flags, // creation flags 1150 NULL, // use parent's environment 1151 NULL, // use parent's current directory 1152 &siStartInfo, // STARTUPINFOW pointer 1153 &piProcInfo); // receives PROCESS_INFORMATION 1154 1155 // If an error occurs, exit the application. 1156 if (!bSuccess) { 1157 DWORD errorMessageID = ::GetLastError(); 1158 throw CalledProcessError("CreateProcess failed: " + util::get_last_error(errorMessageID), errorMessageID); 1159 } 1160 1161 CloseHandle(piProcInfo.hThread); 1162 1163 /* 1164 TODO: use common apis to close linux handles 1165 */ 1166 1167 this->process_handle_ = piProcInfo.hProcess; 1168 1169 this->cleanup_future_ = std::async(std::launch::async, [this] { 1170 WaitForSingleObject(this->process_handle_, INFINITE); 1171 1172 CloseHandle(this->stream_.g_hChildStd_ERR_Wr); 1173 CloseHandle(this->stream_.g_hChildStd_OUT_Wr); 1174 CloseHandle(this->stream_.g_hChildStd_IN_Rd); 1175 }); 1176 1177 /* 1178 NOTE: In the linux version, there is a check to make sure that the process 1179 has been started. Here, we do nothing because CreateProcess will throw 1180 if we fail to create the process. 1181 */ 1182 1183 1184 #else 1185 1186 int err_rd_pipe, err_wr_pipe; 1187 std::tie(err_rd_pipe, err_wr_pipe) = util::pipe_cloexec(); 1188 1189 if (exe_name_.length()) { 1190 vargs_.insert(vargs_.begin(), exe_name_); 1191 populate_c_argv(); 1192 } 1193 exe_name_ = vargs_[0]; 1194 1195 child_pid_ = fork(); 1196 1197 if (child_pid_ < 0) { 1198 subprocess_close(err_rd_pipe); 1199 subprocess_close(err_wr_pipe); 1200 throw OSError("fork failed", errno); 1201 } 1202 1203 if (child_pid_ == 0) 1204 { 1205 // Close descriptors belonging to parent 1206 stream_.close_parent_fds(); 1207 1208 //Close the read end of the error pipe 1209 subprocess_close(err_rd_pipe); 1210 1211 detail::Child chld(this, err_wr_pipe); 1212 chld.execute_child(); 1213 } 1214 else 1215 { 1216 subprocess_close(err_wr_pipe);// close child side of pipe, else get stuck in read below 1217 1218 stream_.close_child_fds(); 1219 1220 try { 1221 char err_buf[SP_MAX_ERR_BUF_SIZ] = {0,}; 1222 1223 FILE* err_fp = fdopen(err_rd_pipe, "r"); 1224 if (!err_fp) { 1225 subprocess_close(err_rd_pipe); 1226 throw OSError("fdopen failed", errno); 1227 } 1228 int read_bytes = util::read_atmost_n(err_fp, err_buf, SP_MAX_ERR_BUF_SIZ); 1229 fclose(err_fp); 1230 1231 if (read_bytes || strlen(err_buf)) { 1232 // Call waitpid to reap the child process 1233 // waitpid suspends the calling process until the 1234 // child terminates. 1235 int retcode = wait(); 1236 1237 // Throw whatever information we have about child failure 1238 throw CalledProcessError(err_buf, retcode); 1239 } 1240 } catch (std::exception& exp) { 1241 stream_.cleanup_fds(); 1242 throw; 1243 } 1244 1245 } 1246 #endif 1247 } 1248 1249 namespace detail { 1250 1251 inline void ArgumentDeducer::set_option(executable&& exe) { 1252 popen_->exe_name_ = std::move(exe.arg_value); 1253 } 1254 1255 inline void ArgumentDeducer::set_option(input&& inp) { 1256 if (inp.rd_ch_ != -1) popen_->stream_.read_from_parent_ = inp.rd_ch_; 1257 if (inp.wr_ch_ != -1) popen_->stream_.write_to_child_ = inp.wr_ch_; 1258 } 1259 1260 inline void ArgumentDeducer::set_option(output&& out) { 1261 if (out.wr_ch_ != -1) popen_->stream_.write_to_parent_ = out.wr_ch_; 1262 if (out.rd_ch_ != -1) popen_->stream_.read_from_child_ = out.rd_ch_; 1263 } 1264 1265 inline void ArgumentDeducer::set_option(error&& err) { 1266 if (err.deferred_) { 1267 if (popen_->stream_.write_to_parent_) { 1268 popen_->stream_.err_write_ = popen_->stream_.write_to_parent_; 1269 } else { 1270 throw std::runtime_error("Set output before redirecting error to output"); 1271 } 1272 } 1273 if (err.wr_ch_ != -1) popen_->stream_.err_write_ = err.wr_ch_; 1274 if (err.rd_ch_ != -1) popen_->stream_.err_read_ = err.rd_ch_; 1275 } 1276 1277 1278 inline void Child::execute_child() { 1279 #ifndef __USING_WINDOWS__ 1280 int sys_ret = -1; 1281 auto& stream = parent_->stream_; 1282 1283 try { 1284 if (stream.write_to_parent_ == 0) 1285 stream.write_to_parent_ = dup(stream.write_to_parent_); 1286 1287 if (stream.err_write_ == 0 || stream.err_write_ == 1) 1288 stream.err_write_ = dup(stream.err_write_); 1289 1290 // Make the child owned descriptors as the 1291 // stdin, stdout and stderr for the child process 1292 auto _dup2_ = [](int fd, int to_fd) { 1293 if (fd == to_fd) { 1294 // dup2 syscall does not reset the 1295 // CLOEXEC flag if the descriptors 1296 // provided to it are same. 1297 // But, we need to reset the CLOEXEC 1298 // flag as the provided descriptors 1299 // are now going to be the standard 1300 // input, output and error 1301 util::set_clo_on_exec(fd, false); 1302 } else if(fd != -1) { 1303 int res = dup2(fd, to_fd); 1304 if (res == -1) throw OSError("dup2 failed", errno); 1305 } 1306 }; 1307 1308 // Create the standard streams 1309 _dup2_(stream.read_from_parent_, 0); // Input stream 1310 _dup2_(stream.write_to_parent_, 1); // Output stream 1311 _dup2_(stream.err_write_, 2); // Error stream 1312 1313 // Close the duped descriptors 1314 if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2) 1315 subprocess_close(stream.read_from_parent_); 1316 1317 if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2) 1318 subprocess_close(stream.write_to_parent_); 1319 1320 if (stream.err_write_ != -1 && stream.err_write_ > 2) 1321 subprocess_close(stream.err_write_); 1322 1323 // Replace the current image with the executable 1324 sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data()); 1325 1326 if (sys_ret == -1) throw OSError("execve failed", errno); 1327 1328 } catch (const OSError& exp) { 1329 // Just write the exception message 1330 // TODO: Give back stack trace ? 1331 std::string err_msg(exp.what()); 1332 //ATTN: Can we do something on error here ? 1333 util::write_n(err_wr_pipe_, err_msg.c_str(), err_msg.length()); 1334 } 1335 1336 // Calling application would not get this 1337 // exit failure 1338 _exit (EXIT_FAILURE); 1339 #endif 1340 } 1341 1342 1343 inline void Streams::setup_comm_channels() 1344 { 1345 #ifdef __USING_WINDOWS__ 1346 util::configure_pipe(&this->g_hChildStd_IN_Rd, &this->g_hChildStd_IN_Wr, &this->g_hChildStd_IN_Wr); 1347 this->input(util::file_from_handle(this->g_hChildStd_IN_Wr, "w")); 1348 this->write_to_child_ = subprocess_fileno(this->input()); 1349 1350 util::configure_pipe(&this->g_hChildStd_OUT_Rd, &this->g_hChildStd_OUT_Wr, &this->g_hChildStd_OUT_Rd); 1351 this->output(util::file_from_handle(this->g_hChildStd_OUT_Rd, "r")); 1352 this->read_from_child_ = subprocess_fileno(this->output()); 1353 1354 util::configure_pipe(&this->g_hChildStd_ERR_Rd, &this->g_hChildStd_ERR_Wr, &this->g_hChildStd_ERR_Rd); 1355 this->error(util::file_from_handle(this->g_hChildStd_ERR_Rd, "r")); 1356 this->err_read_ = subprocess_fileno(this->error()); 1357 #else 1358 1359 if (write_to_child_ != -1) input(fdopen(write_to_child_, "wb")); 1360 if (read_from_child_ != -1) output(fdopen(read_from_child_, "rb")); 1361 if (err_read_ != -1) error(fdopen(err_read_, "rb")); 1362 1363 auto handles = {input(), output(), error()}; 1364 1365 for (auto& h : handles) { 1366 if (h == nullptr) continue; 1367 setvbuf(h, nullptr, _IONBF, BUFSIZ); 1368 } 1369 #endif 1370 } 1371 1372 inline int Communication::send(const char* msg, size_t length) 1373 { 1374 if (stream_->input() == nullptr) return -1; 1375 return std::fwrite(msg, sizeof(char), length, stream_->input()); 1376 } 1377 1378 inline int Communication::send(const std::vector<char>& msg) 1379 { 1380 return send(msg.data(), msg.size()); 1381 } 1382 1383 inline std::pair<OutBuffer, ErrBuffer> 1384 Communication::communicate(const char* msg, size_t length) 1385 { 1386 // Optimization from subprocess.py 1387 // If we are using one pipe, or no pipe 1388 // at all, using select() or threads is unnecessary. 1389 auto hndls = {stream_->input(), stream_->output(), stream_->error()}; 1390 int count = std::count(std::begin(hndls), std::end(hndls), nullptr); 1391 const int len_conv = length; 1392 1393 if (count >= 2) { 1394 OutBuffer obuf; 1395 ErrBuffer ebuf; 1396 if (stream_->input()) { 1397 if (msg) { 1398 int wbytes = std::fwrite(msg, sizeof(char), length, stream_->input()); 1399 if (wbytes < len_conv) { 1400 if (errno != EPIPE && errno != EINVAL) { 1401 throw OSError("fwrite error", errno); 1402 } 1403 } 1404 } 1405 // Close the input stream 1406 stream_->input_.reset(); 1407 } else if (stream_->output()) { 1408 // Read till EOF 1409 // ATTN: This could be blocking, if the process 1410 // at the other end screws up, we get screwed as well 1411 obuf.add_cap(out_buf_cap_); 1412 1413 int rbytes = util::read_all( 1414 stream_->output(), 1415 obuf.buf); 1416 1417 if (rbytes == -1) { 1418 throw OSError("read to obuf failed", errno); 1419 } 1420 1421 obuf.length = rbytes; 1422 // Close the output stream 1423 stream_->output_.reset(); 1424 1425 } else if (stream_->error()) { 1426 // Same screwness applies here as well 1427 ebuf.add_cap(err_buf_cap_); 1428 1429 int rbytes = util::read_atmost_n( 1430 stream_->error(), 1431 ebuf.buf.data(), 1432 ebuf.buf.size()); 1433 1434 if (rbytes == -1) { 1435 throw OSError("read to ebuf failed", errno); 1436 } 1437 1438 ebuf.length = rbytes; 1439 // Close the error stream 1440 stream_->error_.reset(); 1441 } 1442 return std::make_pair(std::move(obuf), std::move(ebuf)); 1443 } 1444 1445 return communicate_threaded(msg, length); 1446 } 1447 1448 1449 inline std::pair<OutBuffer, ErrBuffer> 1450 Communication::communicate_threaded(const char* msg, size_t length) 1451 { 1452 OutBuffer obuf; 1453 ErrBuffer ebuf; 1454 std::future<int> out_fut, err_fut; 1455 const int length_conv = length; 1456 1457 if (stream_->output()) { 1458 obuf.add_cap(out_buf_cap_); 1459 1460 out_fut = std::async(std::launch::async, 1461 [&obuf, this] { 1462 return util::read_all(this->stream_->output(), obuf.buf); 1463 }); 1464 } 1465 if (stream_->error()) { 1466 ebuf.add_cap(err_buf_cap_); 1467 1468 err_fut = std::async(std::launch::async, 1469 [&ebuf, this] { 1470 return util::read_all(this->stream_->error(), ebuf.buf); 1471 }); 1472 } 1473 if (stream_->input()) { 1474 if (msg) { 1475 int wbytes = std::fwrite(msg, sizeof(char), length, stream_->input()); 1476 if (wbytes < length_conv) { 1477 if (errno != EPIPE && errno != EINVAL) { 1478 throw OSError("fwrite error", errno); 1479 } 1480 } 1481 } 1482 stream_->input_.reset(); 1483 } 1484 1485 if (out_fut.valid()) { 1486 int res = out_fut.get(); 1487 if (res != -1) obuf.length = res; 1488 else obuf.length = 0; 1489 } 1490 if (err_fut.valid()) { 1491 int res = err_fut.get(); 1492 if (res != -1) ebuf.length = res; 1493 else ebuf.length = 0; 1494 } 1495 1496 return std::make_pair(std::move(obuf), std::move(ebuf)); 1497 } 1498 1499 } // end namespace detail 1500 1501 } 1502 1503 #endif // BITCOIN_UTIL_SUBPROCESS_H