1 | #pragma once |
2 | |
3 | #include <memory> |
4 | #include <IO/ReadBufferFromFile.h> |
5 | #include <IO/WriteBufferFromFile.h> |
6 | |
7 | |
8 | namespace DB |
9 | { |
10 | |
11 | |
12 | /** Lets you run the command, |
13 | * read it stdout and stderr; write to stdin; |
14 | * wait for completion. |
15 | * |
16 | * The implementation is similar to the popen function from POSIX (see libc source code). |
17 | * |
18 | * The most important difference: uses vfork instead of fork. |
19 | * This is done because fork does not work (with a memory shortage error), |
20 | * with some overcommit settings, if the address space of the process is more than half the amount of available memory. |
21 | * Also, changing memory maps - a fairly resource-intensive operation. |
22 | * |
23 | * The second difference - allows to work simultaneously with stdin, and with stdout, and with stderr of running process, |
24 | * and also to obtain the return code and completion status. |
25 | */ |
26 | class ShellCommand |
27 | { |
28 | private: |
29 | pid_t pid; |
30 | bool wait_called = false; |
31 | bool terminate_in_destructor; |
32 | |
33 | Poco::Logger * log; |
34 | |
35 | ShellCommand(pid_t pid_, int in_fd_, int out_fd_, int err_fd_, bool terminate_in_destructor_); |
36 | |
37 | static std::unique_ptr<ShellCommand> executeImpl(const char * filename, char * const argv[], bool pipe_stdin_only, bool terminate_in_destructor); |
38 | |
39 | public: |
40 | WriteBufferFromFile in; /// If the command reads from stdin, do not forget to call in.close() after writing all the data there. |
41 | ReadBufferFromFile out; |
42 | ReadBufferFromFile err; |
43 | |
44 | ~ShellCommand(); |
45 | |
46 | /// Run the command using /bin/sh -c. |
47 | /// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process. |
48 | static std::unique_ptr<ShellCommand> execute(const std::string & command, bool pipe_stdin_only = false, bool terminate_in_destructor = false); |
49 | |
50 | /// Run the executable with the specified arguments. `arguments` - without argv[0]. |
51 | /// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process. |
52 | static std::unique_ptr<ShellCommand> executeDirect(const std::string & path, const std::vector<std::string> & arguments, bool terminate_in_destructor = false); |
53 | |
54 | /// Wait for the process to end, throw an exception if the code is not 0 or if the process was not completed by itself. |
55 | void wait(); |
56 | |
57 | /// Wait for the process to finish, see the return code. To throw an exception if the process was not completed independently. |
58 | int tryWait(); |
59 | }; |
60 | |
61 | |
62 | } |
63 | |