Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame] | 1 | /** |
| 2 | * @file child_reader.h |
| 3 | * Facility for reading from child processes |
| 4 | * |
| 5 | * @remark Copyright 2002 OProfile authors |
| 6 | * @remark Read the file COPYING |
| 7 | * |
| 8 | * @author Philippe Elie |
| 9 | * @author John Levon |
| 10 | */ |
| 11 | |
| 12 | #ifndef CHILD_READER_H |
| 13 | #define CHILD_READER_H |
| 14 | |
| 15 | #include <sys/types.h> |
| 16 | |
| 17 | #include <vector> |
| 18 | #include <string> |
| 19 | |
| 20 | /** |
| 21 | * a class to read stdout / stderr from a child process. |
| 22 | * |
| 23 | * two interfaces are provided. read line by line: getline() or read all data |
| 24 | * in one : get_data(). In all case get_data() must be called once to flush the |
| 25 | * stderr child output |
| 26 | */ |
| 27 | /* |
| 28 | * FIXME: code review is needed: |
| 29 | * - check the getline()/get_data()/block_read() interface. |
| 30 | * the expected behavior is: |
| 31 | * caller can call getline until nothing is available from the stdout of the |
| 32 | * child. in this case child stderr is acumulated in buf2 and can be read |
| 33 | * through get_data(). get_data() is blocking until the child close stderr / |
| 34 | * stdout (even if the child die by a signal ?). The following corner case must |
| 35 | * work but I'm unsure if the code reflect this behavior: the last line of the |
| 36 | * child stdout have not necessarilly a LF terminator. the child can output any |
| 37 | * size of data in stderr. |
| 38 | */ |
| 39 | class child_reader { |
| 40 | public: |
| 41 | /** fork a process. use error() to get error code. Do not try to |
| 42 | * use other public member interface if error() return non-zero */ |
| 43 | child_reader(std::string const & cmd, |
| 44 | std::vector<std::string> const & args); |
| 45 | |
| 46 | /** wait for the termination of the child process if this have not |
| 47 | * already occur. In this case return code of the child process is not |
| 48 | * available. */ |
| 49 | ~child_reader(); |
| 50 | |
| 51 | /** fill result from on line of stdout of the child process. |
| 52 | * must be used as: |
| 53 | * child_reader reader(...); |
| 54 | * while (reader.getline(line)) .... */ |
| 55 | bool getline(std::string & result); |
| 56 | |
| 57 | /** fill out / err with the stdout / stderr of the child process. |
| 58 | * You can call this after calling one or more time getline(...). This |
| 59 | * call is blocking until the child die and so on all subsequent |
| 60 | * call will fail */ |
| 61 | bool get_data(std::ostream & out, std::ostream & err); |
| 62 | |
| 63 | /** rather to rely on dtor to wait for the termination of the child you |
| 64 | * can use terminate_process() to get the return code of the child |
| 65 | * process */ |
| 66 | int terminate_process(); |
| 67 | |
| 68 | /** return the status of the first error encoutered |
| 69 | * != 0 : something feel wrong, use error_str() to get an error |
| 70 | * message */ |
| 71 | int error() const { return first_error; } |
| 72 | |
| 73 | /** |
| 74 | * return an error message if appropriate, if the process has |
| 75 | * been successfully exec'ed and is not terminate the error message |
| 76 | * is always empty. Error message is also empty if the child process |
| 77 | * terminate successfully. Else three type of error message exist: |
| 78 | * - "unable to fork" followed by sterror(errno) |
| 79 | * - "process_name return xxx" xxx is return code |
| 80 | * - "process_name terminated by signal xxx" xxx is signal number |
| 81 | */ |
| 82 | std::string error_str() const; |
| 83 | |
| 84 | private: |
| 85 | // ctor helper: create the child process. |
| 86 | void exec_command(std::string const & cmd, |
| 87 | std::vector<std::string> const & args); |
| 88 | // return false when eof condition is reached on fd1. fd2 can have |
| 89 | // already input in the pipe buffer or in buf2. |
| 90 | bool block_read(); |
| 91 | |
| 92 | int fd1; |
| 93 | int fd2; |
| 94 | ssize_t pos1; |
| 95 | ssize_t end1; |
| 96 | ssize_t pos2; |
| 97 | ssize_t end2; |
| 98 | pid_t pid; |
| 99 | int first_error; |
| 100 | // child stderr is handled especially, we need to retain data even |
| 101 | // if caller read only stdout of the child. |
| 102 | char * buf2; |
| 103 | ssize_t sz_buf2; |
| 104 | char * buf1; |
| 105 | std::string process_name; |
| 106 | bool is_terminated; |
| 107 | bool terminate_on_exception; |
| 108 | bool forked; |
| 109 | }; |
| 110 | |
| 111 | #endif // CHILD_READER_H |