mirror of
https://github.com/samba-team/samba.git
synced 2025-03-09 08:58:35 +03:00
eventscript: fork() a child for each script.
We rename child_run_scripts() to child_run_script(), because it now runs a single script rather than walking the list. When it's finished, we fork the next child from the ctdb_event_script_handler() callback. ctdb_control_event_script_init() and ctdb_control_event_script_finished() are now called directly by the parent process; the child still calls ctdb_ctrl_event_script_start() and ctdb_ctrl_event_script_stop() before and after the script. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (This used to be ctdb commit 0fafdcb8d3532a05846abaa5805b2e2f3cee8f47)
This commit is contained in:
parent
640b22ff61
commit
dd53eee7a2
@ -445,10 +445,6 @@ static int child_setup(struct ctdb_context *ctdb,
|
||||
DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch eventscript child into client mode. shutting down.\n"));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (ctdb_ctrl_event_script_init(ctdb) != 0) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (setpgid(0,0) != 0) {
|
||||
@ -522,29 +518,24 @@ static int child_run_one(struct ctdb_context *ctdb,
|
||||
}
|
||||
|
||||
/*
|
||||
Actually run the event scripts
|
||||
Actually run one event script
|
||||
this function is called and run in the context of a forked child
|
||||
which allows it to do blocking calls such as system()
|
||||
*/
|
||||
static int child_run_scripts(struct ctdb_context *ctdb,
|
||||
static int child_run_script(struct ctdb_context *ctdb,
|
||||
bool from_user,
|
||||
enum ctdb_eventscript_call call,
|
||||
const char *options,
|
||||
struct ctdb_script_list *scripts)
|
||||
struct ctdb_script_list *current)
|
||||
{
|
||||
char *cmdstr;
|
||||
int ret;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
|
||||
struct ctdb_script_list *current;
|
||||
|
||||
ret = child_setup(ctdb, from_user, call);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
/* fetch the scripts from the tree one by one and execute
|
||||
them
|
||||
*/
|
||||
for (current=scripts; current; current=current->next) {
|
||||
cmdstr = child_command_string(ctdb, tmp_ctx, from_user,
|
||||
current->name, call, options);
|
||||
CTDB_NO_MEMORY(ctdb, cmdstr);
|
||||
@ -569,7 +560,8 @@ static int child_run_scripts(struct ctdb_context *ctdb,
|
||||
}
|
||||
|
||||
if (current->error) {
|
||||
continue;
|
||||
ret = -current->error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = child_run_one(ctdb, current->name, cmdstr);
|
||||
@ -581,27 +573,9 @@ static int child_run_scripts(struct ctdb_context *ctdb,
|
||||
}
|
||||
}
|
||||
|
||||
/* now we've reported the per-script error, don't exit the loop
|
||||
* just because it vanished or was disabled. */
|
||||
if (ret == -ENOENT || ret == -ENOEXEC) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* return an error if the script failed */
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
child_state.start = timeval_current();
|
||||
child_state.script_running = "finished";
|
||||
|
||||
if (!from_user && call == CTDB_EVENT_MONITOR) {
|
||||
if (ctdb_ctrl_event_script_finished(ctdb) != 0) {
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
@ -621,14 +595,75 @@ static void ctdb_event_script_handler(struct event_context *ev, struct fd_event
|
||||
state->cb_status = -errno;
|
||||
} else if (r != sizeof(state->cb_status)) {
|
||||
state->cb_status = -EIO;
|
||||
} else {
|
||||
/* don't stop just because it vanished or was disabled. */
|
||||
if (state->cb_status == -ENOENT || state->cb_status == -ENOEXEC) {
|
||||
state->cb_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
state->child = 0;
|
||||
state->script_list = state->script_list->next;
|
||||
|
||||
/* Aborted or finished all scripts? We're done. */
|
||||
if (state->cb_status != 0 || state->script_list == NULL) {
|
||||
DEBUG(DEBUG_INFO,(__location__ " Eventscript %s %s finished with state %d\n",
|
||||
call_names[state->call], state->options, state->cb_status));
|
||||
|
||||
state->child = 0;
|
||||
if (!state->from_user && state->call == CTDB_EVENT_MONITOR) {
|
||||
ctdb_control_event_script_finished(ctdb);
|
||||
}
|
||||
ctdb->event_script_timeouts = 0;
|
||||
talloc_free(state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Forget about that old fd. */
|
||||
talloc_free(fde);
|
||||
|
||||
/* Next script! */
|
||||
r = pipe(state->fd);
|
||||
if (r != 0) {
|
||||
state->cb_status = -errno;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
state->child = fork();
|
||||
|
||||
if (state->child == (pid_t)-1) {
|
||||
state->cb_status = -errno;
|
||||
close(state->fd[0]);
|
||||
close(state->fd[1]);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (state->child == 0) {
|
||||
int rt;
|
||||
|
||||
close(state->fd[0]);
|
||||
set_close_on_exec(state->fd[1]);
|
||||
|
||||
rt = child_run_script(ctdb, state->from_user, state->call, state->options, state->script_list);
|
||||
/* We must be able to write PIPEBUF bytes at least; if this
|
||||
somehow fails, the read above will be short. */
|
||||
write(state->fd[1], &rt, sizeof(rt));
|
||||
close(state->fd[1]);
|
||||
_exit(rt);
|
||||
}
|
||||
|
||||
close(state->fd[1]);
|
||||
set_close_on_exec(state->fd[0]);
|
||||
|
||||
DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child eventscript process\n", state->fd[0]));
|
||||
|
||||
/* Set ourselves up to be called when that's done. */
|
||||
event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
|
||||
ctdb_event_script_handler, state);
|
||||
return;
|
||||
|
||||
abort:
|
||||
/* This calls the callback. */
|
||||
talloc_free(state);
|
||||
}
|
||||
|
||||
/* called when child times out */
|
||||
@ -794,6 +829,10 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
|
||||
call_names[state->call], state->options));
|
||||
|
||||
state->script_list = ctdb_get_script_list(ctdb, state);
|
||||
if (state->script_list == NULL) {
|
||||
talloc_free(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = pipe(state->fd);
|
||||
if (ret != 0) {
|
||||
@ -801,9 +840,16 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!state->from_user && state->call == CTDB_EVENT_MONITOR) {
|
||||
ctdb_control_event_script_init(ctdb);
|
||||
}
|
||||
|
||||
state->child = fork();
|
||||
|
||||
if (state->child == (pid_t)-1) {
|
||||
if (!state->from_user && state->call == CTDB_EVENT_MONITOR) {
|
||||
ctdb_control_event_script_finished(ctdb);
|
||||
}
|
||||
close(state->fd[0]);
|
||||
close(state->fd[1]);
|
||||
talloc_free(state);
|
||||
@ -816,7 +862,7 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
|
||||
close(state->fd[0]);
|
||||
set_close_on_exec(state->fd[1]);
|
||||
|
||||
rt = child_run_scripts(ctdb, state->from_user, state->call, state->options, state->script_list);
|
||||
rt = child_run_script(ctdb, state->from_user, state->call, state->options, state->script_list);
|
||||
/* We must be able to write PIPEBUF bytes at least; if this
|
||||
somehow fails, the read above will be short. */
|
||||
write(state->fd[1], &rt, sizeof(rt));
|
||||
|
Loading…
x
Reference in New Issue
Block a user