Move ExternalCmd-functions to class methods
This commit is contained in:
@ -18,7 +18,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <maxbase/assert.h>
|
#include <maxbase/assert.h>
|
||||||
@ -29,11 +28,9 @@
|
|||||||
* Tokenize a string into arguments suitable for a `execvp` call
|
* Tokenize a string into arguments suitable for a `execvp` call
|
||||||
*
|
*
|
||||||
* @param args Argument string
|
* @param args Argument string
|
||||||
* @param argv Array of char pointers to be filled with tokenized arguments
|
|
||||||
*
|
|
||||||
* @return 0 on success, -1 on error
|
* @return 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
static int tokenize_arguments(const char* argstr, char** argv)
|
int ExternalCmd::tokenize_arguments(const char* argstr)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
bool quoted = false;
|
bool quoted = false;
|
||||||
@ -47,7 +44,7 @@ static int tokenize_arguments(const char* argstr, char** argv)
|
|||||||
start = args;
|
start = args;
|
||||||
ptr = start;
|
ptr = start;
|
||||||
|
|
||||||
while (*ptr != '\0' && i < MAXSCALE_EXTCMD_ARG_MAX)
|
while (*ptr != '\0' && i < MAX_ARGS)
|
||||||
{
|
{
|
||||||
if (escaped)
|
if (escaped)
|
||||||
{
|
{
|
||||||
@ -103,60 +100,51 @@ static int tokenize_arguments(const char* argstr, char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalCmd* ExternalCmd::externcmd_allocate(const char* argstr, uint32_t timeout)
|
ExternalCmd* ExternalCmd::create(const char* argstr, uint32_t timeout)
|
||||||
{
|
{
|
||||||
ExternalCmd* cmd = (ExternalCmd*) MXS_MALLOC(sizeof(ExternalCmd));
|
auto cmd = new ExternalCmd;
|
||||||
char** argv = (char**) MXS_MALLOC(sizeof(char*) * MAXSCALE_EXTCMD_ARG_MAX);
|
bool success = false;
|
||||||
|
if (argstr && cmd)
|
||||||
if (argstr && cmd && argv)
|
|
||||||
{
|
{
|
||||||
cmd->timeout = timeout;
|
cmd->timeout = timeout;
|
||||||
cmd->argv = argv;
|
if (cmd->tokenize_arguments(argstr) == 0)
|
||||||
if (tokenize_arguments(argstr, cmd->argv) == 0)
|
|
||||||
{
|
{
|
||||||
if (access(cmd->argv[0], X_OK) != 0)
|
auto cmdname = cmd->argv[0];
|
||||||
|
if (access(cmdname, X_OK) != 0)
|
||||||
{
|
{
|
||||||
if (access(cmd->argv[0], F_OK) != 0)
|
if (access(cmdname, F_OK) != 0)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Cannot find file: %s", cmd->argv[0]);
|
MXS_ERROR("Cannot find file: %s", cmdname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MXS_ERROR("Cannot execute file '%s'. Missing "
|
MXS_ERROR("Cannot execute file '%s'. Missing execution permissions.", cmdname);
|
||||||
"execution permissions.",
|
|
||||||
cmd->argv[0]);
|
|
||||||
}
|
}
|
||||||
externcmd_free(cmd);
|
}
|
||||||
cmd = NULL;
|
else
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MXS_ERROR("Failed to parse argument string for external command: %s",
|
MXS_ERROR("Failed to parse argument string for external command: %s", argstr);
|
||||||
argstr);
|
|
||||||
externcmd_free(cmd);
|
|
||||||
cmd = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!success)
|
||||||
{
|
{
|
||||||
MXS_FREE(cmd);
|
delete cmd;
|
||||||
MXS_FREE(argv);
|
cmd = nullptr;
|
||||||
cmd = NULL;
|
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExternalCmd::externcmd_free(ExternalCmd* cmd)
|
ExternalCmd::~ExternalCmd()
|
||||||
{
|
{
|
||||||
if (cmd)
|
for (int i = 0; argv[i]; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; cmd->argv[i]; i++)
|
MXS_FREE(argv[i]);
|
||||||
{
|
|
||||||
MXS_FREE(cmd->argv[i]);
|
|
||||||
}
|
|
||||||
MXS_FREE(cmd->argv);
|
|
||||||
MXS_FREE(cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +366,7 @@ int ExternalCmd::externcmd_execute()
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool externcmd_substitute_arg(ExternalCmd* cmd, const char* match, const char* replace)
|
bool ExternalCmd::substitute_arg(const char* match, const char* replace)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
bool rval = true;
|
bool rval = true;
|
||||||
@ -386,15 +374,15 @@ bool externcmd_substitute_arg(ExternalCmd* cmd, const char* match, const char* r
|
|||||||
pcre2_code* re = pcre2_compile((PCRE2_SPTR) match, PCRE2_ZERO_TERMINATED, 0, &err, &errpos, NULL);
|
pcre2_code* re = pcre2_compile((PCRE2_SPTR) match, PCRE2_ZERO_TERMINATED, 0, &err, &errpos, NULL);
|
||||||
if (re)
|
if (re)
|
||||||
{
|
{
|
||||||
for (int i = 0; cmd->argv[i] && rval; i++)
|
for (int i = 0; argv[i] && rval; i++)
|
||||||
{
|
{
|
||||||
size_t size_orig = strlen(cmd->argv[i]);
|
size_t size_orig = strlen(argv[i]);
|
||||||
size_t size_replace = strlen(replace);
|
size_t size_replace = strlen(replace);
|
||||||
size_t size = MXS_MAX(size_orig, size_replace);
|
size_t size = MXS_MAX(size_orig, size_replace);
|
||||||
char* dest = (char*)MXS_MALLOC(size);
|
char* dest = (char*)MXS_MALLOC(size);
|
||||||
if (dest)
|
if (dest)
|
||||||
{
|
{
|
||||||
mxs_pcre2_result_t rc = mxs_pcre2_substitute(re, cmd->argv[i], replace, &dest, &size);
|
mxs_pcre2_result_t rc = mxs_pcre2_substitute(re, argv[i], replace, &dest, &size);
|
||||||
|
|
||||||
switch (rc)
|
switch (rc)
|
||||||
{
|
{
|
||||||
@ -404,8 +392,8 @@ bool externcmd_substitute_arg(ExternalCmd* cmd, const char* match, const char* r
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MXS_PCRE2_MATCH:
|
case MXS_PCRE2_MATCH:
|
||||||
MXS_FREE(cmd->argv[i]);
|
MXS_FREE(argv[i]);
|
||||||
cmd->argv[i] = dest;
|
argv[i] = dest;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MXS_PCRE2_NOMATCH:
|
case MXS_PCRE2_NOMATCH:
|
||||||
@ -487,11 +475,11 @@ bool externcmd_can_execute(const char* argstr)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool externcmd_matches(const ExternalCmd* cmd, const char* match)
|
bool ExternalCmd::externcmd_matches(const char* match)
|
||||||
{
|
{
|
||||||
for (int i = 0; cmd->argv[i]; i++)
|
for (int i = 0; argv[i]; i++)
|
||||||
{
|
{
|
||||||
if (strstr(cmd->argv[i], match))
|
if (strstr(argv[i], match))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,30 +15,20 @@
|
|||||||
#include <maxscale/ccdefs.hh>
|
#include <maxscale/ccdefs.hh>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define MAXSCALE_EXTCMD_ARG_MAX 256
|
|
||||||
|
|
||||||
class ExternalCmd
|
class ExternalCmd
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Allocate a new external command.
|
* Create a new external command. The name and parameters are copied so
|
||||||
*
|
* the original memory can be freed.
|
||||||
* The name and parameters are copied into the external command structure so
|
|
||||||
* the original memory can be freed if needed.
|
|
||||||
*
|
*
|
||||||
* @param command Command to execute with the parameters
|
* @param command Command to execute with the parameters
|
||||||
* @param timeout Command timeout in seconds
|
* @param timeout Command timeout in seconds
|
||||||
*
|
|
||||||
* @return Pointer to new external command struct or NULL if an error occurred
|
* @return Pointer to new external command struct or NULL if an error occurred
|
||||||
*/
|
*/
|
||||||
static ExternalCmd* externcmd_allocate(const char* argstr, uint32_t timeout);
|
static ExternalCmd* create(const char* argstr, uint32_t timeout);
|
||||||
|
|
||||||
/**
|
~ExternalCmd();
|
||||||
* Free a previously allocated external command
|
|
||||||
*
|
|
||||||
* @param cmd Command to free
|
|
||||||
*/
|
|
||||||
static void externcmd_free(ExternalCmd* cmd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a command
|
* Execute a command
|
||||||
@ -49,23 +39,36 @@ public:
|
|||||||
*/
|
*/
|
||||||
int externcmd_execute();
|
int externcmd_execute();
|
||||||
|
|
||||||
char** argv; /**< Argument vector for the command, first being the
|
/**
|
||||||
* actual command being executed */
|
* Substitute all occurrences of @c match with @c replace in the arguments.
|
||||||
|
*
|
||||||
|
* @param match Match string
|
||||||
|
* @param replace Replacement string
|
||||||
|
*
|
||||||
|
* @return True if replacement was successful, false on error
|
||||||
|
*/
|
||||||
|
bool substitute_arg(const char* match, const char* replace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple matching of string and command
|
||||||
|
*
|
||||||
|
* @param match String to search for
|
||||||
|
*
|
||||||
|
* @return True if the string matched
|
||||||
|
*/
|
||||||
|
bool externcmd_matches(const char* match);
|
||||||
|
|
||||||
|
static const int MAX_ARGS {256};
|
||||||
|
|
||||||
|
char* argv[MAX_ARGS + 1] {}; /**< Arguments. First element is the command. */
|
||||||
|
|
||||||
|
private:
|
||||||
int n_exec; /**< Number of times executed */
|
int n_exec; /**< Number of times executed */
|
||||||
pid_t child; /**< PID of the child process */
|
pid_t child; /**< PID of the child process */
|
||||||
uint32_t timeout; /**< Command timeout in seconds */
|
uint32_t timeout; /**< Command timeout in seconds */
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
int tokenize_arguments(const char* argstr);
|
||||||
* Substitute all occurrences of @c match with @c replace in the arguments for @c cmd
|
};
|
||||||
*
|
|
||||||
* @param cmd External command
|
|
||||||
* @param match Match string
|
|
||||||
* @param replace Replacement string
|
|
||||||
*
|
|
||||||
* @return True if replacement was successful, false on error
|
|
||||||
*/
|
|
||||||
bool externcmd_substitute_arg(ExternalCmd* cmd, const char* re, const char* replace);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a command can be executed
|
* Check if a command can be executed
|
||||||
@ -78,13 +81,3 @@ bool externcmd_substitute_arg(ExternalCmd* cmd, const char* re, const char* repl
|
|||||||
* @return True if the file was found and the use has execution permissions to it
|
* @return True if the file was found and the use has execution permissions to it
|
||||||
*/
|
*/
|
||||||
bool externcmd_can_execute(const char* argstr);
|
bool externcmd_can_execute(const char* argstr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple matching of string and command
|
|
||||||
*
|
|
||||||
* @param cmd Command where the match is searched from
|
|
||||||
* @param match String to search for
|
|
||||||
*
|
|
||||||
* @return True if the string matched
|
|
||||||
*/
|
|
||||||
bool externcmd_matches(const ExternalCmd* cmd, const char* match);
|
|
||||||
|
@ -1056,14 +1056,14 @@ std::string Monitor::child_nodes(MonitorServer* parent)
|
|||||||
|
|
||||||
int Monitor::launch_command(MonitorServer* ptr, ExternalCmd* cmd)
|
int Monitor::launch_command(MonitorServer* ptr, ExternalCmd* cmd)
|
||||||
{
|
{
|
||||||
if (externcmd_matches(cmd, "$INITIATOR"))
|
if (cmd->externcmd_matches("$INITIATOR"))
|
||||||
{
|
{
|
||||||
char initiator[strlen(ptr->server->address) + 24]; // Extra space for port
|
char initiator[strlen(ptr->server->address) + 24]; // Extra space for port
|
||||||
snprintf(initiator, sizeof(initiator), "[%s]:%d", ptr->server->address, ptr->server->port);
|
snprintf(initiator, sizeof(initiator), "[%s]:%d", ptr->server->address, ptr->server->port);
|
||||||
externcmd_substitute_arg(cmd, "[$]INITIATOR", initiator);
|
cmd->substitute_arg("[$]INITIATOR", initiator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$PARENT"))
|
if (cmd->externcmd_matches("$PARENT"))
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
MonitorServer* parent = find_parent_node(ptr);
|
MonitorServer* parent = find_parent_node(ptr);
|
||||||
@ -1072,56 +1072,56 @@ int Monitor::launch_command(MonitorServer* ptr, ExternalCmd* cmd)
|
|||||||
{
|
{
|
||||||
ss << "[" << parent->server->address << "]:" << parent->server->port;
|
ss << "[" << parent->server->address << "]:" << parent->server->port;
|
||||||
}
|
}
|
||||||
externcmd_substitute_arg(cmd, "[$]PARENT", ss.str().c_str());
|
cmd->substitute_arg("[$]PARENT", ss.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$CHILDREN"))
|
if (cmd->externcmd_matches("$CHILDREN"))
|
||||||
{
|
{
|
||||||
externcmd_substitute_arg(cmd, "[$]CHILDREN", child_nodes(ptr).c_str());
|
cmd->substitute_arg("[$]CHILDREN", child_nodes(ptr).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$EVENT"))
|
if (cmd->externcmd_matches("$EVENT"))
|
||||||
{
|
{
|
||||||
externcmd_substitute_arg(cmd, "[$]EVENT", ptr->get_event_name());
|
cmd->substitute_arg("[$]EVENT", ptr->get_event_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
char nodelist[PATH_MAX + MON_ARG_MAX + 1] = {'\0'};
|
char nodelist[PATH_MAX + MON_ARG_MAX + 1] = {'\0'};
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$CREDENTIALS"))
|
if (cmd->externcmd_matches("$CREDENTIALS"))
|
||||||
{
|
{
|
||||||
// We provide the credentials for _all_ servers.
|
// We provide the credentials for _all_ servers.
|
||||||
append_node_names(nodelist, sizeof(nodelist), 0, CredentialsApproach::INCLUDE);
|
append_node_names(nodelist, sizeof(nodelist), 0, CredentialsApproach::INCLUDE);
|
||||||
externcmd_substitute_arg(cmd, "[$]CREDENTIALS", nodelist);
|
cmd->substitute_arg("[$]CREDENTIALS", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$NODELIST"))
|
if (cmd->externcmd_matches("$NODELIST"))
|
||||||
{
|
{
|
||||||
append_node_names(nodelist, sizeof(nodelist), SERVER_RUNNING);
|
append_node_names(nodelist, sizeof(nodelist), SERVER_RUNNING);
|
||||||
externcmd_substitute_arg(cmd, "[$]NODELIST", nodelist);
|
cmd->substitute_arg("[$]NODELIST", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$LIST"))
|
if (cmd->externcmd_matches("$LIST"))
|
||||||
{
|
{
|
||||||
append_node_names(nodelist, sizeof(nodelist), 0);
|
append_node_names(nodelist, sizeof(nodelist), 0);
|
||||||
externcmd_substitute_arg(cmd, "[$]LIST", nodelist);
|
cmd->substitute_arg("[$]LIST", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$MASTERLIST"))
|
if (cmd->externcmd_matches("$MASTERLIST"))
|
||||||
{
|
{
|
||||||
append_node_names(nodelist, sizeof(nodelist), SERVER_MASTER);
|
append_node_names(nodelist, sizeof(nodelist), SERVER_MASTER);
|
||||||
externcmd_substitute_arg(cmd, "[$]MASTERLIST", nodelist);
|
cmd->substitute_arg("[$]MASTERLIST", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$SLAVELIST"))
|
if (cmd->externcmd_matches("$SLAVELIST"))
|
||||||
{
|
{
|
||||||
append_node_names(nodelist, sizeof(nodelist), SERVER_SLAVE);
|
append_node_names(nodelist, sizeof(nodelist), SERVER_SLAVE);
|
||||||
externcmd_substitute_arg(cmd, "[$]SLAVELIST", nodelist);
|
cmd->substitute_arg("[$]SLAVELIST", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externcmd_matches(cmd, "$SYNCEDLIST"))
|
if (cmd->externcmd_matches("$SYNCEDLIST"))
|
||||||
{
|
{
|
||||||
append_node_names(nodelist, sizeof(nodelist), SERVER_JOINED);
|
append_node_names(nodelist, sizeof(nodelist), SERVER_JOINED);
|
||||||
externcmd_substitute_arg(cmd, "[$]SYNCEDLIST", nodelist);
|
cmd->substitute_arg("[$]SYNCEDLIST", nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rv = cmd->externcmd_execute();
|
int rv = cmd->externcmd_execute();
|
||||||
@ -1202,7 +1202,7 @@ int Monitor::launch_script(MonitorServer* ptr)
|
|||||||
char arg[strlen(script) + 1];
|
char arg[strlen(script) + 1];
|
||||||
strcpy(arg, script);
|
strcpy(arg, script);
|
||||||
|
|
||||||
ExternalCmd* cmd = ExternalCmd::externcmd_allocate(arg, m_settings.script_timeout);
|
ExternalCmd* cmd = ExternalCmd::create(arg, m_settings.script_timeout);
|
||||||
|
|
||||||
if (cmd == NULL)
|
if (cmd == NULL)
|
||||||
{
|
{
|
||||||
@ -1213,9 +1213,7 @@ int Monitor::launch_script(MonitorServer* ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rv = launch_command(ptr, cmd);
|
int rv = launch_command(ptr, cmd);
|
||||||
|
delete cmd;
|
||||||
ExternalCmd::externcmd_free(cmd);
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user