/ src / util / subprocess.h
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 &copy; 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