/** * @file child_reader.h * Facility for reading from child processes * * @remark Copyright 2002 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #ifndef CHILD_READER_H #define CHILD_READER_H #include <sys/types.h> #include <vector> #include <string> /** * a class to read stdout / stderr from a child process. * * two interfaces are provided. read line by line: getline() or read all data * in one : get_data(). In all case get_data() must be called once to flush the * stderr child output */ /* * FIXME: code review is needed: * - check the getline()/get_data()/block_read() interface. * the expected behavior is: * caller can call getline until nothing is available from the stdout of the * child. in this case child stderr is acumulated in buf2 and can be read * through get_data(). get_data() is blocking until the child close stderr / * stdout (even if the child die by a signal ?). The following corner case must * work but I'm unsure if the code reflect this behavior: the last line of the * child stdout have not necessarilly a LF terminator. the child can output any * size of data in stderr. */ class child_reader { public: /** fork a process. use error() to get error code. Do not try to * use other public member interface if error() return non-zero */ child_reader(std::string const & cmd, std::vector<std::string> const & args); /** wait for the termination of the child process if this have not * already occur. In this case return code of the child process is not * available. */ ~child_reader(); /** fill result from on line of stdout of the child process. * must be used as: * child_reader reader(...); * while (reader.getline(line)) .... */ bool getline(std::string & result); /** fill out / err with the stdout / stderr of the child process. * You can call this after calling one or more time getline(...). This * call is blocking until the child die and so on all subsequent * call will fail */ bool get_data(std::ostream & out, std::ostream & err); /** rather to rely on dtor to wait for the termination of the child you * can use terminate_process() to get the return code of the child * process */ int terminate_process(); /** return the status of the first error encoutered * != 0 : something feel wrong, use error_str() to get an error * message */ int error() const { return first_error; } /** * return an error message if appropriate, if the process has * been successfully exec'ed and is not terminate the error message * is always empty. Error message is also empty if the child process * terminate successfully. Else three type of error message exist: * - "unable to fork" followed by sterror(errno) * - "process_name return xxx" xxx is return code * - "process_name terminated by signal xxx" xxx is signal number */ std::string error_str() const; private: // ctor helper: create the child process. void exec_command(std::string const & cmd, std::vector<std::string> const & args); // return false when eof condition is reached on fd1. fd2 can have // already input in the pipe buffer or in buf2. bool block_read(); int fd1; int fd2; ssize_t pos1; ssize_t end1; ssize_t pos2; ssize_t end2; pid_t pid; int first_error; // child stderr is handled especially, we need to retain data even // if caller read only stdout of the child. char * buf2; ssize_t sz_buf2; char * buf1; std::string process_name; bool is_terminated; bool terminate_on_exception; bool forked; }; #endif // CHILD_READER_H