MXS-1405: Execute EXTERNCMD synchronously
The execution of external commands in MaxScale by monitors needs to be synchronous in order to prevent the unintended detection of state changes.
This commit is contained in:
parent
efb1e541e2
commit
4f7606ebc0
@ -16,10 +16,12 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include <maxscale/pcre2.h>
|
||||
#include <maxscale/thread.h>
|
||||
|
||||
|
||||
|
||||
@ -175,6 +177,7 @@ int externcmd_execute(EXTERNCMD* cmd)
|
||||
int rval = 0;
|
||||
pid_t pid;
|
||||
|
||||
// The SIGCHLD handler must be disabled before child process is forked
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
@ -191,9 +194,71 @@ int externcmd_execute(EXTERNCMD* cmd)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_INFO("Executing command '%s' in process %d", cmd->argv[0], pid);
|
||||
cmd->child = pid;
|
||||
cmd->n_exec++;
|
||||
MXS_DEBUG("[monitor_exec_cmd] Forked child process %d : %s.", pid, cmd->argv[0]);
|
||||
|
||||
bool first_warning = true;
|
||||
bool again = true;
|
||||
uint64_t t = 0;
|
||||
uint64_t t_max = cmd->timeout * 1000;
|
||||
|
||||
while (again)
|
||||
{
|
||||
int exit_status;
|
||||
|
||||
switch (waitpid(pid, &exit_status, WNOHANG))
|
||||
{
|
||||
case -1:
|
||||
MXS_ERROR("Failed to wait for child process: %d, %s", errno, mxs_strerror(errno));
|
||||
again = false;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (t++ > t_max)
|
||||
{
|
||||
// Command timed out
|
||||
t = 0;
|
||||
if (first_warning)
|
||||
{
|
||||
MXS_WARNING("Soft timeout for command '%s', sending SIGTERM", cmd->argv[0]);
|
||||
kill(pid, SIGTERM);
|
||||
first_warning = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Hard timeout for command '%s', sending SIGKILL", cmd->argv[0]);
|
||||
kill(pid, SIGKILL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sleep and try again
|
||||
thread_millisleep(1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
again = false;
|
||||
|
||||
if (WIFEXITED(exit_status))
|
||||
{
|
||||
rval = WEXITSTATUS(exit_status);
|
||||
}
|
||||
else if (WIFSIGNALED(exit_status))
|
||||
{
|
||||
rval = WTERMSIG(exit_status);
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = exit_status;
|
||||
MXS_ERROR("Command '%s' did not exit normally. Exit status: %d",
|
||||
cmd->argv[0], exit_status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rval;
|
||||
|
@ -369,45 +369,6 @@ sigint_handler(int i)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sigchld_handler (int i)
|
||||
{
|
||||
int exit_status = 0;
|
||||
pid_t child = -1;
|
||||
|
||||
if ((child = wait(&exit_status)) == -1)
|
||||
{
|
||||
MXS_ERROR("Failed to wait child process: %d %s",
|
||||
errno, mxs_strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WIFEXITED(exit_status))
|
||||
{
|
||||
if (WEXITSTATUS(exit_status) != 0)
|
||||
{
|
||||
MXS_ERROR("Child process %d exited with status %d",
|
||||
child, WEXITSTATUS(exit_status));
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_INFO("Child process %d exited with status %d",
|
||||
child, WEXITSTATUS(exit_status));
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(exit_status))
|
||||
{
|
||||
MXS_ERROR("Child process %d was stopped by signal %d.",
|
||||
child, WTERMSIG(exit_status));
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Child process %d did not exit normally. Exit status: %d",
|
||||
child, exit_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile sig_atomic_t fatal_handling = 0;
|
||||
|
||||
static int signal_set(int sig, void (*handler)(int));
|
||||
@ -1178,11 +1139,6 @@ bool configure_signals(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configure_signal(SIGCHLD, "SIGCHLD", sigchld_handler))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SIGBUS
|
||||
if (!configure_signal(SIGBUS, "SIGBUS", sigfatal_handler))
|
||||
{
|
||||
|
@ -22,10 +22,11 @@ MXS_BEGIN_DECLS
|
||||
|
||||
typedef struct extern_cmd_t
|
||||
{
|
||||
char** argv; /*< Argument vector for the command, first being the actual command
|
||||
* being executed. */
|
||||
int n_exec; /*< Number of times executed */
|
||||
pid_t child; /*< PID of the child process */
|
||||
char** argv; /**< Argument vector for the command, first being the
|
||||
* actual command being executed */
|
||||
int n_exec; /**< Number of times executed */
|
||||
pid_t child; /**< PID of the child process */
|
||||
uint32_t timeout; /**< Command timeout in seconds */
|
||||
} EXTERNCMD;
|
||||
|
||||
char* externcmd_extract_command(const char* argstr);
|
||||
|
Loading…
x
Reference in New Issue
Block a user