From: Nick Porter Date: Tue, 15 Jun 2021 21:24:28 +0000 (+0100) Subject: v4: Amend async exec calls to ensure both child process exited and fd callbacks have... X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=325c1710171e7df482b614d9b9f85df2ea34cc9e;p=thirdparty%2Ffreeradius-server.git v4: Amend async exec calls to ensure both child process exited and fd callbacks have completed (#4113) * Improve debug message - program has exited, not necessarily failed * Report all output from exec * Only resume unlang execution when both the child process has... ... exited and the fd event has seen an EOF --- diff --git a/src/lib/server/exec.c b/src/lib/server/exec.c index 35c93573ad0..cf0f3b454f2 100644 --- a/src/lib/server/exec.c +++ b/src/lib/server/exec.c @@ -932,7 +932,7 @@ static void exec_waitpid(UNUSED fr_event_list_t *el, UNUSED pid_t pid, int statu request_t *request = exec->request; if (WIFEXITED(status)) { - RDEBUG("Program failed with status code %d", WEXITSTATUS(status)); + RDEBUG("Program exited with status code %d", WEXITSTATUS(status)); exec->status = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { RDEBUG("Program exited due to signal with status code %d", WTERMSIG(status)); @@ -948,6 +948,10 @@ static void exec_waitpid(UNUSED fr_event_list_t *el, UNUSED pid_t pid, int statu * "pipe has been closed" signal */ if (exec->stdout_fd >= 0) { + if (exec->stdout_used) { + RDEBUG("Program exited without EOF being read"); + return; + } (void) fr_event_fd_delete(exec->request->el, exec->stdout_fd, FR_EVENT_FILTER_IO); close(exec->stdout_fd); exec->stdout_fd = -1; @@ -1001,7 +1005,7 @@ static void exec_timeout( /* * Callback to read stdout from an exec into the pre-prepared extensible sbuff */ -static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx) { +static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, int flags, void *uctx) { fr_exec_state_t *exec = uctx; request_t *request = exec->request; ssize_t data_len, remaining; @@ -1046,6 +1050,24 @@ static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, UNUSED int flag fr_sbuff_advance(&exec->stdout_buff, data_len); } while (remaining == data_len); /* If process returned maximum output, loop again */ + if (flags & EV_EOF) { + /* + * We've received EOF - so the process has finished writing + * Remove event and tidy up + */ + (void) fr_event_fd_delete(exec->request->el, fd, FR_EVENT_FILTER_IO); + close(fd); + exec->stdout_fd = -1; + + if (exec->pid == 0) { + /* + * Child has already exited - unlang can resume + */ + if (exec->ev) fr_event_timer_delete(&exec->ev); + unlang_interpret_mark_runnable(exec->request); + } + } + /* * Only print if we got additional data */ diff --git a/src/modules/rlm_exec/rlm_exec.c b/src/modules/rlm_exec/rlm_exec.c index 7a7081c2148..b63c09d2954 100644 --- a/src/modules/rlm_exec/rlm_exec.c +++ b/src/modules/rlm_exec/rlm_exec.c @@ -379,7 +379,7 @@ static unlang_action_t mod_exec_wait_resume(rlm_rcode_t *p_result, module_ctx_t fr_pair_list_t vps, *output_pairs; fr_value_box_t *box = fr_dlist_head(&m->box); - RDEBUG("EXEC GOT -- %pV", box); + RDEBUG("EXEC GOT -- %pM", &m->box); fr_pair_list_init(&vps); output_pairs = tmpl_list_head(request, inst->output_list);