Improved debug CLI command interpreter to allow for commands with arguments
This commit is contained in:
21
core/dcb.c
21
core/dcb.c
@ -435,6 +435,27 @@ DCB *dcb;
|
|||||||
spinlock_release(dcbspin);
|
spinlock_release(dcbspin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnostic to print a DCB
|
||||||
|
*
|
||||||
|
* @param dcb The DCB to print
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dprintDCB(DCB *pdcb, DCB *dcb)
|
||||||
|
{
|
||||||
|
dcb_printf(pdcb, "DCB: %p\n", (void *)dcb);
|
||||||
|
dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state));
|
||||||
|
if (dcb->remote)
|
||||||
|
dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote);
|
||||||
|
dcb_printf(pdcb, "\tQueued write data: %d\n", gwbuf_length(dcb->writeq));
|
||||||
|
dcb_printf(pdcb, "\tStatistics:\n");
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Reads: %d\n", dcb->stats.n_reads);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Buffered Writes: %d\n", dcb->stats.n_buffered);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string representation of a DCB state.
|
* Return a string representation of a DCB state.
|
||||||
*
|
*
|
||||||
|
@ -136,6 +136,7 @@ extern void dcb_close(DCB *); /* Generic close functionality */
|
|||||||
extern void printAllDCBs(); /* Debug to print all DCB in the system */
|
extern void printAllDCBs(); /* Debug to print all DCB in the system */
|
||||||
extern void printDCB(DCB *); /* Debug print routine */
|
extern void printDCB(DCB *); /* Debug print routine */
|
||||||
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
|
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
|
||||||
|
extern void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */
|
||||||
extern const char *gw_dcb_state2string(int); /* DCB state to string */
|
extern const char *gw_dcb_state2string(int); /* DCB state to string */
|
||||||
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ TESTSRCS=testroute.c
|
|||||||
TESTOBJ=$(TESTSRCS:.c=.o)
|
TESTOBJ=$(TESTSRCS:.c=.o)
|
||||||
READCONSRCS=readconnroute.c
|
READCONSRCS=readconnroute.c
|
||||||
READCONOBJ=$(READCONSRCS:.c=.o)
|
READCONOBJ=$(READCONSRCS:.c=.o)
|
||||||
DEBUGCLISRCS=debugcli.c
|
DEBUGCLISRCS=debugcli.c debugcmd.c
|
||||||
DEBUGCLIOBJ=$(DEBUGCLISRCS:.c=.o)
|
DEBUGCLIOBJ=$(DEBUGCLISRCS:.c=.o)
|
||||||
SRCS=$(TESTSRCS) $(READCONSRCS) $(DEBUGCLISRCS)
|
SRCS=$(TESTSRCS) $(READCONSRCS) $(DEBUGCLISRCS)
|
||||||
OBJ=$(SRCS:.c=.o)
|
OBJ=$(SRCS:.c=.o)
|
||||||
|
@ -52,7 +52,7 @@ static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
|||||||
/** The module object definition */
|
/** The module object definition */
|
||||||
static ROUTER_OBJECT MyObject = { createInstance, newSession, closeSession, execute };
|
static ROUTER_OBJECT MyObject = { createInstance, newSession, closeSession, execute };
|
||||||
|
|
||||||
static int execute_cmd(CLI_SESSION *cli);
|
extern int execute_cmd(CLI_SESSION *cli);
|
||||||
|
|
||||||
static SPINLOCK instlock;
|
static SPINLOCK instlock;
|
||||||
static CLI_INSTANCE *instances;
|
static CLI_INSTANCE *instances;
|
||||||
@ -227,58 +227,3 @@ CLI_SESSION *session = (CLI_SESSION *)router_session;
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
|
||||||
char *cmd;
|
|
||||||
void (*fn)(DCB *);
|
|
||||||
} cmds[] = {
|
|
||||||
{ "show sessions", dprintAllSessions },
|
|
||||||
{ "show services", dprintAllServices },
|
|
||||||
{ "show servers", dprintAllServers },
|
|
||||||
{ "show modules", dprintAllModules },
|
|
||||||
{ "show dcbs", dprintAllDCBs },
|
|
||||||
{ "show epoll", dprintPollStats },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We have a complete line from the user, lookup the commands and execute them
|
|
||||||
*
|
|
||||||
* @param cli The CLI_SESSION
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
execute_cmd(CLI_SESSION *cli)
|
|
||||||
{
|
|
||||||
int i, found = 0;
|
|
||||||
|
|
||||||
if (!strncmp(cli->cmdbuf, "help", 4))
|
|
||||||
{
|
|
||||||
dcb_printf(cli->session->client, "Available commands:\n");
|
|
||||||
for (i = 0; cmds[i].cmd; i++)
|
|
||||||
{
|
|
||||||
dcb_printf(cli->session->client, " %s\n", cmds[i].cmd);
|
|
||||||
}
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
else if (!strncmp(cli->cmdbuf, "quit", 4))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; cmds[i].cmd; i++)
|
|
||||||
{
|
|
||||||
if (strncmp(cli->cmdbuf, cmds[i].cmd, strlen(cmds[i].cmd)) == 0)
|
|
||||||
{
|
|
||||||
cmds[i].fn(cli->session->client);
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
dcb_printf(cli->session->client,
|
|
||||||
"Command not known, type help for a list of available commands\n");
|
|
||||||
memset(cli->cmdbuf, 0, 80);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
202
modules/routing/debugcmd.c
Normal file
202
modules/routing/debugcmd.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* This file is distributed as part of the SkySQL Gateway. It is free
|
||||||
|
* software: you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation,
|
||||||
|
* version 2.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||||
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Copyright SkySQL Ab 2013
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file debugcmd.c - The debug CLI command line interpreter
|
||||||
|
*
|
||||||
|
* @verbatim
|
||||||
|
* Revision History
|
||||||
|
*
|
||||||
|
* Date Who Description
|
||||||
|
* 20/06/13 Mark Riddoch Initial implementation
|
||||||
|
*
|
||||||
|
* @endverbatim
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <service.h>
|
||||||
|
#include <session.h>
|
||||||
|
#include <router.h>
|
||||||
|
#include <modules.h>
|
||||||
|
#include <atomic.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
#include <dcb.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <debugcli.h>
|
||||||
|
|
||||||
|
#define MAXARGS 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subcommand structure
|
||||||
|
*
|
||||||
|
* These are the options that may be passed to a command
|
||||||
|
*/
|
||||||
|
struct subcommand {
|
||||||
|
char *arg1;
|
||||||
|
int n_args;
|
||||||
|
void (*fn)();
|
||||||
|
char *help;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct subcommand showoptions[] = {
|
||||||
|
{ "sessions", 0, dprintAllSessions, "Show all active sessions in the gateway" },
|
||||||
|
{ "services", 0, dprintAllServices, "Show all configured services in the gateway" },
|
||||||
|
{ "servers", 0, dprintAllServers, "Show all configured servers" },
|
||||||
|
{ "modules", 0, dprintAllModules, "Show all currently loaded modules" },
|
||||||
|
{ "dcbs", 0, dprintAllDCBs, "Show all descriptor control blocks (network connections)" },
|
||||||
|
{ "dcb", 1, dprintDCB, "Show a single descriptor control block e.g. show dcb 0x493340" },
|
||||||
|
{ "epoll", 0, dprintPollStats, "Show the poll statistics" },
|
||||||
|
{ NULL, 0, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The debug command table
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
char *cmd;
|
||||||
|
struct subcommand *options;
|
||||||
|
} cmds[] = {
|
||||||
|
{ "show", showoptions },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static long
|
||||||
|
convert_arg(char *arg)
|
||||||
|
{
|
||||||
|
return strtol(arg, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have a complete line from the user, lookup the commands and execute them
|
||||||
|
*
|
||||||
|
* @param cli The CLI_SESSION
|
||||||
|
* @return Returns 0 if the interpreter should exit
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
execute_cmd(CLI_SESSION *cli)
|
||||||
|
{
|
||||||
|
DCB *dcb = cli->session->client;
|
||||||
|
int argc, i, j, found = 0;
|
||||||
|
char *args[MAXARGS];
|
||||||
|
char *saveptr, *delim = " \t\r\n";
|
||||||
|
|
||||||
|
/* Tokenize the input string */
|
||||||
|
args[0] = strtok_r(cli->cmdbuf, delim, &saveptr);
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
args[i] = strtok_r(NULL, delim, &saveptr);
|
||||||
|
} while (args[i] != NULL && i < MAXARGS);
|
||||||
|
|
||||||
|
if (args[0] == NULL)
|
||||||
|
return 1;
|
||||||
|
argc = i - 2; /* The number of extra arguments to commands */
|
||||||
|
|
||||||
|
|
||||||
|
if (!strcasecmp(args[0], "help"))
|
||||||
|
{
|
||||||
|
if (args[1] == NULL)
|
||||||
|
{
|
||||||
|
found = 1;
|
||||||
|
dcb_printf(dcb, "Available commands:\n");
|
||||||
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[j].arg1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(args[1], cmds[i].cmd))
|
||||||
|
{
|
||||||
|
found = 1;
|
||||||
|
dcb_printf(dcb, "Available options to the %s command:\n", args[1]);
|
||||||
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, " %-10s %s\n", cmds[i].options[j].arg1,
|
||||||
|
cmds[i].options[j].help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found == 0)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "No command %s to offer help with\n", args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
else if (!strcasecmp(args[0], "quit"))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(args[0], cmds[i].cmd) == 0)
|
||||||
|
{
|
||||||
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(args[1], cmds[i].options[j].arg1) == 0)
|
||||||
|
{
|
||||||
|
if (argc != cmds[i].options[j].n_args)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Incorrect number of arguments: %s %s expects %d arguments\n",
|
||||||
|
cmds[i].cmd, cmds[i].options[j].arg1,
|
||||||
|
cmds[i].options[j].n_args);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (cmds[i].options[j].n_args)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cmds[i].options[j].fn(dcb);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cmds[i].options[j].fn(dcb, convert_arg(args[2]));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cmds[i].options[j].fn(dcb, convert_arg(args[2]),
|
||||||
|
convert_arg(args[3]));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cmds[i].options[j].fn(dcb, convert_arg(args[2]),
|
||||||
|
convert_arg(args[3]),
|
||||||
|
convert_arg(args[4]));
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
dcb_printf(dcb,
|
||||||
|
"Command not known, type help for a list of available commands\n");
|
||||||
|
memset(cli->cmdbuf, 0, 80);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
@ -36,3 +36,47 @@ readconnroute.o: readconnroute.c /usr/include/stdio.h \
|
|||||||
/usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \
|
/usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \
|
||||||
../../include/server.h ../../include/router.h ../../include/session.h \
|
../../include/server.h ../../include/router.h ../../include/session.h \
|
||||||
../../include/atomic.h ../include/readconnection.h
|
../../include/atomic.h ../include/readconnection.h
|
||||||
|
debugcli.o: debugcli.c /usr/include/stdio.h /usr/include/features.h \
|
||||||
|
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
|
||||||
|
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
|
||||||
|
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
|
||||||
|
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
|
||||||
|
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
|
||||||
|
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
|
||||||
|
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
|
||||||
|
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
|
||||||
|
/usr/include/bits/waitstatus.h /usr/include/endian.h \
|
||||||
|
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
|
||||||
|
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
|
||||||
|
/usr/include/bits/select.h /usr/include/bits/sigset.h \
|
||||||
|
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
|
||||||
|
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||||
|
/usr/include/string.h /usr/include/xlocale.h ../../include/service.h \
|
||||||
|
../../include/spinlock.h ../../include/thread.h /usr/include/pthread.h \
|
||||||
|
/usr/include/sched.h /usr/include/bits/sched.h \
|
||||||
|
/usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \
|
||||||
|
../../include/server.h ../../include/session.h ../../include/router.h \
|
||||||
|
../../include/modules.h ../../include/atomic.h ../../include/poll.h \
|
||||||
|
../include/debugcli.h
|
||||||
|
debugcmd.o: debugcmd.c /usr/include/stdio.h /usr/include/features.h \
|
||||||
|
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
|
||||||
|
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
|
||||||
|
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
|
||||||
|
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
|
||||||
|
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
|
||||||
|
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
|
||||||
|
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
|
||||||
|
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
|
||||||
|
/usr/include/bits/waitstatus.h /usr/include/endian.h \
|
||||||
|
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
|
||||||
|
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
|
||||||
|
/usr/include/bits/select.h /usr/include/bits/sigset.h \
|
||||||
|
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
|
||||||
|
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||||
|
/usr/include/string.h /usr/include/xlocale.h ../../include/service.h \
|
||||||
|
../../include/spinlock.h ../../include/thread.h /usr/include/pthread.h \
|
||||||
|
/usr/include/sched.h /usr/include/bits/sched.h \
|
||||||
|
/usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \
|
||||||
|
../../include/server.h ../../include/session.h ../../include/router.h \
|
||||||
|
../../include/modules.h ../../include/atomic.h ../../include/poll.h \
|
||||||
|
../include/debugcli.h
|
||||||
|
Reference in New Issue
Block a user