summaryrefslogtreecommitdiff
path: root/lib/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c3464
1 files changed, 762 insertions, 2702 deletions
diff --git a/lib/command.c b/lib/command.c
index 0b0614b806..f691cb599a 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1,25 +1,29 @@
/*
- Command interpreter routine for virtual terminal [aka TeletYpe]
- Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
- Copyright (C) 2013 by Open Source Routing.
- Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
-
-This file is part of GNU Zebra.
-
-GNU Zebra 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; either version 2, or (at your
-option) any later version.
-
-GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+ * CLI backend interface.
+ *
+ * --
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ * Copyright (C) 2013 by Open Source Routing.
+ * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
#include <zebra.h>
@@ -29,10 +33,13 @@ Boston, MA 02111-1307, USA. */
#include <lib/version.h>
#include "thread.h"
#include "vector.h"
+#include "linklist.h"
#include "vty.h"
#include "command.h"
#include "workqueue.h"
#include "vrf.h"
+#include "command_match.h"
+#include "command_parse.h"
#include "qobj.h"
DEFINE_MTYPE( LIB, HOST, "Host config")
@@ -43,44 +50,6 @@ DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
each daemon maintains each own cmdvec. */
vector cmdvec = NULL;
-struct cmd_token token_cr;
-char *command_cr = NULL;
-
-/**
- * Filter types. These tell the parser whether to allow
- * partial matching on tokens.
- */
-enum filter_type
-{
- FILTER_RELAXED,
- FILTER_STRICT
-};
-
-/**
- * Command matcher result value.
- */
-enum matcher_rv
-{
- MATCHER_OK,
- MATCHER_COMPLETE,
- MATCHER_INCOMPLETE,
- MATCHER_NO_MATCH,
- MATCHER_AMBIGUOUS,
- MATCHER_EXCEED_ARGC_MAX
-};
-
-/**
- * Defines which matcher_rv values constitute
- * an error. Should be used against matcher_rv
- * return values to do basic error checking.
- */
-#define MATCHER_ERROR(matcher_rv) \
- ( (matcher_rv) == MATCHER_INCOMPLETE \
- || (matcher_rv) == MATCHER_NO_MATCH \
- || (matcher_rv) == MATCHER_AMBIGUOUS \
- || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
- )
-
/* Host information structure. */
struct host host;
@@ -128,7 +97,7 @@ static const struct facility_map {
int facility;
const char *name;
size_t match;
-} syslog_facilities[] =
+} syslog_facilities[] =
{
{ LOG_KERN, "kern", 1 },
{ LOG_USER, "user", 2 },
@@ -180,7 +149,7 @@ static int
level_match(const char *s)
{
int level ;
-
+
for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
if (!strncmp (s, zlog_priority[level], 2))
return level;
@@ -200,7 +169,7 @@ print_version (const char *progname)
/* Utility function to concatenate argv argument into a single string
with inserting ' ' character between each argument. */
char *
-argv_concat (const char **argv, int argc, int shift)
+argv_concat (struct cmd_token **argv, int argc, int shift)
{
int i;
size_t len;
@@ -209,14 +178,14 @@ argv_concat (const char **argv, int argc, int shift)
len = 0;
for (i = shift; i < argc; i++)
- len += strlen(argv[i])+1;
+ len += strlen(argv[i]->arg)+1;
if (!len)
return NULL;
p = str = XMALLOC(MTYPE_TMP, len);
for (i = shift; i < argc; i++)
{
size_t arglen;
- memcpy(p, argv[i], (arglen = strlen(argv[i])));
+ memcpy(p, argv[i]->arg, (arglen = strlen(argv[i]->arg)));
p += arglen;
*p++ = ' ';
}
@@ -224,6 +193,26 @@ argv_concat (const char **argv, int argc, int shift)
return str;
}
+/**
+ * Convenience function for accessing argv data.
+ *
+ * @param argc
+ * @param argv
+ * @param text definition snippet of the desired token
+ * @param index the starting index, and where to store the
+ * index of the found token if it exists
+ * @return 1 if found, 0 otherwise
+ */
+int
+argv_find (struct cmd_token **argv, int argc, const char *text, int *index)
+{
+ int found = 0;
+ for (int i = *index; i < argc && found == 0; i++)
+ if ((found = strmatch (text, argv[i]->text)))
+ *index = i;
+ return found;
+}
+
static unsigned int
cmd_hash_key (void *p)
{
@@ -238,65 +227,57 @@ cmd_hash_cmp (const void *a, const void *b)
/* Install top node of command vector. */
void
-install_node (struct cmd_node *node,
- int (*func) (struct vty *))
+install_node (struct cmd_node *node,
+ int (*func) (struct vty *))
{
vector_set_index (cmdvec, node->node, node);
node->func = func;
+ node->cmdgraph = graph_new ();
node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+ // add start node
+ struct cmd_token *token = new_cmd_token (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ graph_new_node (node->cmdgraph, token, (void (*)(void *)) &del_cmd_token);
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
}
-/* Breaking up string into each command piece. I assume given
- character is separated by a space character. Return value is a
- vector which includes char ** data element. */
+/**
+ * Tokenizes a string, storing tokens in a vector.
+ * Whitespace is ignored.
+ *
+ * Delimiter string = " \n\r\t".
+ *
+ * @param string to tokenize
+ * @return tokenized string
+ */
vector
cmd_make_strvec (const char *string)
{
- const char *cp, *start;
- char *token;
- int strlen;
- vector strvec;
-
- if (string == NULL)
- return NULL;
-
- cp = string;
+ if (!string) return NULL;
- /* Skip white spaces. */
- while (isspace ((int) *cp) && *cp != '\0')
- cp++;
+ char *copy, *copystart;
+ copystart = copy = XSTRDUP (MTYPE_TMP, string);
- /* Return if there is only white spaces */
- if (*cp == '\0')
- return NULL;
+ // skip leading whitespace
+ while (isspace ((int) *copy) && *copy != '\0') copy++;
- if (*cp == '!' || *cp == '#')
+ // if the entire string was whitespace or a comment, return
+ if (*copy == '\0' || *copy == '!' || *copy == '#')
+ {
+ XFREE (MTYPE_TMP, copystart);
return NULL;
+ }
- /* Prepare return vector. */
- strvec = vector_init (VECTOR_MIN_SIZE);
+ vector strvec = vector_init (VECTOR_MIN_SIZE);
+ const char *delim = " \n\r\t", *tok = NULL;
+ while (copy)
+ {
+ tok = strsep (&copy, delim);
+ if (*tok != '\0')
+ vector_set (strvec, XSTRDUP (MTYPE_STRVEC, tok));
+ }
- /* Copy each command piece and set into vector. */
- while (1)
- {
- start = cp;
- while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
- *cp != '\0')
- cp++;
- strlen = cp - start;
- token = XMALLOC (MTYPE_STRVEC, strlen + 1);
- memcpy (token, start, strlen);
- *(token + strlen) = '\0';
- vector_set (strvec, token);
-
- while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
- *cp != '\0')
- cp++;
-
- if (*cp == '\0')
- return strvec;
- }
+ XFREE (MTYPE_TMP, copystart);
+ return strvec;
}
/* Free allocated string vector. */
@@ -316,387 +297,22 @@ cmd_free_strvec (vector v)
vector_free (v);
}
-/**
- * State structure for command format parser. Tracks
- * parse tree position and miscellaneous state variables.
- * Used when building a command vector from format strings.
- */
-struct format_parser_state
-{
- vector topvect; /* Top level vector */
- vector intvect; /* Intermediate level vector, used when there's
- a multiple in a keyword. */
- vector curvect; /* current vector where read tokens should be
- appended. */
-
- const char *string; /* pointer to command string, not modified */
- const char *cp; /* pointer in command string, moved along while
- parsing */
- const char *dp; /* pointer in description string, moved along while
- parsing */
-
- int in_keyword; /* flag to remember if we are in a keyword group */
- int in_multiple; /* flag to remember if we are in a multiple group */
- int just_read_word; /* flag to remember if the last thing we read was a
- real word and not some abstract token */
-};
-
-static void
-format_parser_error(struct format_parser_state *state, const char *message)
-{
- int offset = state->cp - state->string + 1;
-
- fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
- fprintf(stderr, " %*c\n", offset, '^');
- fprintf(stderr, "%s at offset %d.\n", message, offset);
- fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
- exit(1);
-}
-
-/**
- * Reads out one section of a help string from state->dp.
- * Leading whitespace is trimmed and the string is read until
- * a newline is reached.
- *
- * @param[out] state format parser state
- * @return the help string token read
- */
-static char *
-format_parser_desc_str(struct format_parser_state *state)
-{
- const char *cp, *start;
- char *token;
- int strlen;
-
- cp = state->dp;
-
- if (cp == NULL)
- return NULL;
-
- /* Skip white spaces. */
- while (isspace ((int) *cp) && *cp != '\0')
- cp++;
-
- /* Return if there is only white spaces */
- if (*cp == '\0')
- return NULL;
-
- start = cp;
-
- while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
- cp++;
-
- strlen = cp - start;
- token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
- memcpy (token, start, strlen);
- *(token + strlen) = '\0';
-
- state->dp = cp;
-
- return token;
-}
-
-/**
- * Transitions format parser state into keyword parsing mode.
- * A cmd_token struct, `token`, representing this keyword token is initialized
- * and appended to state->curvect. token->keyword is initialized as a vector of
- * vector, a new vector is initialized and added to token->keyword, and
- * state->curvect is set to point at this vector. When control returns to the
- * caller newly parsed tokens will be added to this vector.
- *
- * In short:
- * state->curvect[HEAD] = new cmd_token
- * state->curvect[HEAD]->keyword[0] = new vector
- * state->curvect = state->curvect[HEAD]->keyword[0]
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_begin_keyword(struct format_parser_state *state)
-{
- struct cmd_token *token;
- vector keyword_vect;
-
- if (state->in_keyword
- || state->in_multiple)
- format_parser_error(state, "Unexpected '{'");
-
- state->cp++;
- state->in_keyword = 1;
-
- token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
- token->type = TOKEN_KEYWORD;
- token->keyword = vector_init(VECTOR_MIN_SIZE);
-
- keyword_vect = vector_init(VECTOR_MIN_SIZE);
- vector_set(token->keyword, keyword_vect);
-
- vector_set(state->curvect, token);
- state->curvect = keyword_vect;
-}
-
-/**
- * Transitions format parser state into multiple parsing mode.
- * A cmd_token struct, `token`, representing this multiple token is initialized
- * and appended to state->curvect. token->multiple is initialized as a vector
- * of cmd_token and state->curvect is set to point at token->multiple. If
- * state->curvect != state->topvect (i.e. this multiple token is nested inside
- * another composite token) then a pointer to state->curvect is saved in
- * state->intvect.
- *
- * In short:
- * state->curvect[HEAD] = new cmd_token
- * state->curvect[HEAD]->multiple = new vector
- * state->intvect = state->curvect IFF nested token
- * state->curvect = state->curvect[HEAD]->multiple
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_begin_multiple(struct format_parser_state *state)
-{
- struct cmd_token *token;
-
- if (state->in_keyword == 1)
- format_parser_error(state, "Keyword starting with '('");
-
- if (state->in_multiple)
- format_parser_error(state, "Nested group");
-
- state->cp++;
- state->in_multiple = 1;
- state->just_read_word = 0;
-
- token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
- token->type = TOKEN_MULTIPLE;
- token->multiple = vector_init(VECTOR_MIN_SIZE);
-
- vector_set(state->curvect, token);
- if (state->curvect != state->topvect)
- state->intvect = state->curvect;
- state->curvect = token->multiple;
-}
-
-/**
- * Transition format parser state out of keyword parsing mode.
- * This function is called upon encountering '}'.
- * state->curvect is reassigned to the top level vector (as
- * keywords cannot be nested) and state flags are set appropriately.
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_end_keyword(struct format_parser_state *state)
-{
- if (state->in_multiple
- || !state->in_keyword)
- format_parser_error(state, "Unexpected '}'");
-
- if (state->in_keyword == 1)
- format_parser_error(state, "Empty keyword group");
-
- state->cp++;
- state->in_keyword = 0;
- state->curvect = state->topvect;
-}
-
-/**
- * Transition format parser state out of multiple parsing mode.
- * This function is called upon encountering ')'.
- * state->curvect is reassigned to its parent vector (state->intvect
- * if the multiple token being exited was nested inside another token,
- * state->topvect otherwise) and state flags are set appropriately.
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_end_multiple(struct format_parser_state *state)
-{
- char *dummy;
-
- if (!state->in_multiple)
- format_parser_error(state, "Unexpected ')'");
-
- if (vector_active(state->curvect) == 0)
- format_parser_error(state, "Empty multiple section");
-
- if (!state->just_read_word)
- {
- /* There are constructions like
- * 'show ip ospf database ... (self-originate|)'
- * in use.
- * The old parser reads a description string for the
- * word '' between |) which will never match.
- * Simulate this behvaior by dropping the next desc
- * string in such a case. */
-
- dummy = format_parser_desc_str(state);
- XFREE(MTYPE_CMD_TOKENS, dummy);
- }
-
- state->cp++;
- state->in_multiple = 0;
-
- if (state->intvect)
- state->curvect = state->intvect;
- else
- state->curvect = state->topvect;
-}
-
-/**
- * Format parser handler for pipe '|' character.
- * This character separates subtokens in multiple and keyword type tokens.
- * If the current token is a multiple keyword, the position pointer is
- * simply moved past the pipe and state flags are set appropriately.
- * If the current token is a keyword token, the position pointer is moved
- * past the pipe. Then the cmd_token struct for the keyword is fetched and
- * a new vector of cmd_token is appended to its vector of vector. Finally
- * state->curvect is set to point at this new vector.
- *
- * In short:
- * state->curvect = state->topvect[HEAD]->keyword[HEAD] = new vector
- *
- * @param[out] state state struct to transition
- */
-static void
-format_parser_handle_pipe(struct format_parser_state *state)
-{
- struct cmd_token *keyword_token;
- vector keyword_vect;
-
- if (state->in_multiple)
- {
- state->just_read_word = 0;
- state->cp++;
- }
- else if (state->in_keyword)
- {
- state->in_keyword = 1;
- state->cp++;
-
- keyword_token = vector_slot(state->topvect,
- vector_active(state->topvect) - 1);
- keyword_vect = vector_init(VECTOR_MIN_SIZE);
- vector_set(keyword_token->keyword, keyword_vect);
- state->curvect = keyword_vect;
- }
- else
- {
- format_parser_error(state, "Unexpected '|'");
- }
-}
-
-/**
- * Format parser handler for terminal tokens.
- * Parses the token, appends it to state->curvect, and sets
- * state flags appropriately.
- *
- * @param[out] state state struct for current format parser state
- */
-static void
-format_parser_read_word(struct format_parser_state *state)
-{
- const char *start;
- int len;
- char *cmd;
- struct cmd_token *token;
-
- start = state->cp;
-
- while (state->cp[0] != '\0'
- && !strchr("\r\n(){}|", state->cp[0])
- && !isspace((int)state->cp[0]))
- state->cp++;
-
- len = state->cp - start;
- cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
- memcpy(cmd, start, len);
- cmd[len] = '\0';
-
- 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);
-
- if (state->in_keyword == 1)
- state->in_keyword = 2;
-
- state->just_read_word = 1;
-}
-
-/**
- * Parse a given command format string and build a tree of tokens from
- * it that is suitable to be used by the command subsystem.
- *
- * @param string Command format string.
- * @param descstr Description string.
- * @return A vector of struct cmd_token representing the given command,
- * or NULL on error.
- */
-static vector
-cmd_parse_format(const char *string, const char *descstr)
+char *
+cmd_concat_strvec (vector v)
{
- struct format_parser_state state;
-
- if (string == NULL)
- return NULL;
-
- memset(&state, 0, sizeof(state));
- state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
- state.cp = state.string = string;
- state.dp = descstr;
+ size_t strsize = 0;
+ for (unsigned int i = 0; i < vector_active (v); i++)
+ if (vector_slot (v, i))
+ strsize += strlen ((char *) vector_slot (v, i)) + 1;
- while (1)
- {
- while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
- state.cp++;
+ char *concatenated = calloc (sizeof (char), strsize);
+ for (unsigned int i = 0; i < vector_active (v); i++)
+ {
+ strlcat (concatenated, (char *) vector_slot (v, i), strsize);
+ strlcat (concatenated, " ", strsize);
+ }
- switch (state.cp[0])
- {
- case '\0':
- if (state.in_keyword
- || state.in_multiple)
- format_parser_error(&state, "Unclosed group/keyword");
- return state.topvect;
- case '{':
- format_parser_begin_keyword(&state);
- break;
- case '(':
- format_parser_begin_multiple(&state);
- break;
- case '}':
- format_parser_end_keyword(&state);
- break;
- case ')':
- format_parser_end_multiple(&state);
- break;
- case '|':
- format_parser_handle_pipe(&state);
- break;
- default:
- format_parser_read_word(&state);
- }
- }
+ return concatenated;
}
/* Return prompt character of specified node. */
@@ -714,7 +330,7 @@ void
install_element (enum node_type ntype, struct cmd_element *cmd)
{
struct cmd_node *cnode;
-
+
/* cmd_init hasn't been called */
if (!cmdvec)
{
@@ -722,29 +338,28 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
__func__);
return;
}
-
+
cnode = vector_slot (cmdvec, ntype);
- if (cnode == NULL)
+ if (cnode == NULL)
{
fprintf (stderr, "Command node %d doesn't exist, please check it\n",
- ntype);
- exit (1);
+ ntype);
+ exit (EXIT_FAILURE);
}
-
+
if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
{
- fprintf (stderr,
+ fprintf (stderr,
"Multiple command installs to node %d of command:\n%s\n",
ntype, cmd->string);
return;
}
-
+
assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
-
+
+ command_parse_format (cnode->cmdgraph, cmd);
vector_set (cnode->cmd_vector, cmd);
- if (cmd->tokens == NULL)
- cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
if (ntype == VIEW_NODE)
install_element (ENABLE_NODE, cmd);
@@ -756,7 +371,7 @@ static const unsigned char itoa64[] =
static void
to64(char *s, long v, int n)
{
- while (--n >= 0)
+ while (--n >= 0)
{
*s++ = itoa64[v&0x3f];
v >>= 6;
@@ -771,7 +386,7 @@ zencrypt (const char *passwd)
char *crypt (const char *, const char *);
gettimeofday(&tv,0);
-
+
to64(&salt[0], random(), 3);
to64(&salt[3], tv.tv_usec, 3);
salt[5] = '\0';
@@ -789,9 +404,9 @@ config_write_host (struct vty *vty)
if (host.encrypt)
{
if (host.password_encrypt)
- vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
+ vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
if (host.enable_encrypt)
- vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
+ vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
}
else
{
@@ -804,17 +419,17 @@ config_write_host (struct vty *vty)
if (zlog_default->default_lvl != LOG_DEBUG)
{
vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
- VTY_NEWLINE);
+ VTY_NEWLINE);
vty_out (vty, "log trap %s%s",
- zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
+ zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
}
if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
{
vty_out (vty, "log file %s", host.logfile);
if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
- vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
+ vty_out (vty, " %s",
+ zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -822,8 +437,8 @@ config_write_host (struct vty *vty)
{
vty_out (vty, "log stdout");
if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
- vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
+ vty_out (vty, " %s",
+ zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -831,27 +446,27 @@ config_write_host (struct vty *vty)
vty_out(vty,"no log monitor%s",VTY_NEWLINE);
else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
vty_out(vty,"log monitor %s%s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
+ zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
{
vty_out (vty, "log syslog");
if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
- vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
+ vty_out (vty, " %s",
+ zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
vty_out (vty, "%s", VTY_NEWLINE);
}
if (zlog_default->facility != LOG_DAEMON)
vty_out (vty, "log facility %s%s",
- facility_name(zlog_default->facility), VTY_NEWLINE);
+ facility_name(zlog_default->facility), VTY_NEWLINE);
if (zlog_default->record_priority == 1)
vty_out (vty, "log record-priority%s", VTY_NEWLINE);
if (zlog_default->timestamp_precision > 0)
vty_out (vty, "log timestamp precision %d%s",
- zlog_default->timestamp_precision, VTY_NEWLINE);
+ zlog_default->timestamp_precision, VTY_NEWLINE);
if (host.advanced)
vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
@@ -861,7 +476,7 @@ config_write_host (struct vty *vty)
if (host.lines >= 0)
vty_out (vty, "service terminal-length %d%s", host.lines,
- VTY_NEWLINE);
+ VTY_NEWLINE);
if (host.motdfile)
vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
@@ -871,1376 +486,128 @@ config_write_host (struct vty *vty)
return 1;
}
-/* Utility function for getting command vector. */
-static vector
-cmd_node_vector (vector v, enum node_type ntype)
+/* Utility function for getting command graph. */
+static struct graph *
+cmd_node_graph (vector v, enum node_type ntype)
{
struct cmd_node *cnode = vector_slot (v, ntype);
- return cnode->cmd_vector;
-}
-
-/* Completion match types. */
-enum match_type
-{
- no_match,
- extend_match,
- ipv4_prefix_match,
- ipv4_match,
- ipv6_prefix_match,
- ipv6_match,
- range_match,
- vararg_match,
- partly_match,
- exact_match
-};
-
-static enum match_type
-cmd_ipv4_match (const char *str)
-{
- const char *sp;
- int dots = 0, nums = 0;
- char buf[4];
-
- if (str == NULL)
- return partly_match;
-
- for (;;)
- {
- memset (buf, 0, sizeof (buf));
- sp = str;
- while (*str != '\0')
- {
- if (*str == '.')
- {
- if (dots >= 3)
- return no_match;
-
- if (*(str + 1) == '.')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
- if (!isdigit ((int) *str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy (buf, sp, str - sp);
- if (atoi (buf) > 255)
- return no_match;
-
- nums++;
-
- if (*str == '\0')
- break;
-
- str++;
- }
-
- if (nums < 4)
- return partly_match;
-
- return exact_match;
-}
-
-static enum match_type
-cmd_ipv4_prefix_match (const char *str)
-{
- const char *sp;
- int dots = 0;
- char buf[4];
-
- if (str == NULL)
- return partly_match;
-
- for (;;)
- {
- memset (buf, 0, sizeof (buf));
- sp = str;
- while (*str != '\0' && *str != '/')
- {
- if (*str == '.')
- {
- if (dots == 3)
- return no_match;
-
- if (*(str + 1) == '.' || *(str + 1) == '/')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
-
- if (!isdigit ((int) *str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy (buf, sp, str - sp);
- if (atoi (buf) > 255)
- return no_match;
-
- if (dots == 3)
- {
- if (*str == '/')
- {
- if (*(str + 1) == '\0')
- return partly_match;
-
- str++;
- break;
- }
- else if (*str == '\0')
- return partly_match;
- }
-
- if (*str == '\0')
- return partly_match;
-
- str++;
- }
-
- sp = str;
- while (*str != '\0')
- {
- if (!isdigit ((int) *str))
- return no_match;
-
- str++;
- }
-
- if (atoi (sp) > 32)
- return no_match;
-
- return exact_match;
-}
-
-#define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
-#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
-
-#ifdef HAVE_IPV6
-
-static enum match_type
-cmd_ipv6_match (const char *str)
-{
- struct sockaddr_in6 sin6_dummy;
- int ret;
-
- if (str == NULL)
- return partly_match;
-
- if (strspn (str, IPV6_ADDR_STR) != strlen (str))
- return no_match;
-
- /* use inet_pton that has a better support,
- * for example inet_pton can support the automatic addresses:
- * ::1.2.3.4
- */
- ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-
- if (ret == 1)
- return exact_match;
-
- return no_match;
-}
-
-static enum match_type
-cmd_ipv6_prefix_match (const char *str)
-{
- struct sockaddr_in6 sin6_dummy;
- const char *delim = "/\0";
- char *dupe, *prefix, *mask, *context, *endptr;
- int nmask = -1;
-
- if (str == NULL)
- return partly_match;
-
- if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
- return no_match;
-
- /* tokenize to address + mask */
- dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
- strncpy(dupe, str, strlen(str)+1);
- prefix = strtok_r(dupe, delim, &context);
- mask = strtok_r(NULL, delim, &context);
-
- if (!mask)
- return partly_match;
-
- /* validate prefix */
- if (inet_pton(AF_INET6, prefix, &sin6_dummy.sin6_addr) != 1)
- return no_match;
-
- /* validate mask */
- nmask = strtol (mask, &endptr, 10);
- if (*endptr != '\0' || nmask < 0 || nmask > 128)
- return no_match;
-
- XFREE(MTYPE_TMP, dupe);
-
- return exact_match;
+ return cnode->cmdgraph;
}
-#endif /* HAVE_IPV6 */
-
-#define DECIMAL_STRLEN_MAX 20
-
static int
-cmd_range_match (const char *range, const char *str)
-{
- char *p;
- char buf[DECIMAL_STRLEN_MAX + 1];
- char *endptr = NULL;
- signed long long min, max, val;
-
- if (str == NULL)
+cmd_try_do_shortcut (enum node_type node, char* first_word) {
+ if ( first_word != NULL &&
+ node != AUTH_NODE &&
+ node != VIEW_NODE &&
+ node != AUTH_ENABLE_NODE &&
+ node != ENABLE_NODE &&
+ 0 == strcmp( "do", first_word ) )
return 1;
-
- val = strtoll (str, &endptr, 10);
- if (*endptr != '\0')
- return 0;
- val = llabs(val);
-
- range++;
- p = strchr (range, '-');
- if (p == NULL)
- return 0;
- if (p - range > DECIMAL_STRLEN_MAX)
- return 0;
- strncpy (buf, range, p - range);
- buf[p - range] = '\0';
- min = strtoll (buf, &endptr, 10);
- if (*endptr != '\0')
- return 0;
-
- range = p + 1;
- p = strchr (range, '>');
- if (p == NULL)
- return 0;
- if (p - range > DECIMAL_STRLEN_MAX)
- return 0;
- strncpy (buf, range, p - range);
- buf[p - range] = '\0';
- max = strtoll (buf, &endptr, 10);
- if (*endptr != '\0')
- return 0;
-
- if (val < min || val > max)
- return 0;
-
- return 1;
-}
-
-static enum match_type
-cmd_word_match(struct cmd_token *token,
- enum filter_type filter,
- const char *word)
-{
- const char *str;
- enum match_type match_type;
-
- str = token->cmd;
-
- if (filter == FILTER_RELAXED)
- if (!word || !strlen(word))
- return partly_match;
-
- if (!word)
- return no_match;
-
- switch (token->terminal)
- {
- 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 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;
-}
-
-struct cmd_matcher
-{
- struct cmd_element *cmd; /* The command element the matcher is using */
- enum filter_type filter; /* Whether to use strict or relaxed matching */
- vector vline; /* The tokenized commandline which is to be matched */
- unsigned int index; /* The index up to which matching should be done */
-
- /* If set, construct a list of matches at the position given by index */
- enum match_type *match_type;
- vector *match;
-
- unsigned int word_index; /* iterating over vline */
-};
-
-static int
-push_argument(int *argc, const char **argv, const char *arg)
-{
- if (!arg || !strlen(arg))
- arg = NULL;
-
- if (!argc || !argv)
- return 0;
-
- if (*argc >= CMD_ARGC_MAX)
- return -1;
-
- argv[(*argc)++] = arg;
return 0;
}
-static void
-cmd_matcher_record_match(struct cmd_matcher *matcher,
- enum match_type match_type,
- struct cmd_token *token)
-{
- if (matcher->word_index != matcher->index)
- return;
-
- if (matcher->match)
- {
- if (!*matcher->match)
- *matcher->match = vector_init(VECTOR_MIN_SIZE);
- vector_set(*matcher->match, token);
- }
-
- if (matcher->match_type)
- {
- if (match_type > *matcher->match_type)
- *matcher->match_type = match_type;
- }
-}
-
-static int
-cmd_matcher_words_left(struct cmd_matcher *matcher)
-{
- return matcher->word_index < vector_active(matcher->vline);
-}
-
-static const char*
-cmd_matcher_get_word(struct cmd_matcher *matcher)
-{
- assert(cmd_matcher_words_left(matcher));
-
- return vector_slot(matcher->vline, matcher->word_index);
-}
-
-static enum matcher_rv
-cmd_matcher_match_terminal(struct cmd_matcher *matcher,
- struct cmd_token *token,
- int *argc, const char **argv)
-{
- const char *word;
- enum match_type word_match;
-
- assert(token->type == TOKEN_TERMINAL);
-
- if (!cmd_matcher_words_left(matcher))
- {
- if (token->terminal == TERMINAL_OPTION)
- return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
- else
- return MATCHER_INCOMPLETE;
- }
-
- word = cmd_matcher_get_word(matcher);
- word_match = cmd_word_match(token, matcher->filter, word);
- if (word_match == no_match)
- return MATCHER_NO_MATCH;
-
- /* We have to record the input word as argument if it matched
- * against a variable. */
- if (TERMINAL_RECORD (token->terminal))
- {
- if (push_argument(argc, argv, word))
- return MATCHER_EXCEED_ARGC_MAX;
- }
-
- cmd_matcher_record_match(matcher, word_match, token);
-
- matcher->word_index++;
-
- /* A vararg token should consume all left over words as arguments */
- if (token->terminal == TERMINAL_VARARG)
- while (cmd_matcher_words_left(matcher))
- {
- word = cmd_matcher_get_word(matcher);
- if (word && strlen(word))
- push_argument(argc, argv, word);
- matcher->word_index++;
- }
-
- return MATCHER_OK;
-}
-
-static enum matcher_rv
-cmd_matcher_match_multiple(struct cmd_matcher *matcher,
- struct cmd_token *token,
- int *argc, const char **argv)
-{
- enum match_type multiple_match;
- unsigned int multiple_index;
- const char *word;
- const char *arg = NULL;
- struct cmd_token *word_token;
- enum match_type word_match;
-
- assert(token->type == TOKEN_MULTIPLE);
-
- multiple_match = no_match;
-
- if (!cmd_matcher_words_left(matcher))
- return MATCHER_INCOMPLETE;
-
- word = cmd_matcher_get_word(matcher);
- for (multiple_index = 0;
- multiple_index < vector_active(token->multiple);
- multiple_index++)
- {
- word_token = vector_slot(token->multiple, multiple_index);
-
- word_match = cmd_word_match(word_token, matcher->filter, word);
- if (word_match == no_match)
- continue;
-
- cmd_matcher_record_match(matcher, word_match, word_token);
-
- if (word_match > multiple_match)
- {
- multiple_match = word_match;
- arg = word;
- }
- /* To mimic the behavior of the old command implementation, we
- * tolerate any ambiguities here :/ */
- }
-
- matcher->word_index++;
-
- if (multiple_match == no_match)
- return MATCHER_NO_MATCH;
-
- if (push_argument(argc, argv, arg))
- return MATCHER_EXCEED_ARGC_MAX;
-
- return MATCHER_OK;
-}
-
-static enum matcher_rv
-cmd_matcher_read_keywords(struct cmd_matcher *matcher,
- struct cmd_token *token,
- vector args_vector)
-{
- unsigned int i;
- unsigned long keyword_mask;
- unsigned int keyword_found;
- enum match_type keyword_match;
- enum match_type word_match;
- vector keyword_vector;
- struct cmd_token *word_token;
- const char *word;
- int keyword_argc;
- const char **keyword_argv;
- enum matcher_rv rv = MATCHER_OK;
-
- keyword_mask = 0;
- while (1)
- {
- if (!cmd_matcher_words_left(matcher))
- return MATCHER_OK;
-
- word = cmd_matcher_get_word(matcher);
-
- keyword_found = -1;
- keyword_match = no_match;
- for (i = 0; i < vector_active(token->keyword); i++)
- {
- if (keyword_mask & (1 << i))
- continue;
-
- keyword_vector = vector_slot(token->keyword, i);
- word_token = vector_slot(keyword_vector, 0);
-
- word_match = cmd_word_match(word_token, matcher->filter, word);
- if (word_match == no_match)
- continue;
-
- cmd_matcher_record_match(matcher, word_match, word_token);
-
- if (word_match > keyword_match)
- {
- keyword_match = word_match;
- keyword_found = i;
- }
- else if (word_match == keyword_match)
- {
- if (matcher->word_index != matcher->index || args_vector)
- return MATCHER_AMBIGUOUS;
- }
- }
-
- if (keyword_found == (unsigned int)-1)
- return MATCHER_NO_MATCH;
-
- matcher->word_index++;
-
- if (matcher->word_index > matcher->index)
- return MATCHER_OK;
-
- keyword_mask |= (1 << keyword_found);
-
- if (args_vector)
- {
- keyword_argc = 0;
- keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
- /* We use -1 as a marker for unused fields as NULL might be a valid value */
- for (i = 0; i < CMD_ARGC_MAX + 1; i++)
- keyword_argv[i] = (void*)-1;
- vector_set_index(args_vector, keyword_found, keyword_argv);
- }
- else
- {
- keyword_argv = NULL;
- }
-
- keyword_vector = vector_slot(token->keyword, keyword_found);
- /* the keyword itself is at 0. We are only interested in the arguments,
- * so start counting at 1. */
- for (i = 1; i < vector_active(keyword_vector); i++)
- {
- word_token = vector_slot(keyword_vector, i);
-
- switch (word_token->type)
- {
- case TOKEN_TERMINAL:
- rv = cmd_matcher_match_terminal(matcher, word_token,
- &keyword_argc, keyword_argv);
- break;
- case TOKEN_MULTIPLE:
- rv = cmd_matcher_match_multiple(matcher, word_token,
- &keyword_argc, keyword_argv);
- break;
- case TOKEN_KEYWORD:
- assert(!"Keywords should never be nested.");
- break;
- }
-
- if (MATCHER_ERROR(rv))
- return rv;
-
- if (matcher->word_index > matcher->index)
- return MATCHER_OK;
- }
- }
- /* not reached */
-}
-
-static enum matcher_rv
-cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
- struct cmd_token *token,
- int *argc, const char **argv,
- vector keyword_args_vector)
-{
- unsigned int i, j;
- const char **keyword_args;
- vector keyword_vector;
- struct cmd_token *word_token;
- const char *arg;
- enum matcher_rv rv;
-
- rv = MATCHER_OK;
-
- if (keyword_args_vector == NULL)
- return rv;
-
- for (i = 0; i < vector_active(token->keyword); i++)
- {
- keyword_vector = vector_slot(token->keyword, i);
- keyword_args = vector_lookup(keyword_args_vector, i);
-
- if (vector_active(keyword_vector) == 1)
- {
- /* this is a keyword without arguments */
- if (keyword_args)
- {
- word_token = vector_slot(keyword_vector, 0);
- arg = word_token->cmd;
- XFREE (MTYPE_TMP, keyword_args);
- }
- else
- {
- arg = NULL;
- }
-
- if (push_argument(argc, argv, arg))
- rv = MATCHER_EXCEED_ARGC_MAX;
- }
- else
- {
- /* this is a keyword with arguments */
- if (keyword_args)
- {
- /* the keyword was present, so just fill in the arguments */
- for (j = 0; keyword_args[j] != (void*)-1; j++)
- if (push_argument(argc, argv, keyword_args[j]))
- rv = MATCHER_EXCEED_ARGC_MAX;
- XFREE(MTYPE_TMP, keyword_args);
- }
- else
- {
- /* the keyword was not present, insert NULL for the arguments
- * the keyword would have taken. */
- for (j = 1; j < vector_active(keyword_vector); j++)
- {
- word_token = vector_slot(keyword_vector, j);
- if ((word_token->type == TOKEN_TERMINAL
- && TERMINAL_RECORD (word_token->terminal))
- || word_token->type == TOKEN_MULTIPLE)
- {
- if (push_argument(argc, argv, NULL))
- rv = MATCHER_EXCEED_ARGC_MAX;
- }
- }
- }
- }
- }
- vector_free(keyword_args_vector);
- return rv;
-}
-
-static enum matcher_rv
-cmd_matcher_match_keyword(struct cmd_matcher *matcher,
- struct cmd_token *token,
- int *argc, const char **argv)
-{
- vector keyword_args_vector;
- enum matcher_rv reader_rv;
- enum matcher_rv builder_rv;
-
- assert(token->type == TOKEN_KEYWORD);
-
- if (argc && argv)
- keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
- else
- keyword_args_vector = NULL;
-
- reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
- builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
- argv, keyword_args_vector);
- /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
-
- if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
- return builder_rv;
-
- return reader_rv;
-}
-
-static void
-cmd_matcher_init(struct cmd_matcher *matcher,
- struct cmd_element *cmd,
- enum filter_type filter,
- vector vline,
- unsigned int index,
- enum match_type *match_type,
- vector *match)
-{
- memset(matcher, 0, sizeof(*matcher));
-
- matcher->cmd = cmd;
- matcher->filter = filter;
- matcher->vline = vline;
- matcher->index = index;
-
- matcher->match_type = match_type;
- if (matcher->match_type)
- *matcher->match_type = no_match;
- matcher->match = match;
-
- matcher->word_index = 0;
-}
-
-static enum matcher_rv
-cmd_element_match(struct cmd_element *cmd_element,
- enum filter_type filter,
- vector vline,
- unsigned int index,
- enum match_type *match_type,
- vector *match,
- int *argc,
- const char **argv)
-{
- struct cmd_matcher matcher;
- unsigned int token_index;
- enum matcher_rv rv = MATCHER_OK;
-
- cmd_matcher_init(&matcher, cmd_element, filter,
- vline, index, match_type, match);
-
- if (argc != NULL)
- *argc = 0;
-
- for (token_index = 0;
- token_index < vector_active(cmd_element->tokens);
- token_index++)
- {
- struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
-
- switch (token->type)
- {
- case TOKEN_TERMINAL:
- rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
- break;
- case TOKEN_MULTIPLE:
- rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
- break;
- case TOKEN_KEYWORD:
- rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
- }
-
- if (MATCHER_ERROR(rv))
- return rv;
-
- if (matcher.word_index > index)
- return MATCHER_OK;
- }
-
- /* return MATCHER_COMPLETE if all words were consumed */
- if (matcher.word_index >= vector_active(vline))
- return MATCHER_COMPLETE;
-
- /* return MATCHER_COMPLETE also if only an empty word is left. */
- if (matcher.word_index == vector_active(vline) - 1
- && (!vector_slot(vline, matcher.word_index)
- || !strlen((char*)vector_slot(vline, matcher.word_index))))
- return MATCHER_COMPLETE;
-
- return MATCHER_NO_MATCH; /* command is too long to match */
-}
-
-/**
- * Filter a given vector of commands against a given commandline and
- * calculate possible completions.
- *
- * @param commands A vector of struct cmd_element*. Commands that don't
- * match against the given command line will be overwritten
- * with NULL in that vector.
- * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
- * determines how incomplete commands are handled, compare with
- * cmd_word_match for details.
- * @param vline A vector of char* containing the tokenized commandline.
- * @param index Only match up to the given token of the commandline.
- * @param match_type Record the type of the best match here.
- * @param matches Record the matches here. For each cmd_element in the commands
- * vector, a match vector will be created in the matches vector.
- * That vector will contain all struct command_token* of the
- * cmd_element which matched against the given vline at the given
- * index.
- * @return A code specifying if an error occured. If all went right, it's
- * CMD_SUCCESS.
- */
-static int
-cmd_vector_filter(vector commands,
- enum filter_type filter,
- vector vline,
- unsigned int index,
- enum match_type *match_type,
- vector *matches)
-{
- unsigned int i;
- struct cmd_element *cmd_element;
- enum match_type best_match;
- enum match_type element_match;
- enum matcher_rv matcher_rv;
-
- best_match = no_match;
- *matches = vector_init(VECTOR_MIN_SIZE);
-
- for (i = 0; i < vector_active (commands); i++)
- if ((cmd_element = vector_slot (commands, i)) != NULL)
- {
- vector_set_index(*matches, i, NULL);
- matcher_rv = cmd_element_match(cmd_element, filter,
- vline, index,
- &element_match,
- (vector*)&vector_slot(*matches, i),
- NULL, NULL);
- if (MATCHER_ERROR(matcher_rv))
- {
- vector_slot(commands, i) = NULL;
- if (matcher_rv == MATCHER_AMBIGUOUS)
- return CMD_ERR_AMBIGUOUS;
- if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
- return CMD_ERR_EXEED_ARGC_MAX;
- }
- else if (element_match > best_match)
- {
- best_match = element_match;
- }
- }
- *match_type = best_match;
- return CMD_SUCCESS;
-}
-
/**
- * Check whether a given commandline is complete if used for a specific
- * cmd_element.
- *
- * @param cmd_element A cmd_element against which the commandline should be
- * checked.
- * @param vline The tokenized commandline.
- * @return 1 if the given commandline is complete, 0 otherwise.
+ * Compare function for cmd_token.
+ * Used with qsort to sort command completions.
*/
static int
-cmd_is_complete(struct cmd_element *cmd_element,
- vector vline)
+compare_completions (const void *fst, const void *snd)
{
- enum matcher_rv rv;
-
- rv = cmd_element_match(cmd_element,
- FILTER_RELAXED,
- vline, -1,
- NULL, NULL,
- NULL, NULL);
- return (rv == MATCHER_COMPLETE);
+ struct cmd_token *first = *(struct cmd_token **) fst,
+ *secnd = *(struct cmd_token **) snd;
+ return strcmp (first->text, secnd->text);
}
/**
- * Parse a given commandline and construct a list of arguments for the
- * given command_element.
+ * Takes a list of completions returned by command_complete,
+ * dedeuplicates them based on both text and description,
+ * sorts them, and returns them as a vector.
*
- * @param cmd_element The cmd_element for which we want to construct arguments.
- * @param vline The tokenized commandline.
- * @param argc Where to store the argument count.
- * @param argv Where to store the argument list. Should be at least
- * CMD_ARGC_MAX elements long.
- * @return CMD_SUCCESS if everything went alright, an error otherwise.
+ * @param completions linked list of cmd_token
+ * @return deduplicated and sorted vector with
*/
-static int
-cmd_parse(struct cmd_element *cmd_element,
- vector vline,
- int *argc, const char **argv)
+static vector
+completions_to_vec (struct list *completions)
{
- enum matcher_rv rv = cmd_element_match(cmd_element,
- FILTER_RELAXED,
- vline, -1,
- NULL, NULL,
- argc, argv);
- switch (rv)
- {
- case MATCHER_COMPLETE:
- return CMD_SUCCESS;
-
- case MATCHER_NO_MATCH:
- return CMD_ERR_NO_MATCH;
-
- case MATCHER_AMBIGUOUS:
- return CMD_ERR_AMBIGUOUS;
+ vector comps = vector_init (VECTOR_MIN_SIZE);
- case MATCHER_EXCEED_ARGC_MAX:
- return CMD_ERR_EXEED_ARGC_MAX;
+ struct listnode *ln;
+ struct cmd_token *token, *cr = NULL;
+ unsigned int i, exists;
+ for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
+ {
+ if (token->type == END_TKN && (cr = token))
+ continue;
- default:
- return CMD_ERR_INCOMPLETE;
+ // linear search for token in completions vector
+ exists = 0;
+ for (i = 0; i < vector_active (comps) && !exists; i++)
+ {
+ struct cmd_token *curr = vector_slot (comps, i);
+ exists = !strcmp (curr->text, token->text) &&
+ !strcmp (curr->desc, token->desc);
}
-}
-/* Check ambiguous match */
-static int
-is_cmd_ambiguous (vector cmd_vector,
- const char *command,
- vector matches,
- enum match_type type)
-{
- unsigned int i;
- unsigned int j;
- const char *str = NULL;
- const char *matched = NULL;
- vector match_vector;
- struct cmd_token *cmd_token;
-
- if (command == NULL)
- command = "";
-
- for (i = 0; i < vector_active (matches); i++)
- if ((match_vector = vector_slot (matches, i)) != NULL)
- {
- int match = 0;
-
- for (j = 0; j < vector_active (match_vector); j++)
- if ((cmd_token = vector_slot (match_vector, j)) != NULL)
- {
- enum match_type ret;
-
- assert(cmd_token->type == TOKEN_TERMINAL);
- if (cmd_token->type != TOKEN_TERMINAL)
- continue;
-
- str = cmd_token->cmd;
-
- switch (type)
- {
- case exact_match:
- if (!TERMINAL_RECORD (cmd_token->terminal)
- && strcmp (command, str) == 0)
- match++;
- break;
- case partly_match:
- if (!TERMINAL_RECORD (cmd_token->terminal)
- && strncmp (command, str, strlen (command)) == 0)
- {
- if (matched && strcmp (matched, str) != 0)
- return 1; /* There is ambiguous match. */
- else
- matched = str;
- match++;
- }
- break;
- case range_match:
- if (cmd_range_match (str, command))
- {
- if (matched && strcmp (matched, str) != 0)
- return 1;
- else
- matched = str;
- match++;
- }
- break;
-#ifdef HAVE_IPV6
- case ipv6_match:
- if (cmd_token->terminal == TERMINAL_IPV6)
- match++;
- break;
- case ipv6_prefix_match:
- if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
- {
- if (ret == partly_match)
- return 2; /* There is incomplete match. */
-
- match++;
- }
- break;
-#endif /* HAVE_IPV6 */
- case ipv4_match:
- if (cmd_token->terminal == TERMINAL_IPV4)
- match++;
- break;
- case ipv4_prefix_match:
- if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
- {
- if (ret == partly_match)
- return 2; /* There is incomplete match. */
-
- match++;
- }
- break;
- case extend_match:
- if (TERMINAL_RECORD (cmd_token->terminal))
- match++;
- break;
- case no_match:
- default:
- break;
- }
- }
- if (!match)
- vector_slot (cmd_vector, i) = NULL;
- }
- return 0;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-static const char *
-cmd_entry_function (const char *src, struct cmd_token *token)
-{
- const char *dst = token->cmd;
-
- /* Skip variable arguments. */
- if (TERMINAL_RECORD (token->terminal))
- return NULL;
-
- /* In case of 'command \t', given src is NULL string. */
- if (src == NULL)
- return dst;
-
- /* Matched with input string. */
- if (strncmp (src, dst, strlen (src)) == 0)
- return dst;
-
- return NULL;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-/* 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, struct cmd_token *token)
-{
- const char *dst = token->cmd;
-
- switch (token->terminal)
- {
- 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;
+ if (!exists)
+ vector_set (comps, token);
+ }
- default:
- assert(0);
- return NULL;
- }
-}
+ // sort completions
+ qsort (comps->index,
+ vector_active (comps),
+ sizeof (void *),
+ &compare_completions);
-/**
- * Check whether a string is already present in a vector of strings.
- * @param v A vector of char*.
- * @param str A char*.
- * @return 0 if str is already present in the vector, 1 otherwise.
- */
-static int
-cmd_unique_string (vector v, const char *str)
-{
- unsigned int i;
- char *match;
+ // make <cr> the first element, if it is present
+ if (cr)
+ {
+ vector_set_index (comps, vector_active (comps), NULL);
+ memmove (comps->index + 1, comps->index, (comps->alloced - 1) * sizeof (void *));
+ vector_set_index (comps, 0, cr);
+ }
- for (i = 0; i < vector_active (v); i++)
- if ((match = vector_slot (v, i)) != NULL)
- if (strcmp (match, str) == 0)
- return 0;
- return 1;
+ return comps;
}
-
/**
- * Check whether a struct cmd_token matching a given string is already
- * present in a vector of struct cmd_token.
- * @param v A vector of struct cmd_token*.
- * @param str A char* which should be searched for.
- * @return 0 if there is a struct cmd_token* with its cmd matching str,
- * 1 otherwise.
+ * Generates a vector of cmd_token representing possible completions
+ * on the current input.
+ *
+ * @param vline the vectorized input line
+ * @param vty the vty with the node to match on
+ * @param status pointer to matcher status code
+ * @return vector of struct cmd_token * with possible completions
*/
-static int
-desc_unique_string (vector v, const char *str)
-{
- unsigned int i;
- struct cmd_token *token;
-
- for (i = 0; i < vector_active (v); i++)
- if ((token = vector_slot (v, i)) != NULL)
- if (strcmp (token->cmd, str) == 0)
- return 0;
- return 1;
-}
-
-static int
-cmd_try_do_shortcut (enum node_type node, char* first_word) {
- if ( first_word != NULL &&
- node != AUTH_NODE &&
- node != VIEW_NODE &&
- node != AUTH_ENABLE_NODE &&
- node != ENABLE_NODE &&
- 0 == strcmp( "do", first_word ) )
- return 1;
- return 0;
-}
-
-static void
-cmd_matches_free(vector *matches)
-{
- unsigned int i;
- vector cmd_matches;
-
- for (i = 0; i < vector_active(*matches); i++)
- if ((cmd_matches = vector_slot(*matches, i)) != NULL)
- vector_free(cmd_matches);
- vector_free(*matches);
- *matches = NULL;
-}
-
-static int
-cmd_describe_cmp(const void *a, const void *b)
-{
- const struct cmd_token *first = *(struct cmd_token * const *)a;
- const struct cmd_token *second = *(struct cmd_token * const *)b;
-
- return strcmp(first->cmd, second->cmd);
-}
-
-static void
-cmd_describe_sort(vector matchvec)
-{
- qsort(matchvec->index, vector_active(matchvec),
- sizeof(void*), cmd_describe_cmp);
-}
-
-/* '?' describe command support. */
static vector
-cmd_describe_command_real (vector vline, struct vty *vty, int *status)
+cmd_complete_command_real (vector vline, struct vty *vty, int *status)
{
- unsigned int i;
- vector cmd_vector;
-#define INIT_MATCHVEC_SIZE 10
- vector matchvec;
- struct cmd_element *cmd_element;
- unsigned int index;
- int ret;
- enum match_type match;
- char *command = NULL;
- vector matches = NULL;
- vector match_vector;
- uint32_t command_found = 0;
- const char *last_word;
-
- /* Set index. */
- if (vector_active (vline) == 0)
- {
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
-
- index = vector_active (vline) - 1;
-
- /* Make copy vector of current node's command vector. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
-
- /* Prepare match vector */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
-
- /* Filter commands and build a list how they could possibly continue. */
- for (i = 0; i <= index; i++)
- {
- command = vector_slot (vline, i);
-
- if (matches)
- cmd_matches_free(&matches);
-
- ret = cmd_vector_filter(cmd_vector,
- FILTER_RELAXED,
- vline, i,
- &match,
- &matches);
-
- if (ret != CMD_SUCCESS)
- {
- vector_free (cmd_vector);
- vector_free (matchvec);
- cmd_matches_free(&matches);
- *status = ret;
- return NULL;
- }
-
- /* The last match may well be ambigious, so break here */
- if (i == index)
- break;
-
- if (match == vararg_match)
- {
- /* We found a vararg match - so we can throw out the current matches here
- * and don't need to continue checking the command input */
- unsigned int j, k;
-
- for (j = 0; j < vector_active (matches); j++)
- if ((match_vector = vector_slot (matches, j)) != NULL)
- for (k = 0; k < vector_active (match_vector); k++)
- {
- struct cmd_token *token = vector_slot (match_vector, k);
- vector_set (matchvec, token);
- }
-
- *status = CMD_SUCCESS;
- vector_set(matchvec, &token_cr);
- vector_free (cmd_vector);
- cmd_matches_free(&matches);
- cmd_describe_sort(matchvec);
- return matchvec;
- }
-
- ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
- if (ret == 1)
- {
- vector_free (cmd_vector);
- vector_free (matchvec);
- cmd_matches_free(&matches);
- *status = CMD_ERR_AMBIGUOUS;
- return NULL;
- }
- else if (ret == 2)
- {
- vector_free (cmd_vector);
- vector_free (matchvec);
- cmd_matches_free(&matches);
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
- }
-
- /* Make description vector. */
- for (i = 0; i < vector_active (matches); i++) {
- if ((cmd_element = vector_slot (cmd_vector, i)) != NULL &&
- !(cmd_element->attr == CMD_ATTR_DEPRECATED ||
- cmd_element->attr == CMD_ATTR_HIDDEN))
- {
- unsigned int j;
- vector vline_trimmed;
-
- command_found++;
- last_word = vector_slot(vline, vector_active(vline) - 1);
- if (last_word == NULL || !strlen(last_word))
- {
- vline_trimmed = vector_copy(vline);
- vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
-
- if (cmd_is_complete(cmd_element, vline_trimmed)
- && desc_unique_string(matchvec, command_cr))
- {
- if (match != vararg_match)
- vector_set(matchvec, &token_cr);
- }
-
- vector_free(vline_trimmed);
- }
+ struct list *completions;
+ struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
- match_vector = vector_slot (matches, i);
- if (match_vector)
- for (j = 0; j < vector_active(match_vector); j++)
- {
- struct cmd_token *token = vector_slot(match_vector, j);
- const char *string;
+ enum matcher_rv rv = command_complete (cmdgraph, vline, &completions);
- string = cmd_entry_function_desc(command, token);
- if (string && desc_unique_string(matchvec, string))
- vector_set(matchvec, token);
- }
- }
- }
-
- /*
- * We can get into this situation when the command is complete
- * but the last part of the command is an optional piece of
- * cli.
- */
- last_word = vector_slot(vline, vector_active(vline) - 1);
- if (command_found == 0 && (last_word == NULL || !strlen(last_word))) {
- vector_set(matchvec, &token_cr);
+ if (MATCHER_ERROR(rv))
+ {
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
}
- vector_free (cmd_vector);
- cmd_matches_free(&matches);
+ vector comps = completions_to_vec (completions);
+ list_delete (completions);
- if (vector_slot (matchvec, 0) == NULL)
- {
- vector_free (matchvec);
+ // set status code appropriately
+ switch (vector_active (comps))
+ {
+ case 0:
*status = CMD_ERR_NO_MATCH;
- return NULL;
- }
+ break;
+ case 1:
+ *status = CMD_COMPLETE_FULL_MATCH;
+ break;
+ default:
+ *status = CMD_COMPLETE_LIST_MATCH;
+ }
- *status = CMD_SUCCESS;
- cmd_describe_sort(matchvec);
- return matchvec;
+ return comps;
}
vector
@@ -2260,291 +627,93 @@ cmd_describe_command (vector vline, struct vty *vty, int *status)
shifted_vline = vector_init (vector_count(vline));
/* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
- {
- vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
- }
+ for (index = 1; index < vector_active (vline); index++)
+ {
+ vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
+ }
- ret = cmd_describe_command_real (shifted_vline, vty, status);
+ ret = cmd_complete_command_real (shifted_vline, vty, status);
vector_free(shifted_vline);
vty->node = onode;
return ret;
}
-
- return cmd_describe_command_real (vline, vty, status);
+ return cmd_complete_command_real (vline, vty, status);
}
+/**
+ * Generate possible tab-completions for the given input. This function only
+ * returns results that would result in a valid command if used as Readline
+ * completions (as is the case in vtysh). For instance, if the passed vline ends
+ * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
+ *
+ * @param vline vectorized input line
+ * @param vty the vty
+ * @param status location to store matcher status code in
+ * @return set of valid strings for use with Readline as tab-completions.
+ */
-/* Check LCD of matched command. */
-static int
-cmd_lcd (char **matched)
-{
- int i;
- int j;
- int lcd = -1;
- char *s1, *s2;
- char c1, c2;
-
- if (matched[0] == NULL || matched[1] == NULL)
- return 0;
-
- for (i = 1; matched[i] != NULL; i++)
- {
- s1 = matched[i - 1];
- s2 = matched[i];
-
- for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
- if (c1 != c2)
- break;
-
- if (lcd < 0)
- lcd = j;
- else
- {
- if (lcd > j)
- lcd = j;
- }
- }
- return lcd;
-}
-
-static int
-cmd_complete_cmp(const void *a, const void *b)
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
{
- const char *first = *(char * const *)a;
- const char *second = *(char * const *)b;
-
- if (!first)
- {
- if (!second)
- return 0;
- return 1;
- }
- if (!second)
- return -1;
-
- return strcmp(first, second);
-}
+ char **ret = NULL;
+ int original_node = vty->node;
+ vector input_line = vector_init (vector_count (vline));
-static void
-cmd_complete_sort(vector matchvec)
-{
- qsort(matchvec->index, vector_active(matchvec),
- sizeof(void*), cmd_complete_cmp);
-}
+ // if the first token is 'do' we'll want to execute the command in the enable node
+ int do_shortcut = cmd_try_do_shortcut (vty->node, vector_slot (vline, 0));
+ vty->node = do_shortcut ? ENABLE_NODE : original_node;
-/* Command line completion support. */
-static char **
-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));
-#define INIT_MATCHVEC_SIZE 10
- vector matchvec;
- unsigned int index;
- char **match_str;
- struct cmd_token *token;
- char *command;
- int lcd;
- vector matches = NULL;
- vector match_vector;
+ // construct the input line we'll be matching on
+ unsigned int offset = (do_shortcut) ? 1 : 0;
+ for (unsigned index = 0; index + offset < vector_active (vline); index++)
+ vector_set_index (input_line, index + offset, vector_lookup (vline, index));
- if (vector_active (vline) == 0)
- {
- vector_free (cmd_vector);
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
- else
- index = vector_active (vline) - 1;
+ // get token completions -- this is a copying operation
+ vector comps = NULL, initial_comps;
+ initial_comps = cmd_complete_command_real (input_line, vty, status);
- /* First, filter by command string */
- for (i = 0; i <= index; i++)
+ if (!MATCHER_ERROR (*status))
+ {
+ assert (initial_comps);
+ // filter out everything that is not suitable for a tab-completion
+ comps = vector_init (VECTOR_MIN_SIZE);
+ for (unsigned int i = 0; i < vector_active(initial_comps); i++)
{
- command = vector_slot (vline, i);
- enum match_type match;
- int ret;
-
- if (matches)
- cmd_matches_free(&matches);
-
- /* First try completion match, if there is exactly match return 1 */
- ret = cmd_vector_filter(cmd_vector,
- FILTER_RELAXED,
- vline, i,
- &match,
- &matches);
-
- if (ret != CMD_SUCCESS)
- {
- vector_free(cmd_vector);
- cmd_matches_free(&matches);
- *status = ret;
- return NULL;
- }
-
- /* Break here - the completion mustn't be checked to be non-ambiguous */
- if (i == index)
- break;
-
- /* If there is exact match then filter ambiguous match else check
- ambiguousness. */
- ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
- if (ret == 1)
- {
- vector_free (cmd_vector);
- cmd_matches_free(&matches);
- *status = CMD_ERR_AMBIGUOUS;
- return NULL;
- }
+ struct cmd_token *token = vector_slot (initial_comps, i);
+ if (token->type == WORD_TKN)
+ vector_set (comps, token);
}
-
- /* Prepare match vector. */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
+ vector_free (initial_comps);
- /* Build the possible list of continuations into a list of completions */
- for (i = 0; i < vector_active (matches); i++)
- if ((match_vector = vector_slot (matches, i)))
+ // copy completions text into an array of char*
+ ret = XMALLOC (MTYPE_TMP, (vector_active (comps)+1) * sizeof (char *));
+ unsigned int i;
+ for (i = 0; i < vector_active (comps); i++)
{
- const char *string;
- unsigned int j;
-
- for (j = 0; j < vector_active (match_vector); j++)
- if ((token = vector_slot (match_vector, j)))
- {
- 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 */));
- }
+ struct cmd_token *token = vector_slot (comps, i);
+ ret[i] = XSTRDUP (MTYPE_TMP, token->text);
+ vector_unset (comps, i);
}
+ // set the last element to NULL, because this array is used in
+ // a Readline completion_generator function which expects NULL
+ // as a sentinel value
+ ret[i] = NULL;
+ vector_free (comps);
+ comps = NULL;
+ }
- /* We don't need cmd_vector any more. */
- vector_free (cmd_vector);
- cmd_matches_free(&matches);
-
- /* No matched command */
- if (vector_slot (matchvec, 0) == NULL)
- {
- vector_free (matchvec);
-
- /* In case of 'command \t' pattern. Do you need '?' command at
- the end of the line. */
- if (vector_slot (vline, index) == '\0')
- *status = CMD_ERR_NOTHING_TODO;
- else
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
-
- /* Only one matched */
- if (vector_slot (matchvec, 1) == NULL)
- {
- size_t index_size = matchvec->alloced * sizeof (void *);
- match_str = XMALLOC (MTYPE_TMP, index_size);
- memcpy (match_str, matchvec->index, index_size);
- vector_free (matchvec);
-
- *status = CMD_COMPLETE_FULL_MATCH;
- return match_str;
- }
- /* Make it sure last element is NULL. */
- vector_set (matchvec, NULL);
-
- /* Check LCD of matched strings. */
- if (vector_slot (vline, index) != NULL)
- {
- lcd = cmd_lcd ((char **) matchvec->index);
-
- if (lcd)
- {
- int len = strlen (vector_slot (vline, index));
-
- if (len < lcd)
- {
- char *lcdstr;
-
- lcdstr = (islib != 0 ?
- XMALLOC (MTYPE_TMP, lcd + 1) :
- malloc(lcd + 1));
- memcpy (lcdstr, matchvec->index[0], lcd);
- lcdstr[lcd] = '\0';
-
- /* Free matchvec. */
- for (i = 0; i < vector_active (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. */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
- vector_set (matchvec, lcdstr);
-
- size_t index_size = matchvec->alloced * sizeof (void *);
- match_str = XMALLOC (MTYPE_TMP, index_size);
- memcpy (match_str, matchvec->index, index_size);
- vector_free (matchvec);
-
- *status = CMD_COMPLETE_MATCH;
- return match_str;
- }
- }
- }
-
- match_str = (char **) matchvec->index;
- cmd_complete_sort(matchvec);
- vector_only_wrapper_free (matchvec);
- *status = CMD_COMPLETE_LIST_MATCH;
- return match_str;
-}
-
-char **
-cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
-{
- char **ret;
-
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
- {
- enum node_type onode;
- vector shifted_vline;
- unsigned int index;
-
- onode = vty->node;
- vty->node = ENABLE_NODE;
- /* We can try it on enable node, cos' the vty is authenticated */
-
- shifted_vline = vector_init (vector_count(vline));
- /* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
- {
- vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
- }
-
- ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
+ // comps should always be null here
+ assert (!comps);
- vector_free(shifted_vline);
- vty->node = onode;
- return ret;
- }
+ // free the adjusted input line
+ vector_free (input_line);
- return cmd_complete_command_real (vline, vty, status, islib);
-}
+ // reset vty->node to its original value
+ vty->node = original_node;
-char **
-cmd_complete_command (vector vline, struct vty *vty, int *status)
-{
- return cmd_complete_command_lib (vline, vty, status, 0);
+ return ret;
}
/* return parent node */
@@ -2563,8 +732,8 @@ node_parent ( enum node_type node )
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
- case BGP_VNC_NVE_GROUP_NODE:
- case BGP_VNC_L2_GROUP_NODE:
+ case BGP_VNC_NVE_GROUP_NODE:
+ case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
@@ -2601,109 +770,55 @@ node_parent ( enum node_type node )
/* Execute command by argument vline vector. */
static int
cmd_execute_command_real (vector vline,
- enum filter_type filter,
- struct vty *vty,
- struct cmd_element **cmd)
+ enum filter_type filter,
+ struct vty *vty,
+ const struct cmd_element **cmd)
{
- unsigned int i;
- unsigned int index;
- vector cmd_vector;
- struct cmd_element *cmd_element;
- struct cmd_element *matched_element;
- unsigned int matched_count, incomplete_count;
- int argc;
- const char *argv[CMD_ARGC_MAX];
- enum match_type match = 0;
- char *command;
- int ret;
- vector matches;
-
- /* Make copy of command elements. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
-
- for (index = 0; index < vector_active (vline); index++)
- {
- command = vector_slot (vline, index);
- ret = cmd_vector_filter(cmd_vector,
- filter,
- vline, index,
- &match,
- &matches);
-
- if (ret != CMD_SUCCESS)
- {
- cmd_matches_free(&matches);
- return ret;
- }
-
- if (match == vararg_match)
- {
- cmd_matches_free(&matches);
- break;
- }
-
- ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
- cmd_matches_free(&matches);
-
- if (ret == 1)
- {
- vector_free(cmd_vector);
- return CMD_ERR_AMBIGUOUS;
- }
- else if (ret == 2)
- {
- vector_free(cmd_vector);
- return CMD_ERR_NO_MATCH;
- }
- }
-
- /* Check matched count. */
- matched_element = NULL;
- matched_count = 0;
- incomplete_count = 0;
+ struct list *argv_list;
+ enum matcher_rv status;
+ const struct cmd_element *matched_element = NULL;
- for (i = 0; i < vector_active (cmd_vector); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)))
- {
- if (cmd_is_complete(cmd_element, vline))
- {
- matched_element = cmd_element;
- matched_count++;
- }
- else
- {
- incomplete_count++;
- }
- }
+ struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
+ status = command_match (cmdgraph, vline, &argv_list, &matched_element);
- /* Finish of using cmd_vector. */
- vector_free (cmd_vector);
+ if (cmd)
+ *cmd = matched_element;
- /* To execute command, matched_count must be 1. */
- if (matched_count == 0)
+ // if matcher error, return corresponding CMD_ERR
+ if (MATCHER_ERROR(status))
+ {
+ switch (status)
{
- if (incomplete_count)
- return CMD_ERR_INCOMPLETE;
- else
- return CMD_ERR_NO_MATCH;
+ case MATCHER_INCOMPLETE:
+ return CMD_ERR_INCOMPLETE;
+ case MATCHER_AMBIGUOUS:
+ return CMD_ERR_AMBIGUOUS;
+ default:
+ return CMD_ERR_NO_MATCH;
}
+ }
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
-
- ret = cmd_parse(matched_element, vline, &argc, argv);
- if (ret != CMD_SUCCESS)
- return ret;
+ // build argv array from argv list
+ struct cmd_token **argv = XMALLOC (MTYPE_TMP, argv_list->count * sizeof (struct cmd_token *));
+ struct listnode *ln;
+ struct cmd_token *token;
+ unsigned int i = 0;
+ for (ALL_LIST_ELEMENTS_RO(argv_list,ln,token))
+ argv[i++] = token;
- /* For vtysh execution. */
- if (cmd)
- *cmd = matched_element;
+ int argc = argv_list->count;
+ int ret;
if (matched_element->daemon)
- return CMD_SUCCESS_DAEMON;
+ ret = CMD_SUCCESS_DAEMON;
+ else
+ ret = matched_element->func (matched_element, vty, argc, argv);
- /* Execute matched command. */
- return (*matched_element->func) (matched_element, vty, argc, argv);
+ // delete list and cmd_token's in it
+ list_delete (argv_list);
+ XFREE (MTYPE_TMP, argv);
+
+ return ret;
}
/**
@@ -2722,14 +837,16 @@ cmd_execute_command_real (vector vline,
* as to why no command could be executed.
*/
int
-cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- int vtysh) {
- int ret, saved_ret, tried = 0;
+cmd_execute_command (vector vline, struct vty *vty,
+ const struct cmd_element **cmd,
+ int vtysh)
+{
+ int ret, saved_ret = 0;
enum node_type onode, try_node;
onode = try_node = vty->node;
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
+ if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0)))
{
vector shifted_vline;
unsigned int index;
@@ -2739,10 +856,8 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
shifted_vline = vector_init (vector_count(vline));
/* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
- {
- vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
- }
+ for (index = 1; index < vector_active (vline); index++)
+ vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
@@ -2751,30 +866,27 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
return ret;
}
-
saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
if (vtysh)
return saved_ret;
- /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
- while ( ret != CMD_SUCCESS && ret != CMD_WARNING
- && vty->node > CONFIG_NODE )
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
{
- try_node = node_parent(try_node);
- vty->node = try_node;
- ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
- tried = 1;
- if (ret == CMD_SUCCESS || ret == CMD_WARNING)
- {
- /* succesfull command, leave the node as is */
- return ret;
- }
+ /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
+ while (vty->node > CONFIG_NODE)
+ {
+ try_node = node_parent(try_node);
+ vty->node = try_node;
+ ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
+ if (ret == CMD_SUCCESS || ret == CMD_WARNING)
+ return ret;
+ }
+ /* no command succeeded, reset the vty to the original node */
+ vty->node = onode;
}
- /* no command succeeded, reset the vty to the original node and
- return the error for this node */
- if ( tried )
- vty->node = onode;
+
+ /* return command status for original node */
return saved_ret;
}
@@ -2793,7 +905,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
*/
int
cmd_execute_command_strict (vector vline, struct vty *vty,
- struct cmd_element **cmd)
+ const struct cmd_element **cmd)
{
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
}
@@ -2811,7 +923,7 @@ cmd_execute_command_strict (vector vline, struct vty *vty,
* as to why no command could be executed.
*/
int
-command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
+command_config_read_one_line (struct vty *vty, const struct cmd_element **cmd, int use_daemon)
{
vector vline;
int saved_node;
@@ -2837,7 +949,7 @@ command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use
while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
!(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
- ret != CMD_SUCCESS &&
+ ret != CMD_SUCCESS &&
ret != CMD_WARNING &&
vty->node > CONFIG_NODE) {
vty->node = node_parent(vty->node);
@@ -2848,14 +960,16 @@ command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use
// stay at the same node
if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
!(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
- ret != CMD_SUCCESS &&
+ ret != CMD_SUCCESS &&
ret != CMD_WARNING)
{
- vty->node = saved_node;
- memcpy(vty->error_buf, vty->buf, VTY_BUFSIZ);
+ vty->node = saved_node;
}
}
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ memcpy (vty->error_buf, vty->buf, VTY_BUFSIZ);
+
cmd_free_strvec (vline);
return ret;
@@ -2871,13 +985,13 @@ config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
while (fgets (vty->buf, VTY_BUFSIZ, fp))
{
if (!error_ret)
- ++(*line_num);
+ ++(*line_num);
ret = command_config_read_one_line (vty, NULL, 0);
if (ret != CMD_SUCCESS && ret != CMD_WARNING &&
- ret != CMD_ERR_NOTHING_TODO)
- error_ret = ret;
+ ret != CMD_ERR_NOTHING_TODO)
+ error_ret = ret;
}
if (error_ret) {
@@ -2905,7 +1019,7 @@ DEFUN (config_terminal,
}
/* Enable command */
-DEFUN (enable,
+DEFUN (enable,
config_enable_cmd,
"enable",
"Turn on privileged mode command\n")
@@ -2921,7 +1035,7 @@ DEFUN (enable,
}
/* Disable command */
-DEFUN (disable,
+DEFUN (disable,
config_disable_cmd,
"disable",
"Turn off privileged mode command\n")
@@ -2942,9 +1056,9 @@ DEFUN (config_exit,
case VIEW_NODE:
case ENABLE_NODE:
if (vty_shell (vty))
- exit (0);
+ exit (0);
else
- vty->status = VTY_CLOSE;
+ vty->status = VTY_CLOSE;
break;
case CONFIG_NODE:
vty->node = ENABLE_NODE;
@@ -3007,12 +1121,16 @@ DEFUN (config_exit,
return CMD_SUCCESS;
}
-/* quit is alias of exit. */
-ALIAS (config_exit,
+/* ALIAS_FIXME */
+DEFUN (config_quit,
config_quit_cmd,
"quit",
"Exit current mode and down to previous mode\n")
-
+{
+ return config_exit (self, vty, argc, argv);
+}
+
+
/* End of configuration. */
DEFUN (config_end,
config_end_cmd,
@@ -3078,7 +1196,7 @@ DEFUN (show_version,
"Displays zebra version\n")
{
vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
- VTY_NEWLINE);
+ 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);
@@ -3092,8 +1210,8 @@ DEFUN (config_help,
"help",
"Description of the interactive help system\n")
{
- vty_out (vty,
- "Quagga VTY provides advanced help feature. When you need help,%s\
+ vty_out (vty,
+ "Quagga VTY provides advanced help feature. When you need help,%s\
anytime at the command line please press '?'.%s\
%s\
If nothing matches, the help list will be empty and you must backup%s\
@@ -3105,37 +1223,92 @@ argument.%s\
2. Partial help is provided when an abbreviated argument is entered%s\
and you want to know what arguments match the input%s\
(e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
return CMD_SUCCESS;
}
+static void
+permute (struct graph_node *start, struct vty *vty)
+{
+ static struct list *position = NULL;
+ if (!position) position = list_new ();
+
+ // recursive dfs
+ listnode_add (position, start);
+ for (unsigned int i = 0; i < vector_active (start->to); i++)
+ {
+ struct graph_node *gn = vector_slot (start->to, i);
+ struct cmd_token *tok = gn->data;
+ if (tok->attr == CMD_ATTR_HIDDEN ||
+ tok->attr == CMD_ATTR_DEPRECATED)
+ continue;
+ else if (tok->type == END_TKN || gn == start)
+ {
+ struct graph_node *gnn;
+ struct listnode *ln;
+ vty_out (vty, " ");
+ for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
+ {
+ struct cmd_token *tt = gnn->data;
+ if (tt->type < SELECTOR_TKN)
+ vty_out (vty, " %s", tt->text);
+ }
+ if (gn == start)
+ vty_out (vty, "...");
+ vty_out (vty, VTY_NEWLINE);
+ }
+ else
+ permute (gn, vty);
+ }
+ list_delete_node (position, listtail(position));
+}
+
/* Help display function for all node. */
DEFUN (config_list,
config_list_cmd,
- "list",
- "Print command list\n")
+ "list [permutations]",
+ "Print command list\n"
+ "Print all possible command permutations\n")
{
- unsigned int i;
- struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
- struct cmd_element *cmd;
-
- for (i = 0; i < vector_active (cnode->cmd_vector); i++)
- if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
- && !(cmd->attr == CMD_ATTR_DEPRECATED
- || cmd->attr == CMD_ATTR_HIDDEN))
- vty_out (vty, " %s%s", cmd->string,
- VTY_NEWLINE);
+ struct cmd_node *node = vector_slot (cmdvec, vty->node);
+
+ if ((strmatch (argv[0]->text, "list") && argc == 2) ||
+ (strmatch (argv[0]->text, "show") && argc == 3))
+ permute (vector_slot (node->cmdgraph->nodes, 0), vty);
+ else
+ {
+ /* loop over all commands at this node */
+ struct cmd_element *element = NULL;
+ for (unsigned int i = 0; i < vector_active(node->cmd_vector); i++)
+ if ((element = vector_slot (node->cmd_vector, i)) &&
+ element->attr != CMD_ATTR_DEPRECATED &&
+ element->attr != CMD_ATTR_HIDDEN)
+ vty_out (vty, " %s%s", element->string, VTY_NEWLINE);
+ }
return CMD_SUCCESS;
}
+DEFUN (show_commandtree,
+ show_commandtree_cmd,
+ "show commandtree [permutations]",
+ SHOW_STR
+ "Show command tree\n")
+{
+ return config_list (self, vty, argc, argv);
+}
+
/* Write current configuration into file. */
-DEFUN (config_write_file,
- config_write_file_cmd,
- "write file",
+
+DEFUN (config_write,
+ config_write_cmd,
+ "write [<file|memory|terminal>]",
"Write running configuration to memory, network, or terminal\n"
- "Write to configuration file\n")
+ "Write to configuration file\n"
+ "Write configuration currently in memory\n"
+ "Write configuration to terminal\n")
{
+ int idx_type = 1;
unsigned int i;
int fd;
struct cmd_node *node;
@@ -3146,6 +1319,37 @@ DEFUN (config_write_file,
struct vty *file_vty;
struct stat conf_stat;
+ // if command was 'write terminal', 'write memory' or 'show running-config'
+ if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal") ||
+ !strcmp(argv[idx_type]->text, "memory") ||
+ !strcmp(argv[0]->text, "show")))
+ {
+ if (vty->type == VTY_SHELL_SERV)
+ {
+ for (i = 0; i < vector_active (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ }
+ else
+ {
+ vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+ VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ for (i = 0; i < vector_active (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "end%s",VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+ }
+
if (host.noconfig)
return CMD_SUCCESS;
@@ -3153,13 +1357,13 @@ DEFUN (config_write_file,
if (host.config == NULL)
{
vty_out (vty, "Can't save to configuration file, using vtysh.%s",
- VTY_NEWLINE);
+ VTY_NEWLINE);
return CMD_WARNING;
}
/* Get filename. */
config_file = host.config;
-
+
config_file_sav =
XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
strcpy (config_file_sav, config_file);
@@ -3168,16 +1372,16 @@ DEFUN (config_write_file,
config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
sprintf (config_file_tmp, "%s.XXXXXX", config_file);
-
+
/* Open file to configuration write. */
fd = mkstemp (config_file_tmp);
if (fd < 0)
{
vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
- VTY_NEWLINE);
+ VTY_NEWLINE);
goto finished;
}
-
+
/* Make vty for configuration file. */
file_vty = vty_new ();
file_vty->wfd = fd;
@@ -3191,51 +1395,51 @@ DEFUN (config_write_file,
for (i = 0; i < vector_active (cmdvec); i++)
if ((node = vector_slot (cmdvec, i)) && node->func)
{
- if ((*node->func) (file_vty))
- vty_out (file_vty, "!\n");
+ if ((*node->func) (file_vty))
+ vty_out (file_vty, "!\n");
}
vty_close (file_vty);
if (stat(config_file, &conf_stat) >= 0)
{
if (unlink (config_file_sav) != 0)
- if (errno != ENOENT)
- {
- vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
- VTY_NEWLINE);
- goto finished;
- }
+ if (errno != ENOENT)
+ {
+ vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ goto finished;
+ }
if (link (config_file, config_file_sav) != 0)
- {
- vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
- VTY_NEWLINE);
- goto finished;
- }
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ goto finished;
+ }
sync ();
if (unlink (config_file) != 0)
- {
- vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
- VTY_NEWLINE);
- goto finished;
- }
+ {
+ vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ goto finished;
+ }
}
if (link (config_file_tmp, config_file) != 0)
{
vty_out (vty, "Can't save configuration file %s.%s", config_file,
- VTY_NEWLINE);
+ VTY_NEWLINE);
goto finished;
}
sync ();
-
+
if (chmod (config_file, CONFIGFILE_MASK) != 0)
{
- vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
- config_file, safe_strerror(errno), errno, VTY_NEWLINE);
+ vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
+ config_file, safe_strerror(errno), errno, VTY_NEWLINE);
goto finished;
}
vty_out (vty, "Configuration saved to %s%s", config_file,
- VTY_NEWLINE);
+ VTY_NEWLINE);
ret = CMD_SUCCESS;
finished:
@@ -3245,76 +1449,34 @@ finished:
return ret;
}
-ALIAS (config_write_file,
- config_write_cmd,
- "write",
- "Write running configuration to memory, network, or terminal\n")
-
-ALIAS (config_write_file,
- config_write_memory_cmd,
- "write memory",
- "Write running configuration to memory, network, or terminal\n"
- "Write configuration to the file (same as write file)\n")
+/* ALIAS_FIXME for 'write <terminal|memory>' */
+DEFUN (show_running_config,
+ show_running_config_cmd,
+ "show running-config",
+ SHOW_STR
+ "running configuration (same as write terminal/memory)\n")
+{
+ return config_write (self, vty, argc, argv);
+}
-ALIAS (config_write_file,
- copy_runningconfig_startupconfig_cmd,
- "copy running-config startup-config",
+/* ALIAS_FIXME for 'write file' */
+DEFUN (copy_runningconf_startupconf,
+ copy_runningconf_startupconf_cmd,
+ "copy running-config startup-config",
"Copy configuration\n"
"Copy running config to... \n"
"Copy running config to startup config (same as write file)\n")
-
-/* Write current configuration into the terminal. */
-DEFUN (config_write_terminal,
- config_write_terminal_cmd,
- "write terminal",
- "Write running configuration to memory, network, or terminal\n"
- "Write to terminal\n")
{
- unsigned int i;
- struct cmd_node *node;
-
- if (host.noconfig)
- return CMD_SUCCESS;
-
- if (vty->type == VTY_SHELL_SERV)
- {
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
- {
- if ((*node->func) (vty))
- vty_out (vty, "!%s", VTY_NEWLINE);
- }
- }
- else
- {
- vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
- VTY_NEWLINE);
- vty_out (vty, "!%s", VTY_NEWLINE);
-
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((node = vector_slot (cmdvec, i)) && node->func)
- {
- if ((*node->func) (vty))
- vty_out (vty, "!%s", VTY_NEWLINE);
- }
- vty_out (vty, "end%s",VTY_NEWLINE);
- }
- return CMD_SUCCESS;
+ return config_write (self, vty, argc, argv);
}
-
-/* Write current configuration into the terminal. */
-ALIAS (config_write_terminal,
- show_running_config_cmd,
- "show running-config",
- SHOW_STR
- "running configuration\n")
+/** -- **/
/* Write startup configuration into the terminal. */
DEFUN (show_startup_config,
show_startup_config_cmd,
"show startup-config",
SHOW_STR
- "Contentes of startup configuration\n")
+ "Contents of startup configuration\n")
{
char buf[BUFSIZ];
FILE *confp;
@@ -3328,7 +1490,7 @@ DEFUN (show_startup_config,
if (confp == NULL)
{
vty_out (vty, "Can't open configuration file [%s] due to '%s'%s",
- host.config, safe_strerror(errno), VTY_NEWLINE);
+ host.config, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
@@ -3337,7 +1499,7 @@ DEFUN (show_startup_config,
char *cp = buf;
while (*cp != '\r' && *cp != '\n' && *cp != '\0')
- cp++;
+ cp++;
*cp = '\0';
vty_out (vty, "%s%s", buf, VTY_NEWLINE);
@@ -3349,13 +1511,15 @@ DEFUN (show_startup_config,
}
/* Hostname configuration */
-DEFUN (config_hostname,
+DEFUN (config_hostname,
hostname_cmd,
"hostname WORD",
"Set system's network name\n"
"This system's network name\n")
{
- if (!isalpha((int) *argv[0]))
+ struct cmd_token *word = argv[1];
+
+ if (!isalpha((int) word->arg[0]))
{
vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -3363,12 +1527,12 @@ DEFUN (config_hostname,
if (host.name)
XFREE (MTYPE_HOST, host.name);
-
- host.name = XSTRDUP (MTYPE_HOST, argv[0]);
+
+ host.name = XSTRDUP (MTYPE_HOST, word->arg);
return CMD_SUCCESS;
}
-DEFUN (config_no_hostname,
+DEFUN (config_no_hostname,
no_hostname_cmd,
"no hostname [HOSTNAME]",
NO_STR
@@ -3382,43 +1546,30 @@ DEFUN (config_no_hostname,
}
/* VTY interface password set. */
-DEFUN (config_password, password_cmd,
- "password (8|) WORD",
+DEFUN (config_password,
+ password_cmd,
+ "password [(8-8)] WORD",
"Assign the terminal connection password\n"
"Specifies a HIDDEN password will follow\n"
- "dummy string \n"
- "The HIDDEN line password string\n")
+ "The password string\n")
{
- /* Argument check. */
- if (argc == 0)
- {
- vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (argc == 2)
- {
- if (*argv[0] == '8')
- {
- if (host.password)
- XFREE (MTYPE_HOST, host.password);
- host.password = NULL;
- if (host.password_encrypt)
- XFREE (MTYPE_HOST, host.password_encrypt);
- host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
- return CMD_SUCCESS;
- }
- else
- {
- vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
+ int idx_8 = 1;
+ int idx_word = 2;
+ if (argc == 3) // '8' was specified
+ {
+ if (host.password)
+ XFREE (MTYPE_HOST, host.password);
+ host.password = NULL;
+ if (host.password_encrypt)
+ XFREE (MTYPE_HOST, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
+ return CMD_SUCCESS;
+ }
- if (!isalnum ((int) *argv[0]))
+ if (!isalnum (argv[idx_8]->arg[0]))
{
- vty_out (vty,
- "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -3429,62 +1580,53 @@ DEFUN (config_password, password_cmd,
if (host.encrypt)
{
if (host.password_encrypt)
- XFREE (MTYPE_HOST, host.password_encrypt);
- host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
+ XFREE (MTYPE_HOST, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
}
else
- host.password = XSTRDUP (MTYPE_HOST, argv[0]);
+ host.password = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
return CMD_SUCCESS;
}
-ALIAS (config_password, password_text_cmd,
- "password LINE",
- "Assign the terminal connection password\n"
- "The UNENCRYPTED (cleartext) line password\n")
-
/* VTY enable password set. */
-DEFUN (config_enable_password, enable_password_cmd,
- "enable password (8|) WORD",
+DEFUN (config_enable_password,
+ enable_password_cmd,
+ "enable password [(8-8)] WORD",
"Modify enable password parameters\n"
"Assign the privileged level password\n"
"Specifies a HIDDEN password will follow\n"
- "dummy string \n"
"The HIDDEN 'enable' password string\n")
{
- /* Argument check. */
- if (argc == 0)
- {
- vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ int idx_8 = 2;
+ int idx_word = 3;
/* Crypt type is specified. */
- if (argc == 2)
+ if (argc == 4)
{
- if (*argv[0] == '8')
- {
- if (host.enable)
- XFREE (MTYPE_HOST, host.enable);
- host.enable = NULL;
-
- if (host.enable_encrypt)
- XFREE (MTYPE_HOST, host.enable_encrypt);
- host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
-
- return CMD_SUCCESS;
- }
+ if (argv[idx_8]->arg[0] == '8')
+ {
+ if (host.enable)
+ XFREE (MTYPE_HOST, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (MTYPE_HOST, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
+
+ return CMD_SUCCESS;
+ }
else
- {
- vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
- if (!isalnum ((int) *argv[0]))
+ if (!isalnum (argv[idx_8]->arg[0]))
{
- vty_out (vty,
- "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -3496,24 +1638,18 @@ DEFUN (config_enable_password, enable_password_cmd,
if (host.encrypt)
{
if (host.enable_encrypt)
- XFREE (MTYPE_HOST, host.enable_encrypt);
- host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
+ XFREE (MTYPE_HOST, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
}
else
- host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
+ host.enable = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
return CMD_SUCCESS;
}
-ALIAS (config_enable_password,
- enable_password_text_cmd,
- "enable password LINE",
- "Modify enable password parameters\n"
- "Assign the privileged level password\n"
- "The UNENCRYPTED (cleartext) 'enable' password\n")
-
/* VTY enable password delete. */
-DEFUN (no_config_enable_password, no_enable_password_cmd,
+DEFUN (no_config_enable_password,
+ no_enable_password_cmd,
"no enable password",
NO_STR
"Modify enable password parameters\n"
@@ -3529,7 +1665,7 @@ DEFUN (no_config_enable_password, no_enable_password_cmd,
return CMD_SUCCESS;
}
-
+
DEFUN (service_password_encrypt,
service_password_encrypt_cmd,
"service password-encryption",
@@ -3544,13 +1680,13 @@ DEFUN (service_password_encrypt,
if (host.password)
{
if (host.password_encrypt)
- XFREE (MTYPE_HOST, host.password_encrypt);
+ XFREE (MTYPE_HOST, host.password_encrypt);
host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
}
if (host.enable)
{
if (host.enable_encrypt)
- XFREE (MTYPE_HOST, host.enable_encrypt);
+ XFREE (MTYPE_HOST, host.enable_encrypt);
host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
}
@@ -3580,16 +1716,18 @@ DEFUN (no_service_password_encrypt,
return CMD_SUCCESS;
}
-DEFUN (config_terminal_length, config_terminal_length_cmd,
- "terminal length <0-512>",
+DEFUN (config_terminal_length,
+ config_terminal_length_cmd,
+ "terminal length (0-512)",
"Set terminal line parameters\n"
"Set number of lines on a screen\n"
"Number of lines on screen (0 for no pausing)\n")
{
+ int idx_number = 2;
int lines;
char *endptr = NULL;
- lines = strtol (argv[0], &endptr, 10);
+ lines = strtol (argv[idx_number]->arg, &endptr, 10);
if (lines < 0 || lines > 512 || *endptr != '\0')
{
vty_out (vty, "length is malformed%s", VTY_NEWLINE);
@@ -3600,7 +1738,8 @@ DEFUN (config_terminal_length, config_terminal_length_cmd,
return CMD_SUCCESS;
}
-DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
+DEFUN (config_terminal_no_length,
+ config_terminal_no_length_cmd,
"terminal no length",
"Set terminal line parameters\n"
NO_STR
@@ -3610,16 +1749,18 @@ DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
return CMD_SUCCESS;
}
-DEFUN (service_terminal_length, service_terminal_length_cmd,
- "service terminal-length <0-512>",
+DEFUN (service_terminal_length,
+ service_terminal_length_cmd,
+ "service terminal-length (0-512)",
"Set up miscellaneous service\n"
"System wide terminal length configuration\n"
"Number of lines of VTY (0 means no line control)\n")
{
+ int idx_number = 2;
int lines;
char *endptr = NULL;
- lines = strtol (argv[0], &endptr, 10);
+ lines = strtol (argv[idx_number]->arg, &endptr, 10);
if (lines < 0 || lines > 512 || *endptr != '\0')
{
vty_out (vty, "length is malformed%s", VTY_NEWLINE);
@@ -3630,8 +1771,9 @@ DEFUN (service_terminal_length, service_terminal_length_cmd,
return CMD_SUCCESS;
}
-DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
- "no service terminal-length [<0-512>]",
+DEFUN (no_service_terminal_length,
+ no_service_terminal_length_cmd,
+ "no service terminal-length [(0-512)]",
NO_STR
"Set up miscellaneous service\n"
"System wide terminal length configuration\n"
@@ -3642,15 +1784,15 @@ DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
}
DEFUN_HIDDEN (do_echo,
- echo_cmd,
- "echo .MESSAGE",
- "Echo a message back to the vty\n"
- "The message to echo\n")
+ echo_cmd,
+ "echo MESSAGE...",
+ "Echo a message back to the vty\n"
+ "The message to echo\n")
{
char *message;
- vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
- VTY_NEWLINE);
+ vty_out (vty, "%s%s", ((message = argv_concat (argv, argc, 1)) ? message : ""),
+ VTY_NEWLINE);
if (message)
XFREE(MTYPE_TMP, message);
return CMD_SUCCESS;
@@ -3658,18 +1800,20 @@ DEFUN_HIDDEN (do_echo,
DEFUN (config_logmsg,
config_logmsg_cmd,
- "logmsg "LOG_LEVELS" .MESSAGE",
+ "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
"Send a message to enabled logging destinations\n"
LOG_LEVEL_DESC
"The message to send\n")
{
+ int idx_log_level = 1;
+ int idx_message = 2;
int level;
char *message;
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+ if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
- zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
+ zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
if (message)
XFREE(MTYPE_TMP, message);
@@ -3689,8 +1833,8 @@ DEFUN (show_logging,
vty_out (vty, "disabled");
else
vty_out (vty, "level %s, facility %s, ident %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
- facility_name(zl->facility), zl->ident);
+ zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
+ facility_name(zl->facility), zl->ident);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Stdout logging: ");
@@ -3698,7 +1842,7 @@ DEFUN (show_logging,
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
+ zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Monitor logging: ");
@@ -3706,7 +1850,7 @@ DEFUN (show_logging,
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
+ zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "File logging: ");
@@ -3715,40 +1859,37 @@ DEFUN (show_logging,
vty_out (vty, "disabled");
else
vty_out (vty, "level %s, filename %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
- zl->filename);
+ zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
+ zl->filename);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Protocol name: %s%s",
- zlog_proto_names[zl->protocol], VTY_NEWLINE);
+ zlog_proto_names[zl->protocol], VTY_NEWLINE);
vty_out (vty, "Record priority: %s%s",
- (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
+ (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
vty_out (vty, "Timestamp precision: %d%s",
- zl->timestamp_precision, VTY_NEWLINE);
+ zl->timestamp_precision, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN (config_log_stdout,
config_log_stdout_cmd,
- "log stdout",
- "Logging control\n"
- "Set stdout logging level\n")
-{
- zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN (config_log_stdout_level,
- config_log_stdout_level_cmd,
- "log stdout "LOG_LEVELS,
+ "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
"Logging control\n"
"Set stdout logging level\n"
LOG_LEVEL_DESC)
{
+ int idx_log_level = 2;
+
+ if (argc == idx_log_level)
+ {
+ zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+ return CMD_SUCCESS;
+ }
int level;
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+ if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
return CMD_SUCCESS;
@@ -3756,11 +1897,11 @@ DEFUN (config_log_stdout_level,
DEFUN (no_config_log_stdout,
no_config_log_stdout_cmd,
- "no log stdout [LEVEL]",
+ "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
NO_STR
"Logging control\n"
"Cancel logging to stdout\n"
- "Logging level\n")
+ LOG_LEVEL_DESC)
{
zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
return CMD_SUCCESS;
@@ -3768,24 +1909,21 @@ DEFUN (no_config_log_stdout,
DEFUN (config_log_monitor,
config_log_monitor_cmd,
- "log monitor",
- "Logging control\n"
- "Set terminal line (monitor) logging level\n")
-{
- zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN (config_log_monitor_level,
- config_log_monitor_level_cmd,
- "log monitor "LOG_LEVELS,
+ "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
"Logging control\n"
"Set terminal line (monitor) logging level\n"
LOG_LEVEL_DESC)
{
+ int idx_log_level = 2;
+
+ if (argc == idx_log_level)
+ {
+ zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
+ return CMD_SUCCESS;
+ }
int level;
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
+ if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
return CMD_SUCCESS;
@@ -3793,11 +1931,11 @@ DEFUN (config_log_monitor_level,
DEFUN (no_config_log_monitor,
no_config_log_monitor_cmd,
- "no log monitor [LEVEL]",
+ "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
NO_STR
"Logging control\n"
"Disable terminal line (monitor) logging\n"
- "Logging level\n")
+ LOG_LEVEL_DESC)
{
zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
return CMD_SUCCESS;
@@ -3809,19 +1947,19 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
int ret;
char *p = NULL;
const char *fullpath;
-
+
/* Path detection. */
if (! IS_DIRECTORY_SEP (*fname))
{
char cwd[MAXPATHLEN+1];
cwd[MAXPATHLEN] = '\0';
-
+
if (getcwd (cwd, MAXPATHLEN) == NULL)
{
zlog_err ("config_log_file: Unable to alloc mem!");
return CMD_WARNING;
}
-
+
if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
== NULL)
{
@@ -3859,36 +1997,34 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
DEFUN (config_log_file,
config_log_file_cmd,
- "log file FILENAME",
- "Logging control\n"
- "Logging to file\n"
- "Logging filename\n")
-{
- return set_log_file(vty, argv[0], zlog_default->default_lvl);
-}
-
-DEFUN (config_log_file_level,
- config_log_file_level_cmd,
- "log file FILENAME "LOG_LEVELS,
+ "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
"Logging control\n"
"Logging to file\n"
"Logging filename\n"
LOG_LEVEL_DESC)
{
- int level;
-
- if ((level = level_match(argv[1])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- return set_log_file(vty, argv[0], level);
+ int idx_filename = 2;
+ int idx_log_levels = 3;
+ if (argc == 4)
+ {
+ int level;
+ if ((level = level_match(argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
+ return CMD_ERR_NO_MATCH;
+ return set_log_file(vty, argv[idx_filename]->arg, level);
+ }
+ else
+ return set_log_file(vty, argv[idx_filename]->arg, zlog_default->default_lvl);
}
DEFUN (no_config_log_file,
no_config_log_file_cmd,
- "no log file [FILENAME]",
+ "no log file [FILENAME [LEVEL]]",
NO_STR
"Logging control\n"
"Cancel logging to file\n"
- "Logging file name\n")
+ "Logging file name\n"
+ "Logging file name\n"
+ "Logging level\n")
{
zlog_reset_file (NULL);
@@ -3900,52 +2036,38 @@ DEFUN (no_config_log_file,
return CMD_SUCCESS;
}
-ALIAS (no_config_log_file,
- no_config_log_file_level_cmd,
- "no log file FILENAME LEVEL",
- NO_STR
- "Logging control\n"
- "Cancel logging to file\n"
- "Logging file name\n"
- "Logging level\n")
-
DEFUN (config_log_syslog,
config_log_syslog_cmd,
- "log syslog",
- "Logging control\n"
- "Set syslog logging level\n")
-{
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN (config_log_syslog_level,
- config_log_syslog_level_cmd,
- "log syslog "LOG_LEVELS,
+ "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
"Logging control\n"
"Set syslog logging level\n"
LOG_LEVEL_DESC)
{
- int level;
-
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
- return CMD_SUCCESS;
+ int idx_log_levels = 2;
+ if (argc == 3)
+ {
+ int level;
+ if ((level = level_match (argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
+ return CMD_ERR_NO_MATCH;
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+ return CMD_SUCCESS;
+ }
}
DEFUN_DEPRECATED (config_log_syslog_facility,
- config_log_syslog_facility_cmd,
- "log syslog facility "LOG_FACILITIES,
- "Logging control\n"
- "Logging goes to syslog\n"
- "(Deprecated) Facility parameter for syslog messages\n"
- LOG_FACILITY_DESC)
+ config_log_syslog_facility_cmd,
+ "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
+ "Logging control\n"
+ "Logging goes to syslog\n"
+ "(Deprecated) Facility parameter for syslog messages\n"
+ LOG_FACILITY_DESC)
{
- int facility;
-
- if ((facility = facility_match(argv[0])) < 0)
- return CMD_ERR_NO_MATCH;
+ int facility = facility_match(argv[3]->arg);
zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
zlog_default->facility = facility;
@@ -3954,63 +2076,54 @@ DEFUN_DEPRECATED (config_log_syslog_facility,
DEFUN (no_config_log_syslog,
no_config_log_syslog_cmd,
- "no log syslog [LEVEL]",
+ "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
NO_STR
"Logging control\n"
"Cancel logging to syslog\n"
- "Logging level\n")
+ LOG_FACILITY_DESC
+ LOG_LEVEL_DESC)
{
zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
return CMD_SUCCESS;
}
-ALIAS (no_config_log_syslog,
- no_config_log_syslog_facility_cmd,
- "no log syslog facility "LOG_FACILITIES,
- NO_STR
- "Logging control\n"
- "Logging goes to syslog\n"
- "Facility parameter for syslog messages\n"
- LOG_FACILITY_DESC)
-
DEFUN (config_log_facility,
config_log_facility_cmd,
- "log facility "LOG_FACILITIES,
+ "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
"Logging control\n"
"Facility parameter for syslog messages\n"
LOG_FACILITY_DESC)
{
- int facility;
+ int idx_target = 2;
+ int facility = facility_match(argv[idx_target]->arg);
- if ((facility = facility_match(argv[0])) < 0)
- return CMD_ERR_NO_MATCH;
zlog_default->facility = facility;
return CMD_SUCCESS;
}
DEFUN (no_config_log_facility,
no_config_log_facility_cmd,
- "no log facility [FACILITY]",
+ "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
NO_STR
"Logging control\n"
"Reset syslog facility to default (daemon)\n"
- "Syslog facility\n")
+ LOG_FACILITY_DESC)
{
zlog_default->facility = LOG_DAEMON;
return CMD_SUCCESS;
}
DEFUN_DEPRECATED (config_log_trap,
- config_log_trap_cmd,
- "log trap "LOG_LEVELS,
- "Logging control\n"
- "(Deprecated) Set logging level and default for all destinations\n"
- LOG_LEVEL_DESC)
+ config_log_trap_cmd,
+ "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
+ "Logging control\n"
+ "(Deprecated) Set logging level and default for all destinations\n"
+ LOG_LEVEL_DESC)
{
int new_level ;
int i;
-
- if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
+
+ if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
zlog_default->default_lvl = new_level;
@@ -4021,12 +2134,12 @@ DEFUN_DEPRECATED (config_log_trap,
}
DEFUN_DEPRECATED (no_config_log_trap,
- no_config_log_trap_cmd,
- "no log trap [LEVEL]",
- NO_STR
- "Logging control\n"
- "Permit all logging information\n"
- "Logging level\n")
+ no_config_log_trap_cmd,
+ "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
+ NO_STR
+ "Logging control\n"
+ "Permit all logging information\n"
+ LOG_LEVEL_DESC)
{
zlog_default->default_lvl = LOG_DEBUG;
return CMD_SUCCESS;
@@ -4055,20 +2168,15 @@ DEFUN (no_config_log_record_priority,
DEFUN (config_log_timestamp_precision,
config_log_timestamp_precision_cmd,
- "log timestamp precision <0-6>",
+ "log timestamp precision (0-6)",
"Logging control\n"
"Timestamp configuration\n"
"Set the timestamp precision\n"
"Number of subsecond digits\n")
{
- if (argc != 1)
- {
- vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
+ int idx_number = 3;
VTY_GET_INTEGER_RANGE("Timestamp Precision",
- zlog_default->timestamp_precision, argv[0], 0, 6);
+ zlog_default->timestamp_precision, argv[idx_number]->arg, 0, 6);
return CMD_SUCCESS;
}
@@ -4099,7 +2207,7 @@ cmd_banner_motd_file (const char *file)
if (in == rpath)
{
if (host.motdfile)
- XFREE (MTYPE_HOST, host.motdfile);
+ XFREE (MTYPE_HOST, host.motdfile);
host.motdfile = XSTRDUP (MTYPE_HOST, file);
}
else
@@ -4116,13 +2224,14 @@ DEFUN (banner_motd_file,
"Banner from a file\n"
"Filename\n")
{
- int cmd = cmd_banner_motd_file (argv[0]);
+ int idx_file = 3;
+ const char *filename = argv[idx_file]->arg;
+ int cmd = cmd_banner_motd_file (filename);
if (cmd == CMD_ERR_NO_FILE)
- vty_out (vty, "%s does not exist", argv[0]);
+ vty_out (vty, "%s does not exist", filename);
else if (cmd == CMD_WARNING)
- vty_out (vty, "%s must be in %s",
- argv[0], SYSCONFDIR);
+ vty_out (vty, "%s must be in %s", filename, SYSCONFDIR);
return cmd;
}
@@ -4146,43 +2255,12 @@ DEFUN (no_banner_motd,
"Strings for motd\n")
{
host.motd = NULL;
- if (host.motdfile)
+ if (host.motdfile)
XFREE (MTYPE_HOST, host.motdfile);
host.motdfile = NULL;
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)
@@ -4207,9 +2285,6 @@ install_default (enum node_type node)
install_element (node, &config_help_cmd);
install_element (node, &config_list_cmd);
- install_element (node, &config_write_terminal_cmd);
- install_element (node, &config_write_file_cmd);
- install_element (node, &config_write_memory_cmd);
install_element (node, &config_write_cmd);
install_element (node, &show_running_config_cmd);
}
@@ -4224,12 +2299,6 @@ cmd_init (int terminal)
{
qobj_init ();
- 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, "");
-
/* Allocate initial top vector of commands. */
cmdvec = vector_init (VECTOR_MIN_SIZE);
@@ -4272,10 +2341,7 @@ cmd_init (int terminal)
install_element (ENABLE_NODE, &config_end_cmd);
install_element (ENABLE_NODE, &config_disable_cmd);
install_element (ENABLE_NODE, &config_terminal_cmd);
- install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
- install_element (ENABLE_NODE, &config_write_terminal_cmd);
- install_element (ENABLE_NODE, &config_write_file_cmd);
- install_element (ENABLE_NODE, &config_write_memory_cmd);
+ install_element (ENABLE_NODE, &copy_runningconf_startupconf_cmd);
install_element (ENABLE_NODE, &config_write_cmd);
install_element (ENABLE_NODE, &show_running_config_cmd);
}
@@ -4291,33 +2357,24 @@ cmd_init (int terminal)
install_element (VIEW_NODE, &show_work_queues_cmd);
}
-
+
install_element (CONFIG_NODE, &hostname_cmd);
install_element (CONFIG_NODE, &no_hostname_cmd);
if (terminal > 0)
{
install_element (CONFIG_NODE, &password_cmd);
- install_element (CONFIG_NODE, &password_text_cmd);
install_element (CONFIG_NODE, &enable_password_cmd);
- install_element (CONFIG_NODE, &enable_password_text_cmd);
install_element (CONFIG_NODE, &no_enable_password_cmd);
install_element (CONFIG_NODE, &config_log_stdout_cmd);
- install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
install_element (CONFIG_NODE, &config_log_monitor_cmd);
- install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
install_element (CONFIG_NODE, &config_log_file_cmd);
- install_element (CONFIG_NODE, &config_log_file_level_cmd);
install_element (CONFIG_NODE, &no_config_log_file_cmd);
- install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
install_element (CONFIG_NODE, &config_log_syslog_cmd);
- install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
- install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
- install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
install_element (CONFIG_NODE, &config_log_facility_cmd);
install_element (CONFIG_NODE, &no_config_log_facility_cmd);
install_element (CONFIG_NODE, &config_log_trap_cmd);
@@ -4339,87 +2396,90 @@ cmd_init (int terminal)
srandom(time(NULL));
}
-static void
-cmd_terminate_token(struct cmd_token *token)
+struct cmd_token *
+new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
{
- unsigned int i, j;
- vector keyword_vect;
+ struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
+ token->type = type;
+ token->attr = attr;
+ token->text = text;
+ token->desc = desc;
+ token->arg = NULL;
- if (token->multiple)
- {
- for (i = 0; i < vector_active(token->multiple); i++)
- cmd_terminate_token(vector_slot(token->multiple, i));
- vector_free(token->multiple);
- token->multiple = NULL;
- }
+ return token;
+}
- if (token->keyword)
- {
- for (i = 0; i < vector_active(token->keyword); i++)
- {
- keyword_vect = vector_slot(token->keyword, i);
- for (j = 0; j < vector_active(keyword_vect); j++)
- cmd_terminate_token(vector_slot(keyword_vect, j));
- vector_free(keyword_vect);
- }
- vector_free(token->keyword);
- token->keyword = NULL;
- }
+void
+del_cmd_token (struct cmd_token *token)
+{
+ if (!token) return;
- XFREE(MTYPE_CMD_TOKENS, token->cmd);
- XFREE(MTYPE_CMD_TOKENS, token->desc);
+ if (token->text)
+ XFREE (MTYPE_CMD_TOKENS, token->text);
+ if (token->desc)
+ XFREE (MTYPE_CMD_TOKENS, token->desc);
+ if (token->arg)
+ XFREE (MTYPE_CMD_TOKENS, token->arg);
- XFREE(MTYPE_CMD_TOKENS, token);
+ XFREE (MTYPE_CMD_TOKENS, token);
}
-static void
-cmd_terminate_element(struct cmd_element *cmd)
+struct cmd_token *
+copy_cmd_token (struct cmd_token *token)
{
- unsigned int i;
+ struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
+ copy->max = token->max;
+ copy->min = token->min;
+ copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
+ copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
+ copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
- if (cmd->tokens == NULL)
- return;
+ return copy;
+}
- for (i = 0; i < vector_active(cmd->tokens); i++)
- cmd_terminate_token(vector_slot(cmd->tokens, i));
+void
+del_cmd_element(struct cmd_element *cmd)
+{
+ if (!cmd) return;
+ free ((char *) cmd->string);
+ free ((char *) cmd->doc);
+ free (cmd);
+}
- vector_free(cmd->tokens);
- cmd->tokens = NULL;
+struct cmd_element *
+copy_cmd_element(const struct cmd_element *cmd)
+{
+ struct cmd_element *el = XMALLOC(MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
+ el->string = cmd->string ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->string) : NULL;
+ el->func = cmd->func;
+ el->doc = cmd->doc ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->doc) : NULL;
+ el->daemon = cmd->daemon;
+ el->attr = cmd->attr;
+ return el;
}
void
cmd_terminate ()
{
- unsigned int i, j;
struct cmd_node *cmd_node;
- struct cmd_element *cmd_element;
- vector cmd_node_v;
if (cmdvec)
{
- for (i = 0; i < vector_active (cmdvec); i++)
+ for (unsigned int i = 0; i < vector_active (cmdvec); i++)
if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
- {
- cmd_node_v = cmd_node->cmd_vector;
-
- for (j = 0; j < vector_active (cmd_node_v); j++)
- if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
- cmd_terminate_element(cmd_element);
-
- vector_free (cmd_node_v);
- hash_clean (cmd_node->cmd_hash, NULL);
- hash_free (cmd_node->cmd_hash);
- cmd_node->cmd_hash = NULL;
- }
+ {
+ // deleting the graph delets the cmd_element as well
+ graph_delete_graph (cmd_node->cmdgraph);
+ vector_free (cmd_node->cmd_vector);
+ hash_clean (cmd_node->cmd_hash, NULL);
+ hash_free (cmd_node->cmd_hash);
+ cmd_node->cmd_hash = NULL;
+ }
vector_free (cmdvec);
cmdvec = NULL;
}
- if (command_cr)
- XFREE(MTYPE_CMD_TOKENS, command_cr);
- if (token_cr.desc)
- XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
if (host.name)
XFREE (MTYPE_HOST, host.name);
if (host.password)