s3:smbd: let smbd/nmbd/winbindd child processes terminate if the parent process died.
authorMichael Adam <obnox@samba.org>
Thu, 15 Mar 2012 15:29:27 +0000 (16:29 +0100)
committerMichael Adam <obnox@samba.org>
Thu, 15 Mar 2012 17:41:37 +0000 (18:41 +0100)
This applies to all child processes making use of reinit_after_fork().
It is implemented by establishing a pipe between parent and child.
The child watches for EOF on the read end of the pipe, indidcating
an exited parent.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

source3/include/proto.h
source3/lib/util.c
source3/nmbd/nmbd.c
source3/smbd/server.c
source3/winbindd/winbindd.c

index e0d9f3117e8e948612a73fc97e54a25b91f7421e..e8a0d42b3ca763c73ddebfa7b6772025ab442ac5 100644 (file)
@@ -484,6 +484,7 @@ char *unix_clean_name(TALLOC_CTX *ctx, const char *s);
 char *clean_name(TALLOC_CTX *ctx, const char *s);
 ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos);
 int set_blocking(int fd, bool set);
+NTSTATUS init_before_fork(void);
 NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
                           struct event_context *ev_ctx,
                           bool parent_longlived);
index 822db43fef2c234e2dd8007d58d2ce81cfeaae8b..fa2cc9fd83de57c0cbb110aceb1f45d31503bca5 100644 (file)
@@ -356,6 +356,46 @@ ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos
 #endif
 }
 
+static int reinit_after_fork_pipe[2] = { -1, -1 };
+
+NTSTATUS init_before_fork(void)
+{
+       int ret;
+
+       ret = pipe(reinit_after_fork_pipe);
+       if (ret == -1) {
+               NTSTATUS status;
+
+               status = map_nt_error_from_unix_common(errno);
+
+               DEBUG(0, ("Error creating child_pipe: %s\n",
+                         nt_errstr(status)));
+
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+/**
+ * Detect died parent by detecting EOF on the pipe
+ */
+static void reinit_after_fork_pipe_handler(struct tevent_context *ev,
+                                          struct tevent_fd *fde,
+                                          uint16_t flags,
+                                          void *private_data)
+{
+       char c;
+
+       if (read(reinit_after_fork_pipe[0], &c, 1) != 1) {
+               /*
+                * we have reached EOF on stdin, which means the
+                * parent has exited. Shutdown the server
+                */
+               (void)kill(getpid(), SIGTERM);
+       }
+}
+
 
 NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
                           struct event_context *ev_ctx,
@@ -363,6 +403,11 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
 {
        NTSTATUS status = NT_STATUS_OK;
 
+       if (reinit_after_fork_pipe[1] != -1) {
+               close(reinit_after_fork_pipe[1]);
+               reinit_after_fork_pipe[1] = -1;
+       }
+
        /* Reset the state of the random
         * number generation system, so
         * children do not get the same random
@@ -380,6 +425,17 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
                smb_panic(__location__ ": Failed to re-initialise event context");
        }
 
+       if (reinit_after_fork_pipe[0] != -1) {
+               struct tevent_fd *fde;
+
+               fde = tevent_add_fd(ev_ctx, ev_ctx /* TALLOC_CTX */,
+                                   reinit_after_fork_pipe[0], TEVENT_FD_READ,
+                                   reinit_after_fork_pipe_handler, NULL);
+               if (fde == NULL) {
+                       smb_panic(__location__ ": Failed to add reinit_after_fork pipe event");
+               }
+       }
+
        if (msg_ctx) {
                /*
                 * For clustering, we need to re-init our ctdbd connection after the
index 52d7ed9e4e7d4a948711214f9c02efc1d86501b0..eff1eca2f1657ae6cef69030775e21d54f347e19 100644 (file)
@@ -951,6 +951,17 @@ static bool open_sockets(bool isdaemon, int port)
                exit(1);
        }
 
+       /*
+        * Do not initialize the parent-child-pipe before becoming
+        * a daemon: this is used to detect a died parent in the child
+        * process.
+        */
+       status = init_before_fork();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+               exit(1);
+       }
+
        if (!nmbd_setup_sig_term_handler(msg))
                exit(1);
        if (!nmbd_setup_stdin_handler(msg, !Fork))
index aa3da1f74341c0334ca1dbd170b14db10bb13d0e..851b4608a7e7f32ac7559d29bf8784081219c5af 100644 (file)
@@ -57,6 +57,8 @@ struct smbd_parent_context {
        /* the list of current child processes */
        struct smbd_child_pid *children;
        size_t num_children;
+       /* pipe for detecting death of parent process in child: */
+       int child_pipe[2];
 
        struct timed_event *cleanup_te;
 };
@@ -1231,6 +1233,17 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       /*
+        * Do not initialize the parent-child-pipe before becoming
+        * a daemon: this is used to detect a died parent in the child
+        * process.
+        */
+       status = init_before_fork();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+               exit(1);
+       }
+
        smbd_server_conn->msg_ctx = msg_ctx;
 
        parent = talloc_zero(ev_ctx, struct smbd_parent_context);
index d1d36fd0073859c71104a6cfd775cf199678ce6f..66e53d9caec6ad2fe0cfa89308ba45afc20d72c3 100644 (file)
@@ -1461,6 +1461,17 @@ int main(int argc, char **argv, char **envp)
                exit(1);
        }
 
+       /*
+        * Do not initialize the parent-child-pipe before becoming
+        * a daemon: this is used to detect a died parent in the child
+        * process.
+        */
+       status = init_before_fork();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+               exit(1);
+       }
+
        winbindd_register_handlers(!Fork);
 
        status = init_system_info();