Add support for #!../maxadmin scripts

Add the --help option

Add quoting for executing command with arguments that contain whitespace
This commit is contained in:
Mark Riddoch
2014-06-25 10:00:59 +01:00
parent e0596b7d72
commit 792ae454f4
4 changed files with 119 additions and 31 deletions

View File

@ -55,6 +55,7 @@ static int setipaddress(struct in_addr *a, char *p);
static int authMaxScale(int so, char *user, char *password); static int authMaxScale(int so, char *user, char *password);
static int sendCommand(int so, char *cmd); static int sendCommand(int so, char *cmd);
static void DoSource(int so, char *cmd); static void DoSource(int so, char *cmd);
static void DoUsage();
#ifdef HISTORY #ifdef HISTORY
static char * static char *
@ -66,6 +67,12 @@ prompt(EditLine *el __attribute__((__unused__)))
} }
#endif #endif
/**
* The main for the maxadmin client
*
* @param argc Number of arguments
* @param argv The command line arguments
*/
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -86,6 +93,7 @@ char *user = "admin";
char *passwd = NULL; char *passwd = NULL;
int so, cmdlen; int so, cmdlen;
char *cmd; char *cmd;
int argno = 0;
cmd = malloc(1); cmd = malloc(1);
*cmd = 0; *cmd = 0;
@ -145,14 +153,41 @@ char *cmd;
fatal = 1; fatal = 1;
} }
break; break;
case '-':
{
char *word;
word = &argv[i][2];
if (strcmp(word, "help") == 0)
{
DoUsage();
exit(0);
}
break;
}
} }
} }
else else
{ {
cmdlen += strlen(argv[i]) + 1; /* Arguments after the second argument are quoted
cmd = realloc(cmd, cmdlen); * to allow for quoted names on the command line
strcat(cmd, argv[i]); * to be passed on in quotes.
strcat(cmd, " "); */
if (argno++ > 1)
{
cmdlen += strlen(argv[i]) + 3;
cmd = realloc(cmd, cmdlen);
strcat(cmd, "\"");
strcat(cmd, argv[i]);
strcat(cmd, "\" ");
}
else
{
cmdlen += strlen(argv[i]) + 1;
cmd = realloc(cmd, cmdlen);
strcat(cmd, argv[i]);
strcat(cmd, " ");
}
} }
} }
@ -198,8 +233,11 @@ char *cmd;
if (cmdlen > 1) if (cmdlen > 1)
{ {
cmd[cmdlen - 2] = '\0'; cmd[cmdlen - 2] = '\0'; /* Remove trailing space */
sendCommand(so, cmd); if (access(cmd, R_OK) == 0)
DoSource(so, cmd);
else
sendCommand(so, cmd);
exit(0); exit(0);
} }
@ -266,7 +304,14 @@ char *cmd;
} }
else if (!strncasecmp(buf, "source", 6)) else if (!strncasecmp(buf, "source", 6))
{ {
DoSource(so, buf); char *ptr;
/* Find the filename */
ptr = &buf[strlen("source")];
while (*ptr && isspace(*ptr))
ptr++;
DoSource(so, ptr);
} }
else if (*buf) else if (*buf)
{ {
@ -283,6 +328,13 @@ char *cmd;
return 0; return 0;
} }
/**
* Connect to the MaxScale server
*
* @param hostname The hostname to connect to
* @param port The port to use for the connection
* @return The connected socket or -1 on error
*/
static int static int
connectMaxScale(char *hostname, char *port) connectMaxScale(char *hostname, char *port)
{ {
@ -310,7 +362,7 @@ int so;
} }
/* /**
* Set IP address in socket structure in_addr * Set IP address in socket structure in_addr
* *
* @param a Pointer to a struct in_addr into which the address is written * @param a Pointer to a struct in_addr into which the address is written
@ -364,6 +416,14 @@ setipaddress(struct in_addr *a, char *p)
return 0; return 0;
} }
/**
* Perform authentication using the maxscaled protocol conventions
*
* @param so The socket connected to MaxScale
* @param user The username to authenticate
* @param password The password to authenticate with
* @return Non-zero of succesful authentication
*/
static int static int
authMaxScale(int so, char *user, char *password) authMaxScale(int so, char *user, char *password)
{ {
@ -378,6 +438,14 @@ char buf[20];
return strncmp(buf, "FAILED", 6); return strncmp(buf, "FAILED", 6);
} }
/**
* Send a comamnd using the MaxScaled protocol, display the return data
* on standard output
*
* @param so The socket connect to MaxScale
* @param cmd The command to send
* @return 0 if the connection was closed
*/
static int static int
sendCommand(int so, char *cmd) sendCommand(int so, char *cmd)
{ {
@ -399,22 +467,23 @@ int i;
return 1; return 1;
} }
/**
* Read a file of commands and send them to MaxScale
*
* @param so The socket connected to MaxScale
* @param file The filename
*/
static void static void
DoSource(int so, char *buf) DoSource(int so, char *file)
{ {
char *ptr, *pe; char *ptr, *pe;
char line[132]; char line[132];
FILE *fp; FILE *fp;
/* Find the filename */ if ((fp = fopen(file, "r")) == NULL)
ptr = &buf[strlen("source")];
while (*ptr && isspace(*ptr))
ptr++;
if ((fp = fopen(ptr, "r")) == NULL)
{ {
fprintf(stderr, "Unable to open command file '%s'.\n", fprintf(stderr, "Unable to open command file '%s'.\n",
ptr); file);
return; return;
} }
@ -439,3 +508,24 @@ FILE *fp;
fclose(fp); fclose(fp);
return; return;
} }
/**
* Display the --help text.
*/
static void
DoUsage()
{
printf("maxadmin: The MaxScale administrative and monitor client.\n\n");
printf("Usage: maxadmin [-u user] [-p password] [-h hostname] [-P port] [<command file> | <command>]\n\n");
printf(" -u user The user name to use for the connection, default\n");
printf(" is admin.\n");
printf(" -p password The user password, if not given the password will\n");
printf(" be prompted for interactively\n");
printf(" -h hostname The maxscale host to connecto to. The default is\n");
printf(" localhost\n");
printf(" -P port The port to use for the connection, the default\n");
printf(" port is 6603.\n");
printf(" --help Print this help text.\n");
printf("Any remaining arguments are treated as MaxScale commands or a file\n");
printf("containing commands to execute.\n");
}

