1 /* 2 Run a child process and collect the output 3 4 Copyright (C) Amitay Isaacs 2016 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "replace.h" 21 #include "system/filesys.h" 22 #include "system/wait.h" 23 24 #include <talloc.h> 25 #include <tevent.h> 26 27 #include "lib/util/tevent_unix.h" 28 #include "lib/util/sys_rw.h" 29 #include "lib/util/blocking.h" 30 #include "lib/util/dlinklist.h" 31 32 #include "common/run_proc.h" 33 34 /* 35 * Process abstraction 36 */ 37 38 struct run_proc_context; 39 40 struct proc_context { 41 struct proc_context *prev, *next; 42 43 pid_t pid; 44 45 int fd; 46 struct tevent_fd *fde; 47 48 char *output; 49 struct run_proc_result result; 50 51 struct tevent_req *req; 52 }; 53 54 static int proc_destructor(struct proc_context *proc); 55 56 static struct proc_context *proc_new(TALLOC_CTX *mem_ctx, 57 struct run_proc_context *run_ctx) 58 { 59 struct proc_context *proc; 60 61 proc = talloc_zero(mem_ctx, struct proc_context); 62 if (proc == NULL) { 63 return NULL; 64 } 65 66 proc->pid = -1; 67 proc->fd = -1; 68 69 talloc_set_destructor(proc, proc_destructor); 70 71 return proc; 72 } 73 74 static void run_proc_kill(struct tevent_req *req); 75 76 static int proc_destructor(struct proc_context *proc) 77 { 78 if (proc->req != NULL) { 79 run_proc_kill(proc->req); 80 } 81 82 talloc_free(proc->fde); 83 if (proc->pid != -1) { 84 kill(-proc->pid, SIGKILL); 85 } 86 87 return 0; 88 } 89 90 static void proc_read_handler(struct tevent_context *ev, 91 struct tevent_fd *fde, uint16_t flags, 92 void *private_data); 93 94 static int proc_start(struct proc_context *proc, struct tevent_context *ev, 95 const char *path, const char **argv, int stdin_fd) 96 { 97 int fd[2]; 98 int ret; 99 100 ret = pipe(fd); 101 if (ret != 0) { 102 return ret; 103 } 104 105 proc->pid = fork(); 106 if (proc->pid == -1) { 107 ret = errno; 108 close(fd[0]); 109 close(fd[1]); 110 return ret; 111 } 112 113 if (proc->pid == 0) { 114 close(fd[0]); 115 116 ret = dup2(fd[1], STDOUT_FILENO); 117 if (ret == -1) { 118 exit(64 + errno); 119 } 120 ret = dup2(fd[1], STDERR_FILENO); 121 if (ret == -1) { 122 exit(64 + errno); 123 } 124 125 close(fd[1]); 126 127 if (stdin_fd != -1) { 128 ret = dup2(stdin_fd, STDIN_FILENO); 129 if (ret == -1) { 130 exit(64 + errno); 131 } 132 } 133 134 ret = setpgid(0, 0); 135 if (ret != 0) { 136 exit(64 + errno); 137 } 138 139 ret = execv(path, discard_const(argv)); 140 if (ret != 0) { 141 exit(64 + errno); 142 } 143 144 exit(64 + ENOEXEC); 145 } 146 147 close(fd[1]); 148 149 proc->fd = fd[0]; 150 proc->fde = tevent_add_fd(ev, proc, fd[0], TEVENT_FD_READ, 151 proc_read_handler, proc); 152 if (proc->fde == NULL) { 153 close(fd[0]); 154 return ENOMEM; 155 } 156 157 tevent_fd_set_auto_close(proc->fde); 158 159 return 0; 160 } 161 162 static void proc_read_handler(struct tevent_context *ev, 163 struct tevent_fd *fde, uint16_t flags, 164 void *private_data) 165 { 166 struct proc_context *proc = talloc_get_type_abort( 167 private_data, struct proc_context); 168 size_t offset; 169 ssize_t nread; 170 int len = 0; 171 int ret; 172 173 ret = ioctl(proc->fd, FIONREAD, &len); 174 if (ret != 0) { 175 goto fail; 176 } 177 178 if (len == 0) { 179 /* pipe closed */ 180 goto close; 181 } 182 183 offset = (proc->output == NULL) ? 0 : strlen(proc->output); 184 185 proc->output = talloc_realloc(proc, proc->output, char, offset+len+1); 186 if (proc->output == NULL) { 187 goto fail; 188 } 189 190 nread = sys_read(proc->fd, proc->output + offset, len); 191 if (nread == -1) { 192 goto fail; 193 } 194 proc->output[offset+nread] = '\0'; 195 return; 196 197 fail: 198 if (proc->pid != -1) { 199 kill(-proc->pid, SIGKILL); 200 proc->pid = -1; 201 } 202 close: 203 TALLOC_FREE(proc->fde); 204 proc->fd = -1; 205 } 206 207 208 /* 209 * Run proc abstraction 210 */ 211 212 struct run_proc_context { 213 struct tevent_context *ev; 214 struct tevent_signal *se; 215 struct proc_context *plist; 216 }; 217 218 static void run_proc_signal_handler(struct tevent_context *ev, 219 struct tevent_signal *se, 220 int signum, int count, void *siginfo, 221 void *private_data); 222 static int run_proc_context_destructor(struct run_proc_context *run_ctx); 223 static void run_proc_done(struct tevent_req *req); 224 225 int run_proc_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, 226 struct run_proc_context **result) 227 { 228 struct run_proc_context *run_ctx; 229 230 run_ctx = talloc_zero(mem_ctx, struct run_proc_context); 231 if (run_ctx == NULL) { 232 return ENOMEM; 233 } 234 235 run_ctx->ev = ev; 236 run_ctx->se = tevent_add_signal(ev, run_ctx, SIGCHLD, 0, 237 run_proc_signal_handler, run_ctx); 238 if (run_ctx->se == NULL) { 239 talloc_free(run_ctx); 240 return ENOMEM; 241 } 242 243 talloc_set_destructor(run_ctx, run_proc_context_destructor); 244 245 *result = run_ctx; 246 return 0; 247 } 248 249 static void run_proc_signal_handler(struct tevent_context *ev, 250 struct tevent_signal *se, 251 int signum, int count, void *siginfo, 252 void *private_data) 253 { 254 struct run_proc_context *run_ctx = talloc_get_type_abort( 255 private_data, struct run_proc_context); 256 struct proc_context *proc; 257 pid_t pid = -1; 258 int status; 259 260 again: 261 pid = waitpid(-1, &status, WNOHANG); 262 if (pid == -1) { 263 return; 264 } 265 266 if (pid == 0) { 267 return; 268 } 269 270 for (proc = run_ctx->plist; proc != NULL; proc = proc->next) { 271 if (proc->pid == pid) { 272 break; 273 } 274 } 275 276 if (proc == NULL) { 277 /* unknown process */ 278 goto again; 279 } 280 281 /* Mark the process as terminated */ 282 proc->pid = -1; 283 284 /* Update process status */ 285 if (WIFEXITED(status)) { 286 int pstatus = WEXITSTATUS(status); 287 if (WIFSIGNALED(status)) { 288 proc->result.sig = WTERMSIG(status); 289 } else if (pstatus >= 64 && pstatus < 255) { 290 proc->result.err = pstatus-64; 291 } else { 292 proc->result.status = pstatus; 293 } 294 } else if (WIFSIGNALED(status)) { 295 proc->result.sig = WTERMSIG(status); 296 } 297 298 /* Confirm that all data has been read from the pipe */ 299 if (proc->fd != -1) { 300 proc_read_handler(ev, proc->fde, 0, proc); 301 TALLOC_FREE(proc->fde); 302 proc->fd = -1; 303 } 304 305 DLIST_REMOVE(run_ctx->plist, proc); 306 307 /* Active run_proc request */ 308 if (proc->req != NULL) { 309 run_proc_done(proc->req); 310 } else { 311 talloc_free(proc); 312 } 313 314 goto again; 315 } 316 317 static int run_proc_context_destructor(struct run_proc_context *run_ctx) 318 { 319 struct proc_context *proc; 320 321 /* Get rid of signal handler */ 322 TALLOC_FREE(run_ctx->se); 323 324 /* Kill any pending processes */ 325 while ((proc = run_ctx->plist) != NULL) { 326 DLIST_REMOVE(run_ctx->plist, proc); 327 talloc_free(proc); 328 } 329 330 return 0; 331 } 332 333 struct run_proc_state { 334 struct tevent_context *ev; 335 struct run_proc_context *run_ctx; 336 struct proc_context *proc; 337 338 struct run_proc_result result; 339 char *output; 340 pid_t pid; 341 }; 342 343 static int run_proc_state_destructor(struct run_proc_state *state); 344 static void run_proc_timedout(struct tevent_req *subreq); 345 346 struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx, 347 struct tevent_context *ev, 348 struct run_proc_context *run_ctx, 349 const char *path, const char **argv, 350 int stdin_fd, struct timeval timeout) 351 { 352 struct tevent_req *req; 353 struct run_proc_state *state; 354 struct stat st; 355 int ret; 356 357 req = tevent_req_create(mem_ctx, &state, struct run_proc_state); 358 if (req == NULL) { 359 return NULL; 360 } 361 362 state->ev = ev; 363 state->run_ctx = run_ctx; 364 state->pid = -1; 365 366 ret = stat(path, &st); 367 if (ret != 0) { 368 state->result.err = errno; 369 tevent_req_done(req); 370 return tevent_req_post(req, ev); 371 } 372 373 if (! (st.st_mode & S_IXUSR)) { 374 state->result.err = EACCES; 375 tevent_req_done(req); 376 return tevent_req_post(req, ev); 377 } 378 379 state->proc = proc_new(run_ctx, run_ctx); 380 if (tevent_req_nomem(state->proc, req)) { 381 return tevent_req_post(req, ev); 382 } 383 384 state->proc->req = req; 385 DLIST_ADD(run_ctx->plist, state->proc); 386 387 ret = proc_start(state->proc, ev, path, argv, stdin_fd); 388 if (ret != 0) { 389 tevent_req_error(req, ret); 390 return tevent_req_post(req, ev); 391 } 392 393 talloc_set_destructor(state, run_proc_state_destructor); 394 395 if (! tevent_timeval_is_zero(&timeout)) { 396 struct tevent_req *subreq; 397 398 subreq = tevent_wakeup_send(state, ev, timeout); 399 if (tevent_req_nomem(subreq, req)) { 400 return tevent_req_post(req, ev); 401 } 402 tevent_req_set_callback(subreq, run_proc_timedout, req); 403 } 404 405 return req; 406 } 407 408 static int run_proc_state_destructor(struct run_proc_state *state) 409 { 410 /* Do not get rid of the child process if timeout has occurred */ 411 if (state->proc->req != NULL) { 412 state->proc->req = NULL; 413 DLIST_REMOVE(state->run_ctx->plist, state->proc); 414 talloc_free(state->proc); 415 } 416 417 return 0; 418 } 419 420 static void run_proc_done(struct tevent_req *req) 421 { 422 struct run_proc_state *state = tevent_req_data( 423 req, struct run_proc_state); 424 425 state->proc->req = NULL; 426 427 state->result = state->proc->result; 428 if (state->proc->output != NULL) { 429 state->output = talloc_steal(state, state->proc->output); 430 } 431 talloc_steal(state, state->proc); 432 433 tevent_req_done(req); 434 } 435 436 static void run_proc_kill(struct tevent_req *req) 437 { 438 struct run_proc_state *state = tevent_req_data( 439 req, struct run_proc_state); 440 441 state->proc->req = NULL; 442 443 state->result.sig = SIGKILL; 444 445 tevent_req_done(req); 446 } 447 448 static void run_proc_timedout(struct tevent_req *subreq) 449 { 450 struct tevent_req *req = tevent_req_callback_data( 451 subreq, struct tevent_req); 452 struct run_proc_state *state = tevent_req_data( 453 req, struct run_proc_state); 454 bool status; 455 456 state->proc->req = NULL; 457 458 status = tevent_wakeup_recv(subreq); 459 TALLOC_FREE(subreq); 460 if (! status) { 461 tevent_req_error(req, EIO); 462 return; 463 } 464 465 state->result.err = ETIMEDOUT; 466 if (state->proc->output != NULL) { 467 state->output = talloc_steal(state, state->proc->output); 468 } 469 state->pid = state->proc->pid; 470 471 tevent_req_done(req); 472 } 473 474 bool run_proc_recv(struct tevent_req *req, int *perr, 475 struct run_proc_result *result, pid_t *pid, 476 TALLOC_CTX *mem_ctx, char **output) 477 { 478 struct run_proc_state *state = tevent_req_data( 479 req, struct run_proc_state); 480 int ret; 481 482 if (tevent_req_is_unix_error(req, &ret)) { 483 if (perr != NULL) { 484 *perr = ret; 485 } 486 return false; 487 } 488 489 if (result != NULL) { 490 *result = state->result; 491 } 492 493 if (pid != NULL) { 494 *pid = state->pid; 495 } 496 497 if (output != NULL) { 498 *output = talloc_steal(mem_ctx, state->output); 499 } 500 501 return true; 502 } 503