s3/smbd: start smb_direct_daemon
authorRalph Boehme <slow@samba.org>
Sun, 18 Sep 2016 15:28:37 +0000 (17:28 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 1 Jun 2018 12:35:03 +0000 (14:35 +0200)
Pair-programmed-with: Stefan Metzmacher <metze@samba.org>

source3/smbd/server.c

index b73ac2bb73108afe2e071f9c7ca21c41bf1f037c..18c21473c3e290675473ddd99df68601b1f7f1ca 100644 (file)
@@ -54,6 +54,7 @@
 #include "lib/util/sys_rw.h"
 #include "cleanupdb.h"
 #include "g_lock.h"
+#include "libcli/smb/smb_direct.h"
 
 #ifdef CLUSTER_SUPPORT
 #include "ctdb_protocol.h"
@@ -77,6 +78,7 @@ struct smbd_parent_context {
 
        struct server_id cleanupd;
        struct server_id notifyd;
+       pid_t smb_direct_daemon_pid;
 
        struct tevent_timer *cleanup_te;
 };
@@ -784,6 +786,235 @@ static void cleanupd_started(struct tevent_req *req)
        }
 }
 
+static void smb_direct_daemon_stopped(struct tevent_req *req);
+
+static bool smb_direct_daemon_init(struct tevent_context *ev,
+                                  struct messaging_context *msg,
+                                  bool interactive,
+                                  pid_t *ppid)
+{
+       struct tevent_req *req;
+       pid_t pid;
+       NTSTATUS status;
+       ssize_t rwret;
+       int ret;
+       bool ok;
+       char c;
+       int up_pipe[2];
+
+       sec_init();
+
+
+       if (interactive) {
+               req = smb_direct_daemon_send(ev, ev);
+               *ppid = getpid();
+               return (req != NULL);
+       }
+
+       ret = pipe(up_pipe);
+       if (ret == -1) {
+               DBG_WARNING("pipe failed: %s\n", strerror(errno));
+               return false;
+       }
+
+       pid = fork();
+       if (pid == -1) {
+               DBG_WARNING("fork failed: %s\n", strerror(errno));
+               close(up_pipe[0]);
+               close(up_pipe[1]);
+               return false;
+       }
+
+       if (pid != 0) {
+
+               close(up_pipe[1]);
+               rwret = sys_read(up_pipe[0], &c, 1);
+               close(up_pipe[0]);
+
+               if (rwret == -1) {
+                       DBG_WARNING("sys_read failed: %s\n", strerror(errno));
+                       return false;
+               }
+               if (rwret == 0) {
+                       DBG_WARNING("smb_direct_daemon could not start\n");
+                       return false;
+               }
+               if (c != 0) {
+                       DBG_WARNING("smb_direct_daemon returned %d\n", (int)c);
+                       return false;
+               }
+
+               DBG_DEBUG("Started smb_direct_daemon pid=%d\n", (int)pid);
+
+               if (am_parent != NULL) {
+                       add_child_pid(am_parent, pid);
+               }
+
+               *ppid = pid;
+               return true;
+       }
+
+       close(up_pipe[0]);
+
+       status = smbd_reinit_after_fork(msg, ev, true, "smb_direct_daemon");
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("reinit_after_fork failed: %s\n",
+                           nt_errstr(status));
+               c = 1;
+               sys_write(up_pipe[1], &c, 1);
+
+               exit(1);
+       }
+
+       req = smb_direct_daemon_send(ev, ev);
+       if (req == NULL) {
+               DBG_WARNING("smb_direct_daemon_send failed\n");
+               c = 2;
+               sys_write(up_pipe[1], &c, 1);
+
+               exit(1);
+       }
+
+       tevent_req_set_callback(req, smb_direct_daemon_stopped, msg);
+
+       c = 0;
+       rwret = sys_write(up_pipe[1], &c, 1);
+       close(up_pipe[1]);
+
+       if (rwret == -1) {
+               DBG_WARNING("sys_write failed: %s\n", strerror(errno));
+               exit(1);
+       }
+       if (rwret != 1) {
+               DBG_WARNING("sys_write could not write result\n");
+               exit(1);
+       }
+
+       ok = tevent_req_poll(req, ev);
+       if (!ok) {
+               DBG_WARNING("tevent_req_poll returned %s\n", strerror(errno));
+       }
+
+       ret = smb_direct_daemon_recv(req);
+       TALLOC_FREE(req);
+
+       if (ret != 0) {
+               DBG_WARNING("smb_direct_daemon_recv returned [%s]\n",
+                           strerror(ret));
+       }
+
+       exit(ret);
+}
+
+static void smb_direct_daemon_stopped(struct tevent_req *req)
+{
+       int ret;
+
+       ret = smb_direct_daemon_recv(req);
+       DBG_WARNING("smb_direct_daemon stopped: [%s/%d]\n",
+                   strerror(ret), ret);
+}
+
+static void smb_direct_daemon_init_trigger(struct tevent_req *req);
+
+struct smb_direct_daemon_init_state {
+       bool ok;
+       struct tevent_context *ev;
+       struct messaging_context *msg;
+       pid_t *smb_direct_daemon_pid;
+};
+
+static struct tevent_req *smb_direct_daemon_init_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct messaging_context *msg,
+       pid_t *smb_direct_daemon_pid)
+{
+       struct tevent_req *req = NULL;
+       struct tevent_req *subreq = NULL;
+       struct smb_direct_daemon_init_state *state = NULL;
+
+       req = tevent_req_create(mem_ctx, &state, struct smb_direct_daemon_init_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       *state = (struct smb_direct_daemon_init_state) {
+               .ev = ev,
+               .msg = msg,
+               .smb_direct_daemon_pid = smb_direct_daemon_pid
+       };
+
+       subreq = tevent_wakeup_send(state, ev, tevent_timeval_current_ofs(0, 0));
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq, smb_direct_daemon_init_trigger, req);
+       return req;
+}
+
+static void smb_direct_daemon_init_trigger(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smb_direct_daemon_init_state *state = tevent_req_data(
+               req, struct smb_direct_daemon_init_state);
+       bool ok;
+
+       DBG_NOTICE("Triggering smb_direct_daemon startup\n");
+
+       ok = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               tevent_req_error(req, ENOMEM);
+               return;
+       }
+
+       state->ok = smb_direct_daemon_init(state->ev, state->msg,
+                                          false, state->smb_direct_daemon_pid);
+       if (state->ok) {
+               DBG_WARNING("smb_direct_daemon restarted\n");
+               tevent_req_done(req);
+               return;
+       }
+
+       DBG_NOTICE("smb_direct_daemon startup failed, rescheduling\n");
+
+       subreq = tevent_wakeup_send(state, state->ev,
+                                   tevent_timeval_current_ofs(1, 0));
+       if (tevent_req_nomem(subreq, req)) {
+               DBG_ERR("smb_direct_daemon restart failed, giving up\n");
+               return;
+       }
+
+       tevent_req_set_callback(subreq, smb_direct_daemon_init_trigger, req);
+       return;
+}
+
+static bool smb_direct_daemon_init_recv(struct tevent_req *req)
+{
+       struct smb_direct_daemon_init_state *state = tevent_req_data(
+               req, struct smb_direct_daemon_init_state);
+       bool ok = state->ok;
+
+       tevent_req_received(req);
+
+       return ok;
+}
+
+static void smb_direct_daemon_started(struct tevent_req *req)
+{
+       bool ok;
+
+       ok = smb_direct_daemon_init_recv(req);
+       TALLOC_FREE(req);
+       if (!ok) {
+               DBG_ERR("Failed to restart smb_direct_daemon, giving up\n");
+               return;
+       }
+}
+
 static void remove_child_pid(struct smbd_parent_context *parent,
                             pid_t pid,
                             bool unclean_shutdown)
