From e8481260d763f8827e0188e5cd53e613aa4bd305 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Tue, 7 Apr 2020 18:32:02 +0300 Subject: Execute system commands without invoking system shell Added several new methods to the MTS::System class: - ```executeBackground``` - popen alternative, creates a pipe with the specified mode and spawns a new process with specified arguments; - ```closeBackground``` - pclose alternative, closes parent side of the pipe and waits for the child process to finish its execution; - ```execute``` - MTS::System::cmd alternative that allows to spawn child processes directly without invoking system shell. --- include/mts/MTS_System.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'include/mts/MTS_System.h') diff --git a/include/mts/MTS_System.h b/include/mts/MTS_System.h index bd5fa53..6bca21b 100644 --- a/include/mts/MTS_System.h +++ b/include/mts/MTS_System.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace MTS { @@ -38,6 +39,17 @@ namespace MTS { public: + //! Type of the pipe to be opened in executeBackground + enum class PipeType { + READ, WRITE + }; + + //! Utility structure with information about the child process + struct ChildHandle { + pid_t pid; + FILE* stream; + }; + //UTC (Coordinated Universal Time) : This is the standard international time or the Greenwich Mean Time. //EPOCH : number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time. @@ -53,6 +65,79 @@ namespace MTS { static int32_t cmd(const std::string& cmd, std::string& result); static int32_t readFile(const std::string& path, std::string& result); + + //! Execute application with specified arguments. + /*! + * A safer alternative to System::cmd that allows to execute applications with controlled + * list of arguments bypasing the system shell. + * + * \param app 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 execute(const std::string& app, 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 + * list of arguments bypasing the system shell. If succeded, information about the spawned + * process is written to the \p child structure. + * + * \param app 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 + * \return true on success, false on failure + */ + static bool executeBackground(const std::string& app, const std::vector& argv, PipeType type, ChildHandle& child); + + //! Close the pipe and wait for a child to finish execution + /*! + * \param child 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 int closeBackground(ChildHandle& child); + + private: + + //! Spawn a process and open pipe with the specified type (READ or WRITE) + static bool executeBackground(const std::string& app, char* const argv[], 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); + + //! Utility method. Convert argument vector to a format required by execve and posix_spawn. + static std::vector castArgVector(const std::string& app, const std::vector& argv); + + //! Lightweight C++ wrapper with auto-close for file descriptors + class FdWrapper { + + public: + static const int FD_NOT_READY = -1; + + explicit FdWrapper(int fd = FD_NOT_READY); + ~FdWrapper(); + + inline int get() const; + int release(); + void reset(int fd = FD_NOT_READY); + + private: + int m_fd; + + }; + + //! Utility structure, used by popen wrapper + struct Pipe { + FdWrapper parent; + FdWrapper child; + }; + + //! Initialize UNIX pipe + static int initPipe(Pipe& pipe, PipeType type); + }; } -- cgit v1.2.3