From 64e315d136d63873600895c7385dd40c4cb254ba Mon Sep 17 00:00:00 2001 From: Mykyta Dorokhin Date: Fri, 30 Sep 2022 14:07:39 +0300 Subject: Introduce System::executeEnv and System::executeBackgroundEnv --- include/mts/MTS_System.h | 28 +++++++++++++++++++++++++++- src/MTS_System.cpp | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/include/mts/MTS_System.h b/include/mts/MTS_System.h index d51a5ea..24dc616 100644 --- a/include/mts/MTS_System.h +++ b/include/mts/MTS_System.h @@ -78,6 +78,18 @@ namespace MTS { */ static int32_t execute(const std::string& cmd, const std::vector& argv, std::string& result); + //! Execute application with specified arguments and environment variables inheritance. + /*! + * A safer alternative to System::cmd that allows to execute applications with controlled + * list of arguments and inherited environment variables bypasing the system shell. + * + * \param cmd name of the application to be executed + * \param argv vector of arguments (excluding argument zero) + * \param result stdout output from the application is stored here + * \return result code as for std::system and UNIX pclose + */ + static int32_t executeEnv(const std::string& cmd, const std::vector& argv, std::string& result); + //! Spawn a process and open pipe with the specified type (READ or WRITE) /*! * A safer alternative to POSIX popen that allows to execute applications with controlled @@ -92,6 +104,20 @@ namespace MTS { */ static bool executeBackground(const std::string& cmd, const std::vector& argv, PipeType type, ChildHandle& child); + //! Spawn a process and open pipe with the specified type (READ or WRITE) + /*! + * A safer alternative to POSIX popen that allows to execute applications with controlled + * list of arguments and inherited environment variables bypasing the system shell. + * If succeded, information about the spawned process is written to the \p child structure. + * + * \param cmd name of the application to be executed + * \param argv vector of arguments (excluding argument zero) + * \param type open pipe for read from child or write to child + * \param child on success is populated with child process information, on failure is not defined + * \return true on success, false on failure + */ + static bool executeBackgroundEnv(const std::string& cmd, const std::vector& argv, PipeType type, ChildHandle& child); + //! Close the pipe and wait for a child to finish execution /*! * \param child structure with child process information as populated by executeBackground @@ -102,7 +128,7 @@ namespace MTS { private: //! Spawn a process and open pipe with the specified type (READ or WRITE) - static bool executeBackground(const std::string& cmd, char* const argv[], PipeType type, ChildHandle& child); + static bool executeBackground(const std::string& cmd, char* const argv[], bool env, PipeType type, ChildHandle& child); //! Utility method. Cast argument to a C pointer required by some C-style functions. static inline char* castArgument(const std::string& arg); diff --git a/src/MTS_System.cpp b/src/MTS_System.cpp index 31976e1..8704a34 100644 --- a/src/MTS_System.cpp +++ b/src/MTS_System.cpp @@ -194,9 +194,36 @@ int32_t System::execute(const std::string& cmd, const std::vector& return code; } +int32_t System::executeEnv(const std::string& cmd, const std::vector& argv, std::string& result) { + // Ported directly from System::cmd + std::string output; + const int max_buffer = 256; + char buffer[max_buffer]; + int32_t code = -1; + ChildHandle child; + + if (executeBackgroundEnv(cmd, argv, PipeType::READ, child)) { + while (!feof(child.stream)) { + if (fgets(buffer, max_buffer, child.stream) != NULL) { + output.append(buffer); + } + } + code = closeBackground(child); + } + + result = output; + + return code; +} + bool System::executeBackground(const std::string& cmd, const std::vector& argv, System::PipeType type, System::ChildHandle& child) { std::vector arguments = castArgVector(cmd, argv); - return executeBackground(cmd, arguments.data(), type, child); + return executeBackground(cmd, arguments.data(), false, type, child); +} + +bool System::executeBackgroundEnv(const std::string& cmd, const std::vector& argv, System::PipeType type, System::ChildHandle& child) { + std::vector arguments = castArgVector(cmd, argv); + return executeBackground(cmd, arguments.data(), true, type, child); } int System::closeBackground(System::ChildHandle& child) { @@ -212,7 +239,9 @@ int System::closeBackground(System::ChildHandle& child) { return pstat; } -bool System::executeBackground(const std::string& cmd, char* const argv[], System::PipeType type, ChildHandle& child) { +extern char **environ; + +bool System::executeBackground(const std::string& cmd, char* const argv[], bool env, System::PipeType type, ChildHandle& child) { pid_t childPid; FILE* stream = NULL; posix_spawn_file_actions_t actions; @@ -262,7 +291,7 @@ bool System::executeBackground(const std::string& cmd, char* const argv[], Syste break; } - if (posix_spawnp(&childPid, cmd.c_str(), &actions, NULL, argv, NULL) != 0) { + if (posix_spawnp(&childPid, cmd.c_str(), &actions, NULL, argv, env ? environ : NULL) != 0) { // failed to spawn the process break; } -- cgit v1.2.3