static void smbd_scavenger_msg(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id src, DATA_BLOB *data) { struct smbd_scavenger_state *state = talloc_get_type_abort(private_data, struct smbd_scavenger_state); TALLOC_CTX *frame = talloc_stackframe(); struct server_id self = messaging_server_id(msg_ctx); struct scavenger_message *msg = NULL; struct server_id_buf tmp1, tmp2; DEBUG(10, ("smbd_scavenger_msg: %s got message from %s\n", server_id_str_buf(self, &tmp1), server_id_str_buf(src, &tmp2))); if (server_id_equal(&state->parent_id, &self)) { NTSTATUS status; if (!smbd_scavenger_running(state) && !smbd_scavenger_start(state)) { DEBUG(2, ("Failed to start scavenger\n")); goto done; } DEBUG(10, ("forwarding message to scavenger\n")); status = messaging_send(msg_ctx, *state->scavenger_id, msg_type, data); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("forwarding message to scavenger failed: " "%s\n", nt_errstr(status))); goto done; } goto done; } if (!state->am_scavenger) { DEBUG(10, ("im not the scavenger: ignore message\n")); goto done; } if (!server_id_equal(&state->parent_id, &src)) { DEBUG(10, ("scavenger: ignore spurious message\n")); goto done; } DEBUG(10, ("scavenger: got a message\n")); msg = (struct scavenger_message*)data->data; scavenger_add_timer(state, msg); done: talloc_free(frame); }
static bool smbd_scavenger_start(struct smbd_scavenger_state *state) { struct server_id self = messaging_server_id(state->msg); struct tevent_fd *fde = NULL; int fds[2]; int ret; uint64_t unique_id; bool ok; SMB_ASSERT(server_id_equal(&state->parent_id, &self)); if (smbd_scavenger_running(state)) { DEBUG(10, ("scavenger %s already running\n", server_id_str(talloc_tos(), state->scavenger_id))); return true; } if (state->scavenger_id != NULL) { DEBUG(10, ("scavenger zombie %s, cleaning up\n", server_id_str(talloc_tos(), state->scavenger_id))); TALLOC_FREE(state->scavenger_id); } state->scavenger_id = talloc_zero(state, struct server_id); if (state->scavenger_id == NULL) { DEBUG(2, ("Out of memory\n")); goto fail; } talloc_set_destructor(state->scavenger_id, smbd_scavenger_server_id_destructor); ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); if (ret == -1) { DEBUG(2, ("socketpair failed: %s", strerror(errno))); goto fail; } smb_set_close_on_exec(fds[0]); smb_set_close_on_exec(fds[1]); unique_id = serverid_get_random_unique_id(); ret = fork(); if (ret == -1) { int err = errno; close(fds[0]); close(fds[1]); DEBUG(0, ("fork failed: %s", strerror(err))); goto fail; } if (ret == 0) { /* child */ NTSTATUS status; close(fds[0]); am_parent = NULL; set_my_unique_id(unique_id); status = reinit_after_fork(state->msg, state->ev, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("reinit_after_fork failed: %s\n", nt_errstr(status))); exit_server("reinit_after_fork failed"); return false; } prctl_set_comment("smbd-scavenger"); state->am_scavenger = true; *state->scavenger_id = messaging_server_id(state->msg); scavenger_setup_sig_term_handler(state->ev); serverid_register(*state->scavenger_id, FLAG_MSG_GENERAL); ok = scavenger_say_hello(fds[1], *state->scavenger_id); if (!ok) { DEBUG(2, ("scavenger_say_hello failed\n")); exit_server("scavenger_say_hello failed"); return false; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[1], TEVENT_FD_READ, smbd_scavenger_parent_dead, state); if (fde == NULL) { DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) " "failed\n")); exit_server("tevent_add_fd(smbd_scavenger_parent_dead) " "failed"); return false; } tevent_fd_set_auto_close(fde); ret = smbd_scavenger_main(state); DEBUG(10, ("scavenger ended: %d\n", ret)); exit_server_cleanly("scavenger ended"); return false; } /* parent */ close(fds[1]); ok = scavenger_wait_hello(fds[0], state->scavenger_id); if (!ok) { close(fds[0]); goto fail; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[0], TEVENT_FD_READ, smbd_scavenger_done, state); if (fde == NULL) { close(fds[0]); goto fail; } tevent_fd_set_auto_close(fde); return true; fail: TALLOC_FREE(state->scavenger_id); return false; }