@@ -846,6 +1077,24 @@ static void remove_child_pid(struct smbd_parent_context *parent,
                return;
        }
 
+       if (pid == parent->smb_direct_daemon_pid) {
+               struct tevent_req *req;
+               struct tevent_context *ev = messaging_tevent_context(
+                       parent->msg_ctx);
+
+               DBG_WARNING("Restarting smb_direct_daemon\n");
+
+               req = smb_direct_daemon_init_send(
+                       ev, ev, parent->msg_ctx, &parent->smb_direct_daemon_pid);
+               if (req == NULL) {
+                       DBG_ERR("Failed to restart smb_direct_daemon\n");
+                       return;
+               }
+               tevent_req_set_callback(req, smb_direct_daemon_started, parent);
+               return;
+
+       }
+
        ok = cleanupdb_store_child(pid, unclean_shutdown);
        if (!ok) {
                DBG_ERR("cleanupdb_store_child failed\n");
@@ -1970,6 +2219,12 @@ extern void build_options(bool screen);
                exit_daemon("Samba cannot init the cleanupd", EACCES);
        }
 
+       if (!smb_direct_daemon_init(ev_ctx, msg_ctx, interactive,
+                                   &parent->smb_direct_daemon_pid))
+       {
+               exit_daemon("Samba cannot init the smb_direct_daemon", EACCES);
+       }
+
        if (!messaging_parent_dgm_cleanup_init(msg_ctx)) {
                exit(1);
        }