summaryrefslogtreecommitdiff
path: root/src/providers/child_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/child_common.c')
-rw-r--r--src/providers/child_common.c110
1 files changed, 90 insertions, 20 deletions
diff --git a/src/providers/child_common.c b/src/providers/child_common.c
index b9802557..a8a4e040 100644
--- a/src/providers/child_common.c
+++ b/src/providers/child_common.c
@@ -33,6 +33,42 @@
#include "db/sysdb.h"
#include "providers/child_common.h"
+struct sss_child_ctx {
+ struct tevent_signal *sige;
+ pid_t pid;
+ int child_status;
+ sss_child_callback_t cb;
+ void *pvt;
+};
+
+int child_handler_setup(struct tevent_context *ev, int pid,
+ sss_child_callback_t cb, void *pvt)
+{
+ struct sss_child_ctx *child_ctx;
+
+ DEBUG(8, ("Setting up signal handler up for pid [%d]\n", pid));
+
+ child_ctx = talloc_zero(ev, struct sss_child_ctx);
+ if (child_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ child_ctx->sige = tevent_add_signal(ev, child_ctx, SIGCHLD, SA_SIGINFO,
+ child_sig_handler, child_ctx);
+ if(!child_ctx->sige) {
+ /* Error setting up signal handler */
+ talloc_free(child_ctx);
+ return ENOMEM;
+ }
+
+ child_ctx->pid = pid;
+ child_ctx->cb = cb;
+ child_ctx->pvt = pvt;
+
+ DEBUG(8, ("Signal handler set up for pid [%d]\n", pid));
+ return EOK;
+}
+
/* Async communication with the child process via a pipe */
struct write_pipe_state {
@@ -256,37 +292,71 @@ void fd_nonblocking(int fd)
return;
}
+static void child_invoke_callback(struct tevent_context *ev,
+ struct tevent_immediate *imm,
+ void *pvt);
void child_sig_handler(struct tevent_context *ev,
struct tevent_signal *sige, int signum,
int count, void *__siginfo, void *pvt)
{
- int ret;
- int child_status;
+ int ret, err;
+ struct sss_child_ctx *child_ctx;
+ struct tevent_immediate *imm;
+
+ if (count <= 0) {
+ DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));
+ return;
+ }
+
+ child_ctx = talloc_get_type(pvt, struct sss_child_ctx);
+ DEBUG(7, ("Waiting for child [%d].\n", child_ctx->pid));
- DEBUG(7, ("Waiting for [%d] childeren.\n", count));
- do {
- errno = 0;
- ret = waitpid(-1, &child_status, WNOHANG);
-
- if (ret == -1) {
- DEBUG(1, ("waitpid failed [%d][%s].\n", errno, strerror(errno)));
- } else if (ret == 0) {
- DEBUG(1, ("waitpid did not found a child with changed status.\n"));
- } else {
- if (WEXITSTATUS(child_status) != 0) {
- DEBUG(1, ("child [%d] failed with status [%d].\n", ret,
- child_status));
- } else {
- DEBUG(4, ("child [%d] finished successful.\n", ret));
- }
+ errno = 0;
+ ret = waitpid(child_ctx->pid, &child_ctx->child_status, WNOHANG);
+
+ if (ret == -1) {
+ err = errno;
+ DEBUG(1, ("waitpid failed [%d][%s].\n", err, strerror(err)));
+ } else if (ret == 0) {
+ DEBUG(1, ("waitpid did not found a child with changed status.\n"));
+ } else if WIFEXITED(child_ctx->child_status) {
+ if (WEXITSTATUS(child_ctx->child_status) != 0) {
+ DEBUG(1, ("child [%d] failed with status [%d].\n", ret,
+ child_ctx->child_status));
+ } else {
+ DEBUG(4, ("child [%d] finished successfully.\n", ret));
}
- --count;
- } while (count < 0);
+ /* Invoke the callback in a tevent_immediate handler
+ * so that it is safe to free the tevent_signal *
+ */
+ imm = tevent_create_immediate(ev);
+ if (imm == NULL) {
+ DEBUG(0, ("Out of memory invoking sig handler callback\n"));
+ return;
+ }
+
+ tevent_schedule_immediate(imm, ev,child_invoke_callback,
+ child_ctx);
+ }
return;
}
+static void child_invoke_callback(struct tevent_context *ev,
+ struct tevent_immediate *imm,
+ void *pvt)
+{
+ struct sss_child_ctx *child_ctx =
+ talloc_get_type(pvt, struct sss_child_ctx);
+ if (child_ctx->cb) {
+ child_ctx->cb(child_ctx->child_status, child_ctx->sige, child_ctx->pvt);
+ }
+
+ /* Stop monitoring for this child */
+ talloc_free(child_ctx);
+}
+
static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
int child_debug_fd,
const char *binary,