* @param vb as returned by xlat_frame_eval()
* @param env_pairs VPs to put into into the environment. May be NULL.
* @param[out] pid_p The PID of the child
+ * @param[out] fd_p The stdout FD of the child
* @return
* - <0 on error
- * - >= 0 on success, with FD to read program output
+ * - 0 on success
*
* @todo - maybe take an fr_cursor_t instead of env_pairs? That
* would allow finer-grained control over the attributes to put into
* the environment.
*/
-int fr_exec_wait_start(REQUEST *request, fr_value_box_t *vb, VALUE_PAIR *env_pairs, pid_t *pid_p)
+int fr_exec_wait_start(REQUEST *request, fr_value_box_t *vb, VALUE_PAIR *env_pairs, pid_t *pid_p, int *fd_p)
{
int argc;
char **envp;
char **argv;
pid_t pid;
fr_value_box_t *first;
- int from_child[2];
+ int from_child[2] = {-1, -1};
/*
* Clean up any previous child processes.
argc = fr_value_box_list_flatten_argv(request, &argv, vb);
if (argc < 0) return -1;
- if (pipe(from_child) < 0) {
- fr_strerror_printf("Failed opening pipe to read from child - %s", fr_strerror());
- return -1;
+ if (fd_p) {
+ if (pipe(from_child) < 0) {
+ fr_strerror_printf("Failed opening pipe to read from child - %s", fr_strerror());
+ return -1;
+ }
}
pid = fork();
* The child never returns from calling fr_exec_child();
*/
if (pid == 0) {
- int unused[2];
+ int unused[2] = {-1, -1};
- fr_exec_child(request, argv, envp, false, NULL, NULL, unused, from_child);
+ fr_exec_child(request, argv, envp, false, NULL, fd_p, unused, from_child);
}
/*
* Parent process. Do all necessary cleanups.
*/
talloc_free(envp);
- close(from_child[1]);
if (pid < 0) {
ERROR("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
- close(from_child[0]);
+ if (fd_p) close(*fd_p);
talloc_free(argv);
return -1;
}
* from.
*/
*pid_p = pid;
- fr_nonblock(from_child[0]);
- return from_child[0];
+
+ if (fd_p) fr_nonblock(*fd_p);
+
+ return 0;
}
/** Remember child processes.
return UNLANG_ACTION_CALCULATE_RESULT;
}
+ /*
+ * We might want to just get the status of the program,
+ * and not care about the output.
+ *
+ * If we do care about the output, it's unquoted, and tainted.
+ */
+ if (state->out) {
+ fr_type_t type = FR_TYPE_STRING;
+
+ MEM(state->box = fr_value_box_alloc(state->ctx, FR_TYPE_STRING, NULL, true));
+ if (fr_value_box_from_str(state->box, state->box, &type, NULL,
+ state->buffer, state->ptr - state->buffer, 0, true) < 0) {
+ TALLOC_FREE(state->box);
+ *presult = RLM_MODULE_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+ }
+
/*
* Ensure that the callers resume function is called.
*/
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
- int fd;
+ int fd = -1;
pid_t pid;
+ int *fd_p = NULL;
+
+ /*
+ * @todo - if there's no state->out, then we don't need
+ * to have an FD, and we don't need to have a buffer.
+ */
+ if (state->out) fd_p = &fd;
- fd = fr_exec_wait_start(request, state->box, NULL, &pid);
- if (fd < 0) {
+ if (fr_exec_wait_start(request, state->box, NULL, &pid, fd_p) < 0) {
REDEBUG("Failed executing program - %s", fr_strerror());
fail:
*presult = RLM_MODULE_FAIL;
return UNLANG_ACTION_CALCULATE_RESULT;
}
+ TALLOC_FREE(state->box); /* this is the xlat expansion, and not the output string we want */
+
state->fd = fd;
state->pid = pid;
state->status = 1; /* default to program didn't work */
- MEM(state->buffer = talloc_array(state, char, 024));
/*
* Kill the child process after a period of time.
goto fail;
}
- if (fr_event_fd_insert(state->ctx, request->el, state->fd, unlang_tmpl_exec_read, NULL, NULL, request) < 0) {
- REDEBUG("Failed adding event - %s", fr_strerror());
- unlang_tmpl_exec_cleanup(request);
- goto fail;
+ /*
+ * If the caller doesn't want the output box, we can just skip reading from the FD.
+ */
+ if (state->fd >= 0) {
+ if (fr_event_fd_insert(state->ctx, request->el, state->fd, unlang_tmpl_exec_read, NULL, NULL, request) < 0) {
+ REDEBUG("Failed adding event - %s", fr_strerror());
+ unlang_tmpl_exec_cleanup(request);
+ goto fail;
+ }
+
+ MEM(state->buffer = talloc_array(state, char, 1024));
}
frame->interpret = unlang_tmpl_exec_wait_final;