Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

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