#pragma once #include <mutex> #include "common.hpp" #include "components/logger.hpp" #include "components/types.hpp" #include "errors.hpp" #include "utils/factory.hpp" #include "utils/functional.hpp" POLYBAR_NS DEFINE_ERROR(command_error); /** * Wrapper used to execute command in a subprocess. * In-/output streams are opened to enable ipc. * If the command is created using command_util::make_command<output_policy::REDIRECTED>, the child streams are * redirected and you can read the program output or write into the program input. * * If the command is created using command_util::make_command<output_policy::IGNORED>, the output is not redirected and * you can't communicate with the child program. * * Example usage: * * \code cpp * auto cmd = command_util::make_command<output_policy::REDIRECTED>("cat /etc/rc.local"); * cmd->exec(); * cmd->tail([](string s) { std::cout << s << std::endl; }); * \endcode * * \code cpp * auto cmd = command_util::make_command<output_policy::REDIRECTED>( * "while read -r line; do echo data from parent process: $line; done"); * cmd->exec(false); * cmd->writeline("Test"); * cout << cmd->readline(); * cmd->wait(); * \endcode * * \code cpp * auto cmd = command_util::make_command<output_policy::REDIRECTED>("for i in 1 2 3; do echo $i; done"); * cmd->exec(); * cout << cmd->readline(); // 1 * cout << cmd->readline() << cmd->readline(); // 23 * \endcode * * \code cpp * auto cmd = command_util::make_command<output_policy::IGNORED>("ping kernel.org"); * int status = cmd->exec(); * \endcode */ template <output_policy> class command; template <> class command<output_policy::IGNORED> { public: explicit command(const logger& logger, string cmd); command(const command&) = delete; ~command(); command& operator=(const command&) = delete; int exec(bool wait_for_completion = true); void terminate(); bool is_running(); int wait(); pid_t get_pid(); int get_exit_status(); protected: const logger& m_log; string m_cmd; pid_t m_forkpid{}; int m_forkstatus = - 1; }; template <> class command<output_policy::REDIRECTED> : private command<output_policy::IGNORED> { public: explicit command(const logger& logger, string cmd); command(const command&) = delete; ~command(); command& operator=(const command&) = delete; int exec(bool wait_for_completion = true); using command<output_policy::IGNORED>::terminate; using command<output_policy::IGNORED>::is_running; using command<output_policy::IGNORED>::wait; using command<output_policy::IGNORED>::get_pid; using command<output_policy::IGNORED>::get_exit_status; void tail(callback<string> cb); int writeline(string data); string readline(); int get_stdout(int c); int get_stdin(int c); protected: int m_stdout[2]{}; int m_stdin[2]{}; std::mutex m_pipelock{}; }; namespace command_util { template <output_policy OutputType, typename... Args> unique_ptr<command<OutputType>> make_command(Args&&... args) { return factory_util::unique<command<OutputType>>(logger::make(), forward<Args>(args)...); } } // namespace command_util POLYBAR_NS_END