2016-06-07 08:23:15 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <memory>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/ReadBufferFromFile.h>
|
|
|
|
#include <IO/WriteBufferFromFile.h>
|
2022-07-20 20:30:16 +00:00
|
|
|
#include <unordered_map>
|
2016-06-07 08:23:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2017-05-07 20:25:26 +00:00
|
|
|
/** Lets you run the command,
|
2017-05-10 04:00:19 +00:00
|
|
|
* read it stdout and stderr; write to stdin;
|
|
|
|
* wait for completion.
|
2016-06-07 08:23:15 +00:00
|
|
|
*
|
2017-05-07 20:25:26 +00:00
|
|
|
* The implementation is similar to the popen function from POSIX (see libc source code).
|
2016-06-07 08:23:15 +00:00
|
|
|
*
|
2017-05-07 20:25:26 +00:00
|
|
|
* 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.
|
2016-06-07 08:23:15 +00:00
|
|
|
*
|
2017-05-10 04:00:19 +00:00
|
|
|
* 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.
|
2016-06-07 08:23:15 +00:00
|
|
|
*/
|
2021-08-25 19:30:22 +00:00
|
|
|
class ShellCommand final
|
2021-03-03 19:34:25 +00:00
|
|
|
{
|
2021-08-25 19:30:22 +00:00
|
|
|
public:
|
|
|
|
~ShellCommand();
|
|
|
|
|
|
|
|
struct DestructorStrategy final
|
2021-03-03 19:34:25 +00:00
|
|
|
{
|
2022-12-28 19:07:26 +00:00
|
|
|
explicit DestructorStrategy(bool terminate_in_destructor_, int termination_signal_, size_t wait_for_normal_exit_before_termination_seconds_ = 0)
|
|
|
|
: terminate_in_destructor(terminate_in_destructor_), termination_signal(termination_signal_)
|
2021-08-25 19:30:22 +00:00
|
|
|
, wait_for_normal_exit_before_termination_seconds(wait_for_normal_exit_before_termination_seconds_)
|
|
|
|
{
|
|
|
|
}
|
2021-03-03 19:34:25 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
bool terminate_in_destructor;
|
2022-12-28 19:07:26 +00:00
|
|
|
int termination_signal;
|
2021-03-03 19:34:25 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
/// If terminate in destructor is true, command will wait until send SIGTERM signal to created process
|
|
|
|
size_t wait_for_normal_exit_before_termination_seconds = 0;
|
|
|
|
};
|
2021-03-03 19:34:25 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
struct Config
|
|
|
|
{
|
2022-03-11 21:47:28 +00:00
|
|
|
Config(const std::string & command_) /// NOLINT
|
2021-08-25 19:30:22 +00:00
|
|
|
: command(command_)
|
|
|
|
{}
|
2021-03-03 19:34:25 +00:00
|
|
|
|
2022-03-11 21:47:28 +00:00
|
|
|
Config(const char * command_) /// NOLINT
|
2021-08-25 19:30:22 +00:00
|
|
|
: command(command_)
|
|
|
|
{}
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
std::string command;
|
2018-11-23 08:08:35 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
std::vector<std::string> arguments;
|
2019-12-09 14:49:21 +00:00
|
|
|
|
2021-08-28 19:47:59 +00:00
|
|
|
std::vector<int> read_fds;
|
2019-09-25 14:06:38 +00:00
|
|
|
|
2021-08-28 19:47:59 +00:00
|
|
|
std::vector<int> write_fds;
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2021-08-25 19:30:22 +00:00
|
|
|
bool pipe_stdin_only = false;
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2022-12-28 19:07:26 +00:00
|
|
|
DestructorStrategy terminate_in_destructor_strategy = DestructorStrategy(false, 0);
|
2021-08-25 19:30:22 +00:00
|
|
|
};
|
2017-09-07 00:12:39 +00:00
|
|
|
|
2018-11-23 08:08:35 +00:00
|
|
|
/// Run the command using /bin/sh -c.
|
|
|
|
/// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process.
|
2021-08-25 19:30:22 +00:00
|
|
|
static std::unique_ptr<ShellCommand> execute(const Config & config);
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-05-07 20:25:26 +00:00
|
|
|
/// Run the executable with the specified arguments. `arguments` - without argv[0].
|
2018-11-23 08:08:35 +00:00
|
|
|
/// If terminate_in_destructor is true, send terminate signal in destructor and don't wait process.
|
2021-08-25 19:30:22 +00:00
|
|
|
static std::unique_ptr<ShellCommand> executeDirect(const Config & config);
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-05-07 20:25:26 +00:00
|
|
|
/// Wait for the process to end, throw an exception if the code is not 0 or if the process was not completed by itself.
|
2016-06-07 08:23:15 +00:00
|
|
|
void wait();
|
|
|
|
|
2017-05-07 20:25:26 +00:00
|
|
|
/// Wait for the process to finish, see the return code. To throw an exception if the process was not completed independently.
|
2016-06-07 08:23:15 +00:00
|
|
|
int tryWait();
|
2021-08-25 19:30:22 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-08-28 19:47:59 +00:00
|
|
|
std::unordered_map<int, ReadBufferFromFile> read_fds;
|
|
|
|
std::unordered_map<int, WriteBufferFromFile> write_fds;
|
2021-08-25 19:30:22 +00:00
|
|
|
private:
|
|
|
|
|
|
|
|
pid_t pid;
|
2021-08-28 19:47:59 +00:00
|
|
|
Config config;
|
2021-08-25 19:30:22 +00:00
|
|
|
bool wait_called = false;
|
|
|
|
|
2021-08-28 19:47:59 +00:00
|
|
|
ShellCommand(pid_t pid_, int & in_fd_, int & out_fd_, int & err_fd_, const Config & config);
|
2021-08-25 19:30:22 +00:00
|
|
|
|
|
|
|
bool tryWaitProcessWithTimeout(size_t timeout_in_seconds);
|
|
|
|
|
|
|
|
static Poco::Logger * getLogger();
|
|
|
|
|
|
|
|
/// Print command name and the list of arguments to log. NOTE: No escaping of arguments is performed.
|
|
|
|
static void logCommand(const char * filename, char * const argv[]);
|
|
|
|
|
|
|
|
static std::unique_ptr<ShellCommand> executeImpl(const char * filename, char * const argv[], const Config & config);
|
2016-06-07 08:23:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|