View File

@ -222,13 +222,13 @@ int i;
{ {
dcb_printf(dcb, "Filters\n"); dcb_printf(dcb, "Filters\n");
dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n");
dcb_printf(dcb, "%-18s | %-15s | Options\n", dcb_printf(dcb, "%-19s | %-15s | Options\n",
"Filter", "Module"); "Filter", "Module");
dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n");
} }
while (ptr) while (ptr)
{ {
dcb_printf(dcb, "%-18s | %-15s | ", dcb_printf(dcb, "%-19s | %-15s | ",
ptr->name, ptr->module); ptr->name, ptr->module);
for (i = 0; ptr->options && ptr->options[i]; i++) for (i = 0; ptr->options && ptr->options[i]; i++)
dcb_printf(dcb, "%s ", ptr->options[i]); dcb_printf(dcb, "%s ", ptr->options[i]);

View File

@ -87,8 +87,6 @@ static GWPROTOCOL MyObject = {
NULL /**< Session */ NULL /**< Session */
}; };
static void maxscaled_command(DCB *, unsigned char *cmd);
/** /**
* Implementation of the mandatory version entry point * Implementation of the mandatory version entry point
* *

View File

@ -83,17 +83,17 @@ static int telnetd_listen(DCB *dcb, char *config);
* The "module object" for the telnetd protocol module. * The "module object" for the telnetd protocol module.
*/ */
static GWPROTOCOL MyObject = { static GWPROTOCOL MyObject = {
telnetd_read_event, /**< Read - EPOLLIN handler */ telnetd_read_event, /**< Read - EPOLLIN handler */
telnetd_write, /**< Write - data from gateway */ telnetd_write, /**< Write - data from gateway */
telnetd_write_event, /**< WriteReady - EPOLLOUT handler */ telnetd_write_event, /**< WriteReady - EPOLLOUT handler */
telnetd_error, /**< Error - EPOLLERR handler */ telnetd_error, /**< Error - EPOLLERR handler */
telnetd_hangup, /**< HangUp - EPOLLHUP handler */ telnetd_hangup, /**< HangUp - EPOLLHUP handler */
telnetd_accept, /**< Accept */ telnetd_accept, /**< Accept */
NULL, /**< Connect */ NULL, /**< Connect */
telnetd_close, /**< Close */ telnetd_close, /**< Close */
telnetd_listen, /**< Create a listener */ telnetd_listen, /**< Create a listener */
NULL, /**< Authentication */ NULL, /**< Authentication */
NULL /**< Session */ NULL /**< Session */
}; };
static void telnetd_command(DCB *, unsigned char *cmd); static void telnetd_command(DCB *, unsigned char *cmd);