| 170 | |
| 171 | |
| 172 | int start_async_exec(struct sip_msg* msg, str* command, str* input, |
| 173 | pv_spec_t *outvar, int *fd) |
| 174 | { |
| 175 | pid_t pid; |
| 176 | FILE *pin = NULL, *pout = NULL; |
| 177 | int val; |
| 178 | |
| 179 | if ((input&&input->s&&input->len) || outvar) { |
| 180 | pid = __popen3(command->s, (input&&input->s&&input->len) ? &pin : NULL, |
| 181 | outvar ? &pout : NULL, |
| 182 | NULL); |
| 183 | } else { |
| 184 | pid = fork(); |
| 185 | if (pid == 0) { |
| 186 | /* child process*/ |
| 187 | execl("/bin/sh", "/bin/sh", "-c", command->s, NULL); |
| 188 | exit(-1); |
| 189 | } |
| 190 | if (pid<0) { |
| 191 | /*error of fork*/ |
| 192 | LM_ERR("failed to fork (%s)\n",strerror(errno)); |
| 193 | goto error; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | if (input && input->len && pin) { |
| 198 | if ( (val=fwrite(input->s, 1, input->len, pin)) != input->len) { |
| 199 | LM_ERR("failed to write all (%d needed, %d written) to input pipe," |
| 200 | " but continuing\n",input->len,val); |
| 201 | } |
| 202 | |
| 203 | if (ferror(pin)) { |
| 204 | LM_ERR("failure detected (%s), continuing..\n",strerror(errno)); |
| 205 | } |
| 206 | fclose(pin); |
| 207 | } |
| 208 | |
| 209 | /* set time to kill on the new process */ |
| 210 | schedule_to_kill(pid); |
| 211 | |
| 212 | if (outvar==NULL) { |
| 213 | /* nothing to wait for, no I/O */ |
| 214 | return 2; |
| 215 | } |
| 216 | |
| 217 | /* prepare the read FD and make it non-blocking */ |
| 218 | if ( (*fd=dup( fileno( pout ) ))<0 ) { |
| 219 | LM_ERR("dup failed: (%d) %s\n", errno, strerror(errno)); |
| 220 | goto error; |
| 221 | } |
| 222 | val = fcntl( *fd, F_GETFL); |
| 223 | if (val==-1){ |
| 224 | LM_ERR("fcntl failed: (%d) %s\n", errno, strerror(errno)); |
| 225 | goto error2; |
| 226 | } |
| 227 | if (fcntl( *fd , F_SETFL, val|O_NONBLOCK)==-1){ |
| 228 | LM_ERR("set non-blocking failed: (%d) %s\n", |
| 229 | errno, strerror(errno)); |
no test coverage detected