child_reader.cpp
Go to the documentation of this file.00001
00012 #include <unistd.h>
00013 #include <sys/wait.h>
00014 #include <limits.h>
00015
00016 #include <cerrno>
00017 #include <sstream>
00018 #include <iostream>
00019 #include <cstring>
00020 #include <cstdlib>
00021
00022 #include "op_libiberty.h"
00023 #include "child_reader.h"
00024
00025 using namespace std;
00026
00027 child_reader::child_reader(string const & cmd, vector<string> const & args)
00028 :
00029 fd1(-1), fd2(-1),
00030 pos1(0), end1(0),
00031 pos2(0), end2(0),
00032 pid(0),
00033 first_error(0),
00034 buf2(0), sz_buf2(0),
00035 buf1(new char[PIPE_BUF]),
00036 process_name(cmd),
00037 is_terminated(true),
00038 terminate_on_exception(false),
00039 forked(false)
00040 {
00041 exec_command(cmd, args);
00042 }
00043
00044
00045 child_reader::~child_reader()
00046 {
00047 terminate_process();
00048 delete [] buf1;
00049 if (buf2) {
00050
00051 free(buf2);
00052 }
00053 }
00054
00055
00056 void child_reader::exec_command(string const & cmd, vector<string> const & args)
00057 {
00058 int pstdout[2];
00059 int pstderr[2];
00060
00061 if (pipe(pstdout) == -1 || pipe(pstderr) == -1) {
00062 first_error = errno;
00063 return;
00064 }
00065
00066 pid = fork();
00067 switch (pid) {
00068 case -1:
00069 first_error = errno;
00070 return;
00071
00072 case 0: {
00073 char const ** argv = new char const *[args.size() + 2];
00074 size_t i;
00075 argv[0] = cmd.c_str();
00076
00077 for (i = 1 ; i <= args.size() ; ++i)
00078 argv[i] = args[i - 1].c_str();
00079
00080 argv[i] = 0;
00081
00082
00083 close(pstdout[0]);
00084 dup2(pstdout[1], STDOUT_FILENO);
00085 close(pstdout[1]);
00086 close(pstderr[0]);
00087 dup2(pstderr[1], STDERR_FILENO);
00088 close(pstderr[1]);
00089
00090 execvp(cmd.c_str(), (char * const *)argv);
00091
00092 int ret_code = errno;
00093
00094
00095
00096
00097
00098
00099
00100 cerr << "Couldn't exec \"" << cmd << "\" : "
00101 << strerror(errno) << endl;
00102 exit(ret_code);
00103 }
00104
00105 default:;
00106
00107 close(pstdout[1]);
00108 close(pstderr[1]);
00109 forked = true;
00110 break;
00111 }
00112
00113 fd1 = pstdout[0];
00114 fd2 = pstderr[0];
00115
00116 is_terminated = false;
00117
00118 return;
00119 }
00120
00121
00122 bool child_reader::block_read()
00123 {
00124 fd_set read_fs;
00125
00126 FD_ZERO(&read_fs);
00127 FD_SET(fd1, &read_fs);
00128 FD_SET(fd2, &read_fs);
00129
00130 if (select(max(fd1, fd2) + 1, &read_fs, 0, 0, 0) >= 0) {
00131 if (FD_ISSET(fd1, &read_fs)) {
00132 ssize_t temp = read(fd1, buf1, PIPE_BUF);
00133 if (temp >= 0)
00134 end1 = temp;
00135 else
00136 end1 = 0;
00137 }
00138
00139 if (FD_ISSET(fd2, &read_fs)) {
00140 if (end2 >= sz_buf2) {
00141 sz_buf2 = sz_buf2 ? sz_buf2 * 2 : PIPE_BUF;
00142 buf2 = (char *)xrealloc(buf2, sz_buf2);
00143 }
00144
00145 ssize_t temp = read(fd2, buf2 + end2, sz_buf2 - end2);
00146 if (temp > 0)
00147 end2 += temp;
00148 }
00149 }
00150
00151 bool ret = !(end1 == 0 && end2 == 0);
00152
00153 if (end1 == -1)
00154 end1 = 0;
00155 if (end2 == -1)
00156 end2 = 0;
00157
00158 return ret;
00159 }
00160
00161
00162 bool child_reader::getline(string & result)
00163 {
00164
00165 result.erase(result.begin(), result.end());
00166
00167 bool ok = true;
00168 bool can_stop = false;
00169 do {
00170 int temp = end2;
00171 if (pos1 >= end1) {
00172 pos1 = 0;
00173 block_read();
00174 }
00175
00176
00177 ssize_t temp_pos = pos1;
00178 while (temp_pos < end1 && ok) {
00179 char ch = buf1[temp_pos++];
00180 if (ch == '\n')
00181 ok = false;
00182 }
00183
00184
00185 result.append(&buf1[pos1], (temp_pos - pos1) - !ok);
00186
00187 if (!ok || !end1)
00188 can_stop = true;
00189
00190
00191
00192
00193 if (ok && temp != end2)
00194 can_stop = false;
00195
00196 pos1 = temp_pos;
00197 } while (!can_stop);
00198
00199
00200 return end1 != 0 || result.length() != 0;
00201 }
00202
00203
00204 bool child_reader::get_data(ostream & out, ostream & err)
00205 {
00206 bool ret = true;
00207 while (ret) {
00208 ret = block_read();
00209
00210 out.write(buf1, end1);
00211 err.write(buf2, end2);
00212
00213 end1 = end2 = 0;
00214 }
00215
00216 return first_error == 0;
00217 }
00218
00219
00220 int child_reader::terminate_process()
00221 {
00222
00223
00224 if (!is_terminated) {
00225 int ret;
00226 waitpid(pid, &ret, 0);
00227
00228 is_terminated = true;
00229
00230 if (WIFEXITED(ret)) {
00231 first_error = WEXITSTATUS(ret) | WIFSIGNALED(ret);
00232 } else if (WIFSIGNALED(ret)) {
00233 terminate_on_exception = true;
00234 first_error = WTERMSIG(ret);
00235 } else {
00236
00237
00238
00239 first_error = -1;
00240 }
00241 }
00242
00243 if (fd1 != -1) {
00244 close(fd1);
00245 fd1 = -1;
00246 }
00247 if (fd2 != -1) {
00248 close(fd2);
00249 fd2 = -1;
00250 }
00251
00252 return first_error;
00253 }
00254
00255
00256 string child_reader::error_str() const
00257 {
00258 ostringstream err;
00259 if (!forked) {
00260 err << string("unable to fork, error: ")
00261 << strerror(first_error);
00262 } else if (is_terminated) {
00263 if (first_error) {
00264 if (terminate_on_exception) {
00265 err << process_name << " terminated by signal "
00266 << first_error;
00267 } else {
00268 err << process_name << " return "
00269 << first_error;
00270 }
00271 }
00272 }
00273
00274 return err.str();
00275 }