#pragma once #include #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, 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, the output is not redirected and * you can't communicate with the child program. * * Example usage: * * \code cpp * auto cmd = command_util::make_command("cat /etc/rc.local"); * cmd->exec(); * cmd->tail([](string s) { std::cout << s << std::endl; }); * \endcode * * \code cpp * auto cmd = command_util::make_command( * "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("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("ping kernel.org"); * int status = cmd->exec(); * \endcode */ template class command; template <> class command { 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{}; }; template <> class command : private command { 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::terminate; using command::is_running; using command::wait; using command::get_pid; using command::get_exit_status; void tail(callback 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 unique_ptr> make_command(Args&&... args) { return factory_util::unique>(logger::make(), forward(args)...); } } // namespace command_util POLYBAR_NS_END