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