diff options
author | Oliver Reiche <oliver.reiche@huawei.com> | 2022-03-07 18:23:53 +0100 |
---|---|---|
committer | Oliver Reiche <oliver.reiche@huawei.com> | 2022-03-08 13:46:08 +0100 |
commit | 28abe1bf4d8c16af92e1ef3dc1f267399f0690b9 (patch) | |
tree | a88380091984fdabe288caffb0dc814543a613d5 /src/buildtool/file_system/system_command.hpp | |
parent | 6f44f11a9a063d2f8f10a99c3531325e0fabead8 (diff) | |
download | justbuild-28abe1bf4d8c16af92e1ef3dc1f267399f0690b9.tar.gz |
SystemCommand: Move to new module "src/buildtool/system"
Diffstat (limited to 'src/buildtool/file_system/system_command.hpp')
-rw-r--r-- | src/buildtool/file_system/system_command.hpp | 202 |
1 files changed, 0 insertions, 202 deletions
diff --git a/src/buildtool/file_system/system_command.hpp b/src/buildtool/file_system/system_command.hpp deleted file mode 100644 index 66470ade..00000000 --- a/src/buildtool/file_system/system_command.hpp +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_EXECUTION_SYSTEM_HPP -#define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_EXECUTION_SYSTEM_HPP - -#include <array> -#include <cstdio> -#include <cstring> // for strerror() -#include <iterator> -#include <map> -#include <optional> -#include <sstream> -#include <string> -#include <vector> - -#include <sys/wait.h> -#include <unistd.h> - -#include "gsl-lite/gsl-lite.hpp" -#include "src/buildtool/file_system/file_system_manager.hpp" -#include "src/buildtool/logging/logger.hpp" - -/// \brief Execute system commands and obtain stdout, stderr and return value. -/// Subsequent commands are context free and are not affected by previous -/// commands. This class is not thread-safe. -class SystemCommand { - public: - struct ExecOutput { - int return_value{}; - std::filesystem::path stdout_file{}; - std::filesystem::path stderr_file{}; - }; - - /// \brief Create execution system with name. - explicit SystemCommand(std::string name) : logger_{std::move(name)} {} - - /// \brief Execute command and arguments. - /// \param argv argv vector with the command to execute - /// \param env Environment variables set for execution. - /// \param cwd Working directory for execution. - /// \param tmpdir Temporary directory for storing stdout/stderr files. - /// \returns std::nullopt if there was an error in the execution setup - /// outside running the command itself, SystemCommand::ExecOutput otherwise. - [[nodiscard]] auto Execute(std::vector<std::string> argv, - std::map<std::string, std::string> env, - std::filesystem::path const& cwd, - std::filesystem::path const& tmpdir) noexcept - -> std::optional<ExecOutput> { - if (not FileSystemManager::IsDirectory(tmpdir)) { - logger_.Emit(LogLevel::Error, - "Temporary directory does not exist {}", - tmpdir.string()); - return std::nullopt; - } - - if (argv.empty()) { - logger_.Emit(LogLevel::Error, "Command cannot be empty."); - return std::nullopt; - } - - std::vector<char*> cmd = UnwrapStrings(&argv); - - std::vector<std::string> env_string{}; - std::transform(std::begin(env), - std::end(env), - std::back_inserter(env_string), - [](auto& name_value) { - return name_value.first + "=" + name_value.second; - }); - std::vector<char*> envp = UnwrapStrings(&env_string); - return ExecuteCommand(cmd.data(), envp.data(), cwd, tmpdir); - } - - private: - Logger logger_; - - /// \brief Open file exclusively as write-only. - [[nodiscard]] static auto OpenFile( - std::filesystem::path const& file_path) noexcept { - static auto file_closer = [](gsl::owner<FILE*> f) { - if (f != nullptr) { - std::fclose(f); - } - }; - return std::unique_ptr<FILE, decltype(file_closer)>( - std::fopen(file_path.c_str(), "wx"), file_closer); - } - - /// \brief Execute command and arguments. - /// \param cmd Command arguments as char pointer array. - /// \param envp Environment variables as char pointer array. - /// \param cwd Working directory for execution. - /// \param tmpdir Temporary directory for storing stdout/stderr files. - /// \returns ExecOutput if command was successfully submitted to the system. - /// \returns std::nullopt on internal failure. - [[nodiscard]] auto ExecuteCommand( - char* const* cmd, - char* const* envp, - std::filesystem::path const& cwd, - std::filesystem::path const& tmpdir) noexcept - -> std::optional<ExecOutput> { - auto stdout_file = tmpdir / "stdout"; - auto stderr_file = tmpdir / "stderr"; - if (auto const out = OpenFile(stdout_file)) { - if (auto const err = OpenFile(stderr_file)) { - if (auto retval = ForkAndExecute( - cmd, envp, cwd, fileno(out.get()), fileno(err.get()))) { - return ExecOutput{*retval, - std::move(stdout_file), - std::move(stderr_file)}; - } - } - else { - logger_.Emit(LogLevel::Error, - "Failed to open stderr file '{}' with error: {}", - stderr_file.string(), - strerror(errno)); - } - } - else { - logger_.Emit(LogLevel::Error, - "Failed to open stdout file '{}' with error: {}", - stdout_file.string(), - strerror(errno)); - } - - return std::nullopt; - } - - /// \brief Fork process and exec command. - /// \param cmd Command arguments as char pointer array. - /// \param envp Environment variables as char pointer array. - /// \param cwd Working directory for execution. - /// \param out_fd File descriptor to standard output file. - /// \param err_fd File descriptor to standard erro file. - /// \returns return code if command was successfully submitted to system. - /// \returns std::nullopt if fork or exec failed. - [[nodiscard]] auto ForkAndExecute(char* const* cmd, - char* const* envp, - std::filesystem::path const& cwd, - int out_fd, - int err_fd) const noexcept - -> std::optional<int> { - // fork child process - pid_t pid = ::fork(); - if (-1 == pid) { - logger_.Emit(LogLevel::Error, - "Failed to execute '{}': cannot fork a child process.", - *cmd); - return std::nullopt; - } - - // dispatch child/parent process - if (pid == 0) { - // some executables require an open (possibly seekable) stdin, and - // therefore, we use an open temporary file that does not appear - // on the file system and will be removed automatically once the - // descriptor is closed. - gsl::owner<FILE*> in_file = std::tmpfile(); - auto in_fd = fileno(in_file); - - // redirect and close fds - ::dup2(in_fd, STDIN_FILENO); - ::dup2(out_fd, STDOUT_FILENO); - ::dup2(err_fd, STDERR_FILENO); - ::close(in_fd); - ::close(out_fd); - ::close(err_fd); - - [[maybe_unused]] auto anchor = - FileSystemManager::ChangeDirectory(cwd); - - // execute command in child process and exit - ::execvpe(*cmd, cmd, envp); - - // report error and terminate child process if ::execvp did not exit - logger_.Emit(LogLevel::Error, - "Failed to execute '{}' with error: {}", - *cmd, - strerror(errno)); - - std::exit(EXIT_FAILURE); - } - - // wait for child to finish and obtain return value - int status{}; - ::waitpid(pid, &status, 0); - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return WEXITSTATUS(status); - } - - static auto UnwrapStrings(std::vector<std::string>* v) noexcept - -> std::vector<char*> { - std::vector<char*> raw{}; - std::transform(std::begin(*v), - std::end(*v), - std::back_inserter(raw), - [](auto& str) { return str.data(); }); - raw.push_back(nullptr); - return raw; - } -}; - -#endif // INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_EXECUTION_SYSTEM_HPP |