00042 {
00043
char line[MAXLINE];
00044 pid_t pid;
00045
int fds[4] = { -1, }, mode = 0, pipes = 0, i;
00046
00047
if (stdout_handler)
00048 {
00049 mode += 1;
00050 pipes++;
00051 }
00052
if (stderr_handler)
00053 {
00054 mode += 2;
00055 pipes++;
00056 }
00057
00058
for (i = 0; i < pipes; i++)
00059 pipe (&fds[i * 2]);
00060
00061 pid = fork ();
00062
00063
if (pid <= 0)
00064 {
00065
for (i = 0; i < pipes; i++)
00066 close (fds[i * 2]);
00067 }
00068
00069
if (pid == 0)
00070 {
00071
int temp, realfds[3] =
00072 {
00073 0,
00074 fds[1],
00075 fds[3]
00076 };
00077
00078 temp = open (
"/dev/null", O_RDWR);
00079
00080
switch (mode)
00081 {
00082
case 0:
00083 realfds[1] = temp;
00084 realfds[2] = temp;
00085
break;
00086
case 2:
00087 realfds[1] = temp;
00088 realfds[2] = fds[1];
00089
break;
00090
case 1:
00091 realfds[2] = fds[1];
00092
break;
00093 }
00094
00095
for (i = 1; i <= 2; i++)
00096 dup2 (realfds[i], i);
00097
00098 close (temp);
00099 }
00100
00101
for (i = 0; i < pipes; i++)
00102 close (fds[i * 2 + 1]);
00103
00104
if (pid == 0)
00105 {
00106
if (child_prepare_handler)
00107
if (child_prepare_handler (pid, child_prepare_user_data))
00108 exit (255);
00109
00110 execv (path, (
char *
const *) argv);
00111 exit (127);
00112 }
00113
else if (pid < 0)
00114 {
00115
di_log (DI_LOG_LEVEL_WARNING,
"fork failed");
00116
return -1;
00117 }
00118
else
00119 {
00120
int status = -1;
00121
struct pollfd pollfds[pipes];
00122
struct files
00123 {
00124 FILE *file;
00125
di_io_handler *handler;
00126 }
00127 files[pipes];
00128
00129
for (i = 0; i < pipes; i++)
00130 {
00131 fcntl (fds[i * 2], F_SETFL, O_NONBLOCK);
00132 files[i].file = fdopen (fds[i * 2],
"r");
00133 pollfds[i].fd = fds[i * 2];
00134 pollfds[i].events = POLLIN;
00135 }
00136
00137
switch (mode)
00138 {
00139
case 2:
00140 files[0].handler = stderr_handler;
00141
break;
00142
case 3:
00143 files[1].handler = stderr_handler;
00144
case 1:
00145 files[0].handler = stdout_handler;
00146
break;
00147 }
00148
00149
if (parent_prepare_handler && parent_prepare_handler (pid, parent_prepare_user_data))
00150 kill (pid, 9);
00151
else if (pipes)
00152
while (poll (pollfds, pipes, -1) >= 0)
00153 {
00154
bool exit =
false;
00155
00156
for (i = 0; i < pipes; i++)
00157 {
00158
if (pollfds[i].revents & POLLIN)
00159 {
00160
while (fgets (line,
sizeof (line), files[i].file) != NULL)
00161 {
00162 size_t len = strlen (line);
00163
if (line[len - 1] ==
'\n')
00164 {
00165 line[len - 1] =
'\0';
00166 len--;
00167 }
00168 files[i].handler (line, len, io_user_data);
00169 }
00170 exit =
true;
00171 }
00172 }
00173
00174
if (exit)
00175
continue;
00176
00177
for (i = 0; i < pipes; i++)
00178
if (pollfds[i].revents & POLLHUP)
00179 exit =
true;
00180
00181
if (exit)
00182
break;
00183 }
00184
00185
if (!waitpid (pid, &status, 0))
00186
return -1;
00187
00188
for (i = 0; i < pipes; i++)
00189 fclose (files[i].file);
00190
00191
return status;
00192 }
00193
00194
return -1;
00195 }