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