void (*)(struct tevent_context *,
struct loadparm_context *, struct server_id,
void *),
- void *);
+ void *,
+ int);
/* function to terminate a connection or task */
void (*terminate)(struct tevent_context *, struct loadparm_context *lp_ctx,
/*
called to startup a new task
*/
-static void single_new_task(struct tevent_context *ev,
+static void single_new_task(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
const char *service_name,
- void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *),
- void *private_data)
+ void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *),
+ void *private_data,
+ int from_parent_fd)
{
pid_t pid = getpid();
/* start our taskids at MAX_INT32, the first 2^31 tasks are is reserved for fd numbers */
NTSTATUS process_model_standard_init(TALLOC_CTX *);
-/* 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] = { -1, -1 };
+static int from_parent_fd;
/*
called when the process model is selected
*/
static void standard_model_init(void)
{
- int rc;
-
- rc = pipe(child_pipe);
- if (rc < 0) {
- smb_panic("Failed to initialize pipe!");
- }
}
static void sighup_signal_handler(struct tevent_context *ev,
smb_panic("Failed to re-initialise imessaging after fork");
}
- fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
+ fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
standard_pipe_handler, NULL);
if (fde == NULL) {
smb_panic("Failed to add fd handler after fork");
}
- if (child_pipe[1] != -1) {
- close(child_pipe[1]);
- child_pipe[1] = -1;
- }
-
se = tevent_add_signal(ev,
ev,
SIGHUP,
/*
called to create a new server task
*/
-static void standard_new_task(struct tevent_context *ev,
+static void standard_new_task(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
const char *service_name,
void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *),
- void *private_data)
+ void *private_data,
+ int new_from_parent_fd)
{
pid_t pid;
NTSTATUS status;
if (state == NULL) {
return;
}
+ from_parent_fd = new_from_parent_fd;
pid = fork();
smb_panic("Failed to re-initialise imessaging after fork");
}
- fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
+ fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
standard_pipe_handler, NULL);
if (fde == NULL) {
smb_panic("Failed to add fd handler after fork");
}
- if (child_pipe[1] != -1) {
- close(child_pipe[1]);
- child_pipe[1] = -1;
- }
se = tevent_add_signal(ev,
ev,
#include "lib/util/samba_modules.h"
#include "nsswitch/winbind_client.h"
#include "libds/common/roles.h"
+#include "lib/util/tfork.h"
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
struct server_state {
struct tevent_context *event_ctx;
return 0;
}
+#ifdef HAVE_PTHREAD
+static int to_children_fd = -1;
+static void atfork_prepare(void) {
+}
+static void atfork_parent(void) {
+}
+static void atfork_child(void) {
+ if (to_children_fd != -1) {
+ close(to_children_fd);
+ to_children_fd = -1;
+ }
+}
+#endif
+
/*
main server.
*/
DEBUG(0,("%s: using '%s' process model\n", binary_name, model));
- status = server_service_startup(state->event_ctx, cmdline_lp_ctx, model,
- lpcfg_server_services(cmdline_lp_ctx));
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(state);
- exit_daemon("Samba failed to start services",
- NT_STATUS_V(status));
+ {
+ int child_pipe[2];
+ int rc;
+ bool start_services = false;
+
+ rc = pipe(child_pipe);
+ if (rc < 0) {
+ TALLOC_FREE(state);
+ exit_daemon("Samba failed to open process control pipe",
+ errno);
+ }
+ smb_set_close_on_exec(child_pipe[0]);
+ smb_set_close_on_exec(child_pipe[1]);
+
+#ifdef HAVE_PTHREAD
+ to_children_fd = child_pipe[1];
+ pthread_atfork(atfork_prepare, atfork_parent,
+ atfork_child);
+ start_services = true;
+#else
+ pid_t pid;
+ struct tfork *t = NULL;
+ t = tfork_create();
+ if (t == NULL) {
+ exit_daemon(
+ "Samba unable to fork master process",
+ 0);
+ }
+ pid = tfork_child_pid(t);
+ if (pid == 0) {
+ start_services = false;
+ } else {
+ /* In the child process */
+ start_services = true;
+ close(child_pipe[1]);
+ }
+#endif
+ if (start_services) {
+ status = server_service_startup(
+ state->event_ctx, cmdline_lp_ctx, model,
+ lpcfg_server_services(cmdline_lp_ctx),
+ child_pipe[0]);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state);
+ exit_daemon("Samba failed to start services",
+ NT_STATUS_V(status));
+ }
+ }
}
if (opt_daemon) {
static NTSTATUS server_service_init(const char *name,
struct tevent_context *event_context,
struct loadparm_context *lp_ctx,
- const struct model_ops *model_ops)
+ const struct model_ops *model_ops,
+ int from_parent_fd)
{
struct registered_server *srv;
for (srv=registered_servers; srv; srv=srv->next) {
if (strcasecmp(name, srv->service_name) == 0) {
- return task_server_startup(event_context, lp_ctx, srv->service_name,
- model_ops, srv->task_init);
+ return task_server_startup(event_context, lp_ctx,
+ srv->service_name,
+ model_ops, srv->task_init,
+ from_parent_fd);
}
}
return NT_STATUS_INVALID_SYSTEM_SERVICE;
/*
startup all of our server services
*/
-NTSTATUS server_service_startup(struct tevent_context *event_ctx,
+NTSTATUS server_service_startup(struct tevent_context *event_ctx,
struct loadparm_context *lp_ctx,
- const char *model, const char **server_services)
+ const char *model, const char **server_services,
+ int from_parent_fd)
{
int i;
const struct model_ops *model_ops;
for (i=0;server_services[i];i++) {
NTSTATUS status;
- status = server_service_init(server_services[i], event_ctx, lp_ctx, model_ops);
+ status = server_service_init(server_services[i], event_ctx,
+ lp_ctx, model_ops, from_parent_fd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to start service '%s' - %s\n",
server_services[i], nt_errstr(status)));
struct loadparm_context *lp_ctx,
const char *service_name,
const struct model_ops *model_ops,
- void (*task_init)(struct task_server *))
+ void (*task_init)(struct task_server *),
+ int from_parent_fd)
{
struct task_state *state;
state->task_init = task_init;
state->model_ops = model_ops;
-
- model_ops->new_task(event_ctx, lp_ctx, service_name, task_server_callback, state);
+
+ state->model_ops->new_task(event_ctx, lp_ctx, service_name,
+ task_server_callback, state,
+ from_parent_fd);
return NT_STATUS_OK;
}