| 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 | |