ensure that child tasks die when the parent dies
authorAndrew Tridgell <tridge@samba.org>
Fri, 7 Aug 2009 07:21:54 +0000 (17:21 +1000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 7 Aug 2009 07:24:48 +0000 (17:24 +1000)
Previously we relied on process groups and SIGTERM to ensure that
child tasks died in the standard process model when the parent task
died. This doesn't work when the server is run in interactive mode, as
in that case we don't call become_daemon() and don't get a separate
process group.

The fix is to have a pipe held open by the parent server process, and
inherited by child tasks. If the parent exits then the write side of
the pipe is implicitly closed, which causes an event in the child
tasks that causes them to exit

source4/smbd/process_standard.c

index 137e0a7ce02c07e5a95ebd11fdb773e42331f55f..730e185e5a2e312cdea048f83162e8327efc7eea 100644 (file)
@@ -44,14 +44,30 @@ static int none_setproctitle(const char *fmt, ...)
 }
 #endif
 
+/* we hold a pipe open in the parent, and the any child
+   processes wait for EOF on that pipe. This ensures that
+   children die when the parent dies */
+static int child_pipe[2];
+
 /*
   called when the process model is selected
 */
 static void standard_model_init(struct tevent_context *ev)
 {
+       pipe(child_pipe);
        signal(SIGCHLD, SIG_IGN);
 }
 
+/*
+  handle EOF on the child pipe
+*/
+static void standard_pipe_handler(struct tevent_context *event_ctx, struct tevent_fd *fde, 
+                                 uint16_t flags, void *private_data)
+{
+       DEBUG(10,("Child %d exiting\n", (int)getpid()));
+       exit(0);
+}
+
 /*
   called when a listening socket becomes readable. 
 */
@@ -114,6 +130,10 @@ static void standard_accept_connection(struct tevent_context *ev,
                DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
        }
 
+       tevent_add_fd(ev2, ev2, child_pipe[0], TEVENT_FD_READ,
+                     standard_pipe_handler, NULL);
+       close(child_pipe[1]);
+
        /* Ensure that the forked children do not expose identical random streams */
        set_need_random_reseed();
 
@@ -177,6 +197,10 @@ static void standard_new_task(struct tevent_context *ev,
                DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
        }
 
+       tevent_add_fd(ev2, ev2, child_pipe[0], TEVENT_FD_READ,
+                     standard_pipe_handler, NULL);
+       close(child_pipe[1]);
+
        /* Ensure that the forked children do not expose identical random streams */
        set_need_random_reseed();