summaryrefslogtreecommitdiff
path: root/lib/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c358
1 files changed, 215 insertions, 143 deletions
diff --git a/lib/command.c b/lib/command.c
index a71cb5ddd2..72a2739895 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -182,6 +182,7 @@ print_version (const char *progname)
{
printf ("%s version %s\n", progname, QUAGGA_VERSION);
printf ("%s\n", QUAGGA_COPYRIGHT);
+ printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
}
@@ -506,6 +507,25 @@ format_parser_read_word(struct format_parser_state *state)
token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
token->type = TOKEN_TERMINAL;
+ if (strcmp (cmd, "A.B.C.D") == 0)
+ token->terminal = TERMINAL_IPV4;
+ else if (strcmp (cmd, "A.B.C.D/M") == 0)
+ token->terminal = TERMINAL_IPV4_PREFIX;
+ else if (strcmp (cmd, "X:X::X:X") == 0)
+ token->terminal = TERMINAL_IPV6;
+ else if (strcmp (cmd, "X:X::X:X/M") == 0)
+ token->terminal = TERMINAL_IPV6_PREFIX;
+ else if (cmd[0] == '[')
+ token->terminal = TERMINAL_OPTION;
+ else if (cmd[0] == '.')
+ token->terminal = TERMINAL_VARARG;
+ else if (cmd[0] == '<')
+ token->terminal = TERMINAL_RANGE;
+ else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
+ token->terminal = TERMINAL_VARIABLE;
+ else
+ token->terminal = TERMINAL_LITERAL;
+
token->cmd = cmd;
token->desc = format_parser_desc_str(state);
vector_set(state->curvect, token);
@@ -1172,59 +1192,61 @@ cmd_word_match(struct cmd_token *token,
if (!word)
return no_match;
- if (CMD_VARARG(str))
- {
- return vararg_match;
- }
- else if (CMD_RANGE(str))
- {
- if (cmd_range_match(str, word))
- return range_match;
- }
-#ifdef HAVE_IPV6
- else if (CMD_IPV6(str))
+ switch (token->terminal)
{
- match_type = cmd_ipv6_match(word);
- if ((filter == FILTER_RELAXED && match_type != no_match)
- || (filter == FILTER_STRICT && match_type == exact_match))
- return ipv6_match;
- }
- else if (CMD_IPV6_PREFIX(str))
- {
- match_type = cmd_ipv6_prefix_match(word);
- if ((filter == FILTER_RELAXED && match_type != no_match)
- || (filter == FILTER_STRICT && match_type == exact_match))
- return ipv6_prefix_match;
- }
-#endif /* HAVE_IPV6 */
- else if (CMD_IPV4(str))
- {
- match_type = cmd_ipv4_match(word);
- if ((filter == FILTER_RELAXED && match_type != no_match)
- || (filter == FILTER_STRICT && match_type == exact_match))
- return ipv4_match;
- }
- else if (CMD_IPV4_PREFIX(str))
- {
- match_type = cmd_ipv4_prefix_match(word);
- if ((filter == FILTER_RELAXED && match_type != no_match)
+ case TERMINAL_VARARG:
+ return vararg_match;
+
+ case TERMINAL_RANGE:
+ if (cmd_range_match(str, word))
+ return range_match;
+ break;
+
+ case TERMINAL_IPV6:
+ match_type = cmd_ipv6_match(word);
+ if ((filter == FILTER_RELAXED && match_type != no_match)
|| (filter == FILTER_STRICT && match_type == exact_match))
- return ipv4_prefix_match;
- }
- else if (CMD_OPTION(str) || CMD_VARIABLE(str))
- {
- return extend_match;
- }
- else
- {
- if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
- {
- if (!strcmp(str, word))
- return exact_match;
- return partly_match;
- }
- if (filter == FILTER_STRICT && !strcmp(str, word))
- return exact_match;
+ return ipv6_match;
+ break;
+
+ case TERMINAL_IPV6_PREFIX:
+ match_type = cmd_ipv6_prefix_match(word);
+ if ((filter == FILTER_RELAXED && match_type != no_match)
+ || (filter == FILTER_STRICT && match_type == exact_match))
+ return ipv6_prefix_match;
+ break;
+
+ case TERMINAL_IPV4:
+ match_type = cmd_ipv4_match(word);
+ if ((filter == FILTER_RELAXED && match_type != no_match)
+ || (filter == FILTER_STRICT && match_type == exact_match))
+ return ipv4_match;
+ break;
+
+ case TERMINAL_IPV4_PREFIX:
+ match_type = cmd_ipv4_prefix_match(word);
+ if ((filter == FILTER_RELAXED && match_type != no_match)
+ || (filter == FILTER_STRICT && match_type == exact_match))
+ return ipv4_prefix_match;
+ break;
+
+ case TERMINAL_OPTION:
+ case TERMINAL_VARIABLE:
+ return extend_match;
+
+ case TERMINAL_LITERAL:
+ if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
+ {
+ if (!strcmp(str, word))
+ return exact_match;
+ return partly_match;
+ }
+ if (filter == FILTER_STRICT && !strcmp(str, word))
+ return exact_match;
+ break;
+
+ default:
+ assert (0);
}
return no_match;
@@ -1308,7 +1330,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher,
if (!cmd_matcher_words_left(matcher))
{
- if (CMD_OPTION(token->cmd))
+ if (token->terminal == TERMINAL_OPTION)
return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
else
return MATCHER_INCOMPLETE;
@@ -1321,9 +1343,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher,
/* We have to record the input word as argument if it matched
* against a variable. */
- if (CMD_VARARG(token->cmd)
- || CMD_VARIABLE(token->cmd)
- || CMD_OPTION(token->cmd))
+ if (TERMINAL_RECORD (token->terminal))
{
if (push_argument(argc, argv, word))
return MATCHER_EXCEED_ARGC_MAX;
@@ -1334,7 +1354,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher,
matcher->word_index++;
/* A vararg token should consume all left over words as arguments */
- if (CMD_VARARG(token->cmd))
+ if (token->terminal == TERMINAL_VARARG)
while (cmd_matcher_words_left(matcher))
{
word = cmd_matcher_get_word(matcher);
@@ -1354,7 +1374,7 @@ cmd_matcher_match_multiple(struct cmd_matcher *matcher,
enum match_type multiple_match;
unsigned int multiple_index;
const char *word;
- const char *arg;
+ const char *arg = NULL;
struct cmd_token *word_token;
enum match_type word_match;
@@ -1565,9 +1585,7 @@ cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
{
word_token = vector_slot(keyword_vector, j);
if ((word_token->type == TOKEN_TERMINAL
- && (CMD_VARARG(word_token->cmd)
- || CMD_VARIABLE(word_token->cmd)
- || CMD_OPTION(word_token->cmd)))
+ && TERMINAL_RECORD (word_token->terminal))
|| word_token->type == TOKEN_MULTIPLE)
{
if (push_argument(argc, argv, NULL))
@@ -1853,12 +1871,12 @@ is_cmd_ambiguous (vector cmd_vector,
switch (type)
{
case exact_match:
- if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
+ if (!TERMINAL_RECORD (cmd_token->terminal)
&& strcmp (command, str) == 0)
match++;
break;
case partly_match:
- if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
+ if (!TERMINAL_RECORD (cmd_token->terminal)
&& strncmp (command, str, strlen (command)) == 0)
{
if (matched && strcmp (matched, str) != 0)
@@ -1880,7 +1898,7 @@ is_cmd_ambiguous (vector cmd_vector,
break;
#ifdef HAVE_IPV6
case ipv6_match:
- if (CMD_IPV6 (str))
+ if (cmd_token->terminal == TERMINAL_IPV6)
match++;
break;
case ipv6_prefix_match:
@@ -1894,7 +1912,7 @@ is_cmd_ambiguous (vector cmd_vector,
break;
#endif /* HAVE_IPV6 */
case ipv4_match:
- if (CMD_IPV4 (str))
+ if (cmd_token->terminal == TERMINAL_IPV4)
match++;
break;
case ipv4_prefix_match:
@@ -1907,7 +1925,7 @@ is_cmd_ambiguous (vector cmd_vector,
}
break;
case extend_match:
- if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ if (TERMINAL_RECORD (cmd_token->terminal))
match++;
break;
case no_match:
@@ -1923,11 +1941,12 @@ is_cmd_ambiguous (vector cmd_vector,
/* If src matches dst return dst string, otherwise return NULL */
static const char *
-cmd_entry_function (const char *src, const char *dst)
+cmd_entry_function (const char *src, struct cmd_token *token)
{
+ const char *dst = token->cmd;
+
/* Skip variable arguments. */
- if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
- CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
+ if (TERMINAL_RECORD (token->terminal))
return NULL;
/* In case of 'command \t', given src is NULL string. */
@@ -1945,65 +1964,64 @@ cmd_entry_function (const char *src, const char *dst)
/* This version will return the dst string always if it is
CMD_VARIABLE for '?' key processing */
static const char *
-cmd_entry_function_desc (const char *src, const char *dst)
+cmd_entry_function_desc (const char *src, struct cmd_token *token)
{
- if (CMD_VARARG (dst))
- return dst;
-
- if (CMD_RANGE (dst))
- {
- if (cmd_range_match (dst, src))
- return dst;
- else
- return NULL;
- }
-
-#ifdef HAVE_IPV6
- if (CMD_IPV6 (dst))
- {
- if (cmd_ipv6_match (src))
- return dst;
- else
- return NULL;
- }
-
- if (CMD_IPV6_PREFIX (dst))
- {
- if (cmd_ipv6_prefix_match (src))
- return dst;
- else
- return NULL;
- }
-#endif /* HAVE_IPV6 */
+ const char *dst = token->cmd;
- if (CMD_IPV4 (dst))
+ switch (token->terminal)
{
- if (cmd_ipv4_match (src))
- return dst;
- else
- return NULL;
+ case TERMINAL_VARARG:
+ return dst;
+
+ case TERMINAL_RANGE:
+ if (cmd_range_match (dst, src))
+ return dst;
+ else
+ return NULL;
+
+ case TERMINAL_IPV6:
+ if (cmd_ipv6_match (src))
+ return dst;
+ else
+ return NULL;
+
+ case TERMINAL_IPV6_PREFIX:
+ if (cmd_ipv6_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+
+ case TERMINAL_IPV4:
+ if (cmd_ipv4_match (src))
+ return dst;
+ else
+ return NULL;
+
+ case TERMINAL_IPV4_PREFIX:
+ if (cmd_ipv4_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+
+ /* Optional or variable commands always match on '?' */
+ case TERMINAL_OPTION:
+ case TERMINAL_VARIABLE:
+ return dst;
+
+ case TERMINAL_LITERAL:
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+ else
+ return NULL;
+
+ default:
+ assert(0);
+ return NULL;
}
-
- if (CMD_IPV4_PREFIX (dst))
- {
- if (cmd_ipv4_prefix_match (src))
- return dst;
- else
- return NULL;
- }
-
- /* Optional or variable commands always match on '?' */
- if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
- return dst;
-
- /* In case of 'command \t', given src is NULL string. */
- if (src == NULL)
- return dst;
-
- if (strncmp (src, dst, strlen (src)) == 0)
- return dst;
- else
- return NULL;
}
/**
@@ -2222,7 +2240,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
struct cmd_token *token = vector_slot(match_vector, j);
const char *string;
- string = cmd_entry_function_desc(command, token->cmd);
+ string = cmd_entry_function_desc(command, token);
if (string && desc_unique_string(matchvec, string))
vector_set(matchvec, token);
}
@@ -2348,7 +2366,7 @@ cmd_complete_sort(vector matchvec)
/* Command line completion support. */
static char **
-cmd_complete_command_real (vector vline, struct vty *vty, int *status)
+cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
{
unsigned int i;
vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
@@ -2433,13 +2451,14 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
for (j = 0; j < vector_active (match_vector); j++)
if ((token = vector_slot (match_vector, j)))
- {
- if ((string =
- cmd_entry_function (vector_slot (vline, index),
- token->cmd)))
- if (cmd_unique_string (matchvec, string))
- vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
- }
+ {
+ string = cmd_entry_function (vector_slot (vline, index),
+ token);
+ if (string && cmd_unique_string (matchvec, string))
+ vector_set (matchvec, (islib != 0 ?
+ XSTRDUP (MTYPE_TMP, string) :
+ strdup (string) /* rl freed */));
+ }
}
/* We don't need cmd_vector any more. */
@@ -2484,7 +2503,9 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
{
char *lcdstr;
- lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
+ lcdstr = (islib != 0 ?
+ XMALLOC (MTYPE_TMP, lcd + 1) :
+ malloc(lcd + 1));
memcpy (lcdstr, matchvec->index[0], lcd);
lcdstr[lcd] = '\0';
@@ -2492,10 +2513,15 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
/* Free matchvec. */
for (i = 0; i < vector_active (matchvec); i++)
- {
- if (vector_slot (matchvec, i))
- XFREE (MTYPE_TMP, vector_slot (matchvec, i));
- }
+ {
+ if (vector_slot (matchvec, i))
+ {
+ if (islib != 0)
+ XFREE (MTYPE_TMP, vector_slot (matchvec, i));
+ else
+ free (vector_slot (matchvec, i));
+ }
+ }
vector_free (matchvec);
/* Make new matchvec. */
@@ -2518,7 +2544,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
}
char **
-cmd_complete_command (vector vline, struct vty *vty, int *status)
+cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
{
char **ret;
@@ -2539,15 +2565,20 @@ cmd_complete_command (vector vline, struct vty *vty, int *status)
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
- ret = cmd_complete_command_real (shifted_vline, vty, status);
+ ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
vector_free(shifted_vline);
vty->node = onode;
return ret;
}
+ return cmd_complete_command_real (vline, vty, status, islib);
+}
- return cmd_complete_command_real (vline, vty, status);
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
+{
+ return cmd_complete_command_lib (vline, vty, status, 0);
}
/* return parent node */
@@ -2562,6 +2593,7 @@ node_parent ( enum node_type node )
switch (node)
{
case BGP_VPNV4_NODE:
+ case BGP_VPNV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
@@ -2947,9 +2979,10 @@ DEFUN (config_exit,
case VTY_NODE:
vty->node = CONFIG_NODE;
break;
- case BGP_VPNV4_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
+ case BGP_VPNV4_NODE:
+ case BGP_VPNV6_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
vty->node = BGP_NODE;
@@ -2990,6 +3023,7 @@ DEFUN (config_end,
case RIPNG_NODE:
case BGP_NODE:
case BGP_VPNV4_NODE:
+ case BGP_VPNV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
@@ -3022,6 +3056,8 @@ DEFUN (show_version,
vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
VTY_NEWLINE);
vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
+ vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE,
+ QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -3117,7 +3153,7 @@ DEFUN (config_write_file,
/* Make vty for configuration file. */
file_vty = vty_new ();
- file_vty->fd = fd;
+ file_vty->wfd = fd;
file_vty->type = VTY_FILE;
/* Config file header print. */
@@ -4054,6 +4090,37 @@ DEFUN (no_banner_motd,
return CMD_SUCCESS;
}
+DEFUN (show_commandtree,
+ show_commandtree_cmd,
+ "show commandtree",
+ NO_STR
+ "Show command tree\n")
+{
+ /* TBD */
+ vector cmd_vector;
+ unsigned int i;
+
+ vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE);
+
+ /* vector of all commands installed at this node */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ /* loop over all commands at this node */
+ for (i = 0; i < vector_active(cmd_vector); ++i)
+ {
+ struct cmd_element *cmd_element;
+
+ /* A cmd_element (seems to be) is an individual command */
+ if ((cmd_element = vector_slot (cmd_vector, i)) == NULL)
+ continue;
+
+ vty_out (vty, " %s%s", cmd_element->string, VTY_NEWLINE);
+ }
+
+ vector_free (cmd_vector);
+ return CMD_SUCCESS;
+}
+
/* Set config filename. Called from vty.c */
void
host_config_set (const char *filename)
@@ -4085,6 +4152,7 @@ cmd_init (int terminal)
{
command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
token_cr.type = TOKEN_TERMINAL;
+ token_cr.terminal = TERMINAL_LITERAL;
token_cr.cmd = command_cr;
token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
@@ -4121,6 +4189,7 @@ cmd_init (int terminal)
install_element (VIEW_NODE, &config_terminal_length_cmd);
install_element (VIEW_NODE, &config_terminal_no_length_cmd);
install_element (VIEW_NODE, &show_logging_cmd);
+ install_element (VIEW_NODE, &show_commandtree_cmd);
install_element (VIEW_NODE, &echo_cmd);
install_element (RESTRICTED_NODE, &config_list_cmd);
@@ -4130,6 +4199,7 @@ cmd_init (int terminal)
install_element (RESTRICTED_NODE, &config_enable_cmd);
install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
+ install_element (RESTRICTED_NODE, &show_commandtree_cmd);
install_element (RESTRICTED_NODE, &echo_cmd);
}
@@ -4142,6 +4212,7 @@ cmd_init (int terminal)
}
install_element (ENABLE_NODE, &show_startup_config_cmd);
install_element (ENABLE_NODE, &show_version_cmd);
+ install_element (ENABLE_NODE, &show_commandtree_cmd);
if (terminal)
{
@@ -4206,7 +4277,8 @@ cmd_init (int terminal)
vrf_install_commands ();
}
- srand(time(NULL));
+ install_element (CONFIG_NODE, &show_commandtree_cmd);
+ srandom(time(NULL));
}
static void