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