#pragma once #include #include #include namespace DB { /** Lets you run the command, * read it stdout and stderr; write to stdin; * wait for completion. * * The implementation is similar to the popen function from POSIX (see libc source code). * * The most important difference: uses vfork instead of fork. * This is done because fork does not work (with a memory shortage error), * with some overcommit settings, if the address space of the process is more than half the amount of available memory. * Also, changing memory maps - a fairly resource-intensive operation. * * The second difference - allows to work simultaneously with stdin, and with stdout, and with stderr of running process, * and also to obtain the return code and completion status. */ class ShellCommand { private: pid_t pid; bool wait_called = false; bool terminate_in_destructor; Poco::Logger * log; ShellCommand(pid_t pid_, int in_fd_, int out_fd_, int err_fd_, bool terminate_in_destructor_); static std::unique_ptr executeImpl(const char * filename, char * const argv[], bool pipe_stdin_only, bool terminate_in_destructor); public: WriteBufferFromFile in; /// If the command reads from stdin, do not forget to call in.close() after writing all the data there. ReadBufferFromFile out; ReadBufferFromFile err; ~ShellCommand(); /// Run the command using /bin/sh -c. /// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process. static std::unique_ptr execute(const std::string & command, bool pipe_stdin_only = false, bool terminate_in_destructor = false); /// Run the executable with the specified arguments. `arguments` - without argv[0]. /// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process. static std::unique_ptr executeDirect(const std::string & path, const std::vector & arguments, bool terminate_in_destructor = false); /// Wait for the process to end, throw an exception if the code is not 0 or if the process was not completed by itself. void wait(); /// Wait for the process to finish, see the return code. To throw an exception if the process was not completed independently. int tryWait(); }; }