1#pragma once
2
3#include <memory>
4#include <IO/ReadBufferFromFile.h>
5#include <IO/WriteBufferFromFile.h>
6
7
8namespace 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 */
26class ShellCommand
27{
28private:
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
39public:
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