subprocess.h raw

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