diff options
author | Gary Lockyer <gary@catalyst.net.nz> | 2018-09-04 12:12:49 +1200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2018-11-23 08:25:19 +0100 |
commit | 6c850b77c4ae6c4aa6d914f7ccedc2bcce939217 (patch) | |
tree | 70d8da9dc6b4e25e0c8a02213e81df615152e1df /source4 | |
parent | 3315a28ea92438eca499fb87b863cbd2db50a6a6 (diff) | |
download | samba-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.c | 3 | ||||
-rw-r--r-- | source4/smbd/process_model.h | 17 | ||||
-rw-r--r-- | source4/smbd/process_prefork.c | 99 | ||||
-rw-r--r-- | source4/smbd/process_single.c | 30 | ||||
-rw-r--r-- | source4/smbd/process_standard.c | 32 | ||||
-rw-r--r-- | source4/smbd/service_stream.c | 4 | ||||
-rw-r--r-- | source4/smbd/service_task.c | 2 |
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); |