summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2018-09-04 12:12:49 +1200
committerAndrew Bartlett <abartlet@samba.org>2018-11-23 08:25:19 +0100
commit6c850b77c4ae6c4aa6d914f7ccedc2bcce939217 (patch)
tree70d8da9dc6b4e25e0c8a02213e81df615152e1df /source4
parent3315a28ea92438eca499fb87b863cbd2db50a6a6 (diff)
downloadsamba-6c850b77c4ae6c4aa6d914f7ccedc2bcce939217.tar.gz
source4 smbd prefork: restart on non zero exit code
Restart any pre-fork master or worker process that exits with a non zero exit code. Signed-off-by: Gary Lockyer <gary@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4')
-rw-r--r--source4/kdc/kdc-heimdal.c3
-rw-r--r--source4/smbd/process_model.h17
-rw-r--r--source4/smbd/process_prefork.c99
-rw-r--r--source4/smbd/process_single.c30
-rw-r--r--source4/smbd/process_standard.c32
-rw-r--r--source4/smbd/service_stream.c4
-rw-r--r--source4/smbd/service_task.c2
7 files changed, 119 insertions, 68 deletions
diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index 67c07c3d81a..b5de5a790d4 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -276,7 +276,8 @@ static NTSTATUS kdc_task_init(struct task_server *task)
return NT_STATUS_INVALID_DOMAIN_ROLE;
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
- task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true);
+ task_server_terminate(
+ task, "Cannot start KDC as a 'classic Samba' DC", false);
return NT_STATUS_INVALID_DOMAIN_ROLE;
case ROLE_ACTIVE_DIRECTORY_DC:
/* Yes, we want a KDC */
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 2a226cef8cb..2892dd43c04 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -65,12 +65,17 @@ struct model_ops {
const struct service_details*,
const int);
- /* function to terminate a connection or task */
- void (*terminate)(struct tevent_context *,
- struct loadparm_context *lp_ctx,
- const char *reason,
- bool fatal,
- void *process_context);
+ /* function to terminate a task */
+ void (*terminate_task)(struct tevent_context *,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ bool fatal,
+ void *process_context);
+ /* function to terminate a connection */
+ void (*terminate_connection)(struct tevent_context *,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void *process_context);
/* function to set a title for the connection or task */
void (*set_title)(struct tevent_context *, const char *title);
diff --git a/source4/smbd/process_prefork.c b/source4/smbd/process_prefork.c
index c470820efb8..d2627937b44 100644
--- a/source4/smbd/process_prefork.c
+++ b/source4/smbd/process_prefork.c
@@ -147,6 +147,33 @@ static void prefork_pipe_handler(struct tevent_context *event_ctx,
exit(0);
}
+static void prefork_restart(struct tevent_context *ev,
+ struct restart_context *rc)
+{
+ if (rc->master != NULL) {
+ DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
+ prefork_new_task(ev,
+ rc->master->lp_ctx,
+ rc->service_name,
+ rc->master->new_task_fn,
+ rc->master->private_data,
+ rc->service_details,
+ rc->from_parent_fd);
+ } else if (rc->worker != NULL) {
+ struct process_details pd = initial_process_details;
+ DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
+ rc->service_name,
+ rc->worker->instance);
+ pd.instances = rc->worker->instance;
+ prefork_fork_worker(rc->worker->task,
+ ev,
+ rc->worker->ev2,
+ rc->service_details,
+ rc->service_name,
+ rc->worker->control_pipe,
+ &pd);
+ }
+}
/*
handle EOF on the child pipe in the parent, so we know when a
process terminates without using SIGCHLD or waiting on all possible pids.
@@ -176,49 +203,26 @@ static void prefork_child_pipe_handler(struct tevent_context *ev,
DBG_ERR("Parent %d, Child %d terminated, "
"unable to get status code from tfork\n",
getpid(), pid);
+ prefork_restart(ev, rc);
} else if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
DBG_ERR("Parent %d, Child %d exited with status %d\n",
getpid(), pid, status);
+ if (status != 0) {
+ prefork_restart(ev, rc);
+ }
} else if (WIFSIGNALED(status)) {
status = WTERMSIG(status);
DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
getpid(), pid, status);
if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
- status == SIGILL || status == SIGSYS) {
- /*
- * Lets restart the process.
- *
- */
- tfork_destroy(&rc->t);
- if (rc->master != NULL) {
- DBG_ERR("Restarting [%s] pre-fork master\n",
- rc->service_name);
- prefork_new_task(ev,
- rc->master->lp_ctx,
- rc->service_name,
- rc->master->new_task_fn,
- rc->master->private_data,
- rc->service_details,
- rc->from_parent_fd);
- } else if (rc->worker != NULL) {
- struct process_details pd =
- initial_process_details;
- DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
- rc->service_name,
- rc->worker->instance);
- pd.instances = rc->worker->instance;
- prefork_fork_worker(rc->worker->task,
- ev,
- rc->worker->ev2,
- rc->service_details,
- rc->service_name,
- rc->worker->control_pipe,
- &pd);
- }
+ status == SIGILL || status == SIGSYS || status == SIGSEGV) {
+
+ prefork_restart(ev, rc);
}
}
/* tfork allocates tfork structures with malloc */
+ tfork_destroy(&rc->t);
free(rc->t);
TALLOC_FREE(rc);
return;
@@ -529,15 +533,31 @@ static void prefork_new_task(
}
-
-/* called when a task goes down */
-static void prefork_terminate(struct tevent_context *ev,
- struct loadparm_context *lp_ctx,
- const char *reason,
- bool fatal,
- void *process_context)
+/*
+ * called when a task terminates
+ */
+static void prefork_terminate_task(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ bool fatal,
+ void *process_context)
{
DBG_DEBUG("called with reason[%s]\n", reason);
+ if (fatal == true) {
+ exit(127);
+ } else {
+ exit(0);
+ }
+}
+
+/*
+ * called when a connection completes
+ */
+static void prefork_terminate_connection(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void *process_context)
+{
}
/* called to set a title of a task or connection */
@@ -550,7 +570,8 @@ static const struct model_ops prefork_ops = {
.model_init = prefork_model_init,
.accept_connection = prefork_accept_connection,
.new_task = prefork_new_task,
- .terminate = prefork_terminate,
+ .terminate_task = prefork_terminate_task,
+ .terminate_connection = prefork_terminate_connection,
.set_title = prefork_set_title,
};
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index 061f09673dd..12ed2e30a74 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -119,17 +119,28 @@ static void single_new_task(struct tevent_context *ev,
}
}
-
-/* called when a task goes down */
-static void single_terminate(struct tevent_context *ev,
- struct loadparm_context *lp_ctx,
- const char *reason,
- bool fatal,
- void *process_context)
+/*
+ * Called when a task goes down
+ */
+static void single_terminate_task(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ bool fatal,
+ void *process_context)
{
DBG_NOTICE("single_terminate: reason[%s]\n",reason);
}
+/*
+ * Called when a connection has ended
+ */
+static void single_terminate_connection(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void *process_context)
+{
+}
+
/* called to set a title of a task or connection */
static void single_set_title(struct tevent_context *ev, const char *title)
{
@@ -138,9 +149,10 @@ static void single_set_title(struct tevent_context *ev, const char *title)
const struct model_ops single_ops = {
.name = "single",
.model_init = single_model_init,
- .new_task = single_new_task,
+ .new_task = single_new_task,
.accept_connection = single_accept_connection,
- .terminate = single_terminate,
+ .terminate_task = single_terminate_task,
+ .terminate_connection = single_terminate_connection,
.set_title = single_set_title,
};
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 536a6be3007..d25538716ba 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -510,15 +510,27 @@ static void standard_new_task(struct tevent_context *ev,
/* called when a task goes down */
-static void standard_terminate(struct tevent_context *ev,
- struct loadparm_context *lp_ctx,
- const char *reason,
- bool fatal,
- void *process_context)
+static void standard_terminate_task(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ bool fatal,
+ void *process_context)
+{
+ if (fatal == true) {
+ exit(127);
+ }
+ exit(0);
+}
+
+/* called when a connection terminates*/
+static void standard_terminate_connection(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void *process_context)
{
struct process_context *proc_ctx = NULL;
- DBG_DEBUG("process terminating reason[%s]\n", reason);
+ DBG_DEBUG("connection terminating reason[%s]\n", reason);
if (process_context == NULL) {
smb_panic("Panicking process_context is NULL");
}
@@ -547,7 +559,6 @@ static void standard_terminate(struct tevent_context *ev,
/* terminate this process */
exit(0);
}
-
/* called to set a title of a task or connection */
static void standard_set_title(struct tevent_context *ev, const char *title)
{
@@ -562,9 +573,10 @@ static const struct model_ops standard_ops = {
.name = "standard",
.model_init = standard_model_init,
.accept_connection = standard_accept_connection,
- .new_task = standard_new_task,
- .terminate = standard_terminate,
- .set_title = standard_set_title,
+ .new_task = standard_new_task,
+ .terminate_task = standard_terminate_task,
+ .terminate_connection = standard_terminate_connection,
+ .set_title = standard_set_title,
};
/*
diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c
index 336a0cb32aa..d0ad45aca3a 100644
--- a/source4/smbd/service_stream.c
+++ b/source4/smbd/service_stream.c
@@ -57,7 +57,6 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
const struct model_ops *model_ops = srv_conn->model_ops;
struct loadparm_context *lp_ctx = srv_conn->lp_ctx;
void *process_context = srv_conn->process_context;
- bool fatal = true;
TALLOC_CTX *frame = NULL;
if (!reason) reason = "unknown reason";
@@ -92,7 +91,8 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
srv_conn->event.fde = NULL;
imessaging_cleanup(srv_conn->msg_ctx);
TALLOC_FREE(srv_conn);
- model_ops->terminate(event_ctx, lp_ctx, reason, fatal, process_context);
+ model_ops->terminate_connection(
+ event_ctx, lp_ctx, reason, process_context);
TALLOC_FREE(frame);
}
diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c
index cb1f4d5ad1f..d911027db0a 100644
--- a/source4/smbd/service_task.c
+++ b/source4/smbd/service_task.c
@@ -54,7 +54,7 @@ void task_server_terminate(struct task_server *task, const char *reason, bool fa
imessaging_cleanup(task->msg_ctx);
- model_ops->terminate(
+ model_ops->terminate_task(
event_ctx, task->lp_ctx, reason, fatal, task->process_context);
/* don't free this above, it might contain the 'reason' being printed */
talloc_free(task);