summaryrefslogtreecommitdiffstats
path: root/lib/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c2940
1 files changed, 1738 insertions, 1202 deletions
diff --git a/lib/command.c b/lib/command.c
index 264e0f7b..67a9ab04 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1,11 +1,11 @@
/*
$Id$
-
+
Command interpreter routine for virtual terminal [aka TeletYpe]
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
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
@@ -30,8 +30,12 @@ Boston, MA 02111-1307, USA. */
#include "thread.h"
#include "vector.h"
#include "vty.h"
+#include "uty.h"
+#include "qstring.h"
#include "command.h"
+#include "command_execute.h"
#include "workqueue.h"
+#include "command_queue.h"
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
@@ -89,11 +93,17 @@ Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
\r\n";
+#ifdef QDEBUG
+const char* debug_banner =
+ QUAGGA_PROGNAME " version " QUAGGA_VERSION " QDEBUG=" QDEBUG_NAME " "
+ __DATE__ " " __TIME__ ;
+#endif
+
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 },
@@ -145,7 +155,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;
@@ -160,11 +170,11 @@ print_version (const char *progname)
printf ("%s\n", QUAGGA_COPYRIGHT);
}
-
+
/* 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 (const char* const* argv, int argc, int shift)
{
int i;
size_t len;
@@ -188,16 +198,7 @@ argv_concat (const char **argv, int argc, int shift)
return str;
}
-/* Install top node of command vector. */
-void
-install_node (struct cmd_node *node,
- int (*func) (struct vty *))
-{
- vector_set_index (cmdvec, node->node, node);
- node->func = func;
- node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
-}
-
+#if 0 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* Compare two command's string. Used in sort_node (). */
static int
cmp_node (const void *p, const void *q)
@@ -217,102 +218,245 @@ cmp_desc (const void *p, const void *q)
return strcmp (a->cmd, b->cmd);
}
+#endif //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+/* Install top node of command vector. */
+void
+install_node (struct cmd_node *node,
+ int (*func) (struct vty *))
+{
+ vector_set_index (cmdvec, node->node, node);
+ node->func = func;
+ node->cmd_vector = vector_init (0);
+}
+
+/* Compare two command's string. Used in sort_node (). */
+static int
+cmp_node (const struct cmd_element **a, const struct cmd_element **b)
+{
+ return strcmp ((*a)->string, (*b)->string);
+}
+
+static int
+cmp_desc (const struct desc **a, const struct desc **b)
+{
+ return strcmp ((*a)->cmd, (*b)->cmd);
+}
+
/* Sort each node's command element according to command string. */
void
sort_node ()
{
- unsigned int i, j;
- struct cmd_node *cnode;
- vector descvec;
- struct cmd_element *cmd_element;
+ unsigned int i ;
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((cnode = vector_slot (cmdvec, i)) != NULL)
- {
- vector cmd_vector = cnode->cmd_vector;
- qsort (cmd_vector->index, vector_active (cmd_vector),
- sizeof (void *), cmp_node);
+ for (i = 0; i < vector_length(cmdvec); i++)
+ {
+ struct cmd_node *cnode;
+ vector cmd_vector ;
+ unsigned int j;
- for (j = 0; j < vector_active (cmd_vector); j++)
- if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
- && vector_active (cmd_element->strvec))
- {
- descvec = vector_slot (cmd_element->strvec,
- vector_active (cmd_element->strvec) - 1);
- qsort (descvec->index, vector_active (descvec),
- sizeof (void *), cmp_desc);
- }
- }
-}
+ cnode = vector_get_item(cmdvec, i) ;
-/* 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. */
-vector
-cmd_make_strvec (const char *string)
+ if (cnode == NULL)
+ continue ;
+
+ cmd_vector = cnode->cmd_vector;
+ if (cmd_vector == NULL)
+ continue ;
+
+ vector_sort(cmd_vector, (vector_sort_cmp*)cmp_node) ;
+
+ for (j = 0; j < vector_length(cmd_vector); j++)
+ {
+ struct cmd_element *cmd_element ;
+ vector descvec ;
+
+ cmd_element = vector_get_item (cmd_vector, j);
+ if (cmd_element == NULL)
+ continue ;
+
+ descvec = vector_get_last_item(cmd_element->strvec) ;
+ if (descvec == NULL)
+ continue ;
+
+ vector_sort(descvec, (vector_sort_cmp*)cmp_desc) ;
+ } ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Take string and break it into tokens.
+ *
+ * Discards leading and trailing white-space.
+ *
+ * Treats lines that start with '!' or '#' (after any leading white-space)
+ * as empty -- these are comment lines.
+ *
+ * Tokens are non-whitespace separated by one or more white-space.
+ *
+ * White-space is anything that isspace() thinks is a space. (Which in the
+ * 'C' locale is ' ', '\t', '\r, '\n', '\f' and '\v'.)
+ *
+ * Returns: NULL => empty line (after white-space trimming) or comment line.
+ * otherwise: is vector containing one or more tokens.
+ *
+ * ....
+ *
+ *
+ * Note: all the tokens in the vector have at least one character, and no
+ * entries are NULL.
+ *
+ * NB: it is the caller's responsibility to release the vector and its contents,
+ * see cmd_free_strvec().
+ */
+static vector
+cmd_make_vline(vector vline, qstring qs, const char *string)
{
- const char *cp, *start;
- char *token;
- int strlen;
- vector strvec;
-
+ char *token, *tp ;
+ const char *cp, *sp, *ep, *op ;
+
+ /* Reset any existing vline, and empty the qstring if given. */
+ if (vline != NULL)
+ vector_set_length(vline, 0) ;
+
+ qs_clear(qs) ;
+
+ /* Strip leading and trailing white-space and deal with empty or effectively
+ * empty lines -- comment lines are treated as effectively empty.
+ */
+ cp = string;
+
if (string == NULL)
return NULL;
-
- cp = string;
- /* Skip white spaces. */
- while (isspace ((int) *cp) && *cp != '\0')
+ while (isspace((int) *cp))
cp++;
- /* Return if there is only white spaces */
- if (*cp == '\0')
- return NULL;
+ ep = cp + strlen(cp) ;
- if (*cp == '!' || *cp == '#')
+ while ((ep > cp) && (isspace((int)*(ep - 1))))
+ --ep ;
+
+ if ((cp == ep) || (*cp == '!') || (*cp == '#'))
return NULL;
- /* Prepare return vector. */
- strvec = vector_init (VECTOR_MIN_SIZE);
+ /* Prepare return vector -- expect some reasonable number of tokens. */
+ if (vline == NULL)
+ vline = vector_init(10) ;
- /* Copy each command piece and set into vector. */
- while (1)
+ /* If writing the words to a qstring, copy the body of the original (less
+ * any leading/trailing whitespace) to the qstring and '\0' terminate.
+ */
+ if (qs != NULL)
{
- 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;
+ qs_set_n(qs, cp, ep - cp) ;
+ tp = (char*)qs->body ; /* start at the beginning */
}
+ else
+ tp = NULL ; /* not used, but not undefined */
+
+ op = cp ; /* original start position */
+
+ /* Now have string cp..ep with no leading/trailing whitespace.
+ *
+ * If using a qstring, a copy of that exists at tp, complete with terminating
+ * '\0'. Writes '\0' terminators after each word found -- overwriting first
+ * separating white-space or the '\0' at the end.
+ *
+ * If not using a qstring, construct a new MTYPE_STRVEC for each word.
+ */
+ while (cp < ep)
+ {
+ while (isspace((int) *cp))
+ cp++ ; /* skip white-space */
+
+ sp = cp ;
+ while ((cp < ep) && !isspace((int) *cp))
+ cp++ ; /* eat token characters */
+
+ if (qs == NULL)
+ {
+ /* creating array of MTYPE_STRVEC */
+ size_t len ;
+
+ len = cp - sp ;
+ token = XMALLOC (MTYPE_STRVEC, len + 1);
+ memcpy (token, sp, len);
+ *(token + len) = '\0';
+ }
+ else
+ {
+ /* using qstring */
+ token = tp + (sp - op) ; /* token in qstring */
+ *(tp + (cp - op)) = '\0' ; /* terminate */
+ } ;
+
+ vector_push_item(vline, token);
+ } ;
+
+ return vline ;
}
-/* Free allocated string vector. */
-void
-cmd_free_strvec (vector v)
+/*------------------------------------------------------------------------------
+ * Take string and break it into tokens.
+ *
+ * Discards leading and trailing white-space.
+ *
+ * Treats lines that start with '!' or '#' (after any leading white-space)
+ * as empty -- these are comment lines.
+ *
+ * Tokens are non-whitespace separated by one or more white-space.
+ *
+ * White-space is anything that isspace() thinks is a space. (Which in the
+ * 'C' locale is ' ', '\t', '\r, '\n', '\f' and '\v'.)
+ *
+ * Returns: NULL => empty line (after white-space trimming) or comment line.
+ * otherwise: is vector containing one or more tokens.
+ *
+ * Note: all the tokens in the vector have at least one character, and no
+ * entries are NULL.
+ *
+ * NB: it is the caller's responsibility to release the vector and its contents,
+ * see cmd_free_strvec().
+ */
+extern vector
+cmd_make_strvec (const char *string)
{
- unsigned int i;
- char *cp;
+ return cmd_make_vline(NULL, NULL, string) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add given string to vector of strings.
+ *
+ * Create vector if required.
+ */
+extern vector
+cmd_add_to_strvec (vector strvec, const char* str)
+{
+ if (strvec == NULL)
+ strvec = vector_init(1) ;
- if (!v)
- return;
+ vector_push_item(strvec, XSTRDUP(MTYPE_STRVEC, str));
- for (i = 0; i < vector_active (v); i++)
- if ((cp = vector_slot (v, i)) != NULL)
- XFREE (MTYPE_STRVEC, cp);
+ return strvec ;
+} ;
- vector_free (v);
-}
+/*------------------------------------------------------------------------------
+ * Free allocated string vector (if any) and all its contents.
+ *
+ * Note that this is perfectly happy with strvec == NULL.
+ */
+extern void
+cmd_free_strvec (vector strvec)
+{
+ char *cp;
+
+ /* Note that vector_ream_free() returns NULL if strvec == NULL */
+ while((cp = vector_ream_free(strvec)) != NULL)
+ XFREE (MTYPE_STRVEC, cp);
+} ;
+
+/*----------------------------------------------------------------------------*/
/* Fetch next description. Used in cmd_make_descvec(). */
static char *
@@ -321,7 +465,7 @@ cmd_desc_str (const char **string)
const char *cp, *start;
char *token;
int strlen;
-
+
cp = *string;
if (cp == NULL)
@@ -370,7 +514,7 @@ cmd_make_descvec (const char *string, const char *descstr)
if (cp == NULL)
return NULL;
- allvec = vector_init (VECTOR_MIN_SIZE);
+ allvec = vector_init (0);
while (1)
{
@@ -396,7 +540,7 @@ cmd_make_descvec (const char *string, const char *descstr)
}
cp++;
}
-
+
while (isspace ((int) *cp) && *cp != '\0')
cp++;
@@ -406,7 +550,7 @@ cmd_make_descvec (const char *string, const char *descstr)
cp++;
}
- if (*cp == '\0')
+ if (*cp == '\0')
return allvec;
sp = cp;
@@ -428,14 +572,14 @@ cmd_make_descvec (const char *string, const char *descstr)
{
if (multiple == 1)
{
- strvec = vector_init (VECTOR_MIN_SIZE);
+ strvec = vector_init (0);
vector_set (allvec, strvec);
}
multiple++;
}
else
{
- strvec = vector_init (VECTOR_MIN_SIZE);
+ strvec = vector_init (0);
vector_set (allvec, strvec);
}
vector_set (strvec, desc);
@@ -449,23 +593,27 @@ cmd_cmdsize (vector strvec)
{
unsigned int i;
int size = 0;
- vector descvec;
- struct desc *desc;
- for (i = 0; i < vector_active (strvec); i++)
- if ((descvec = vector_slot (strvec, i)) != NULL)
+ for (i = 0; i < vector_length(strvec); i++)
{
- if ((vector_active (descvec)) == 1
- && (desc = vector_slot (descvec, 0)) != NULL)
- {
- if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
- return size;
- else
- size++;
- }
- else
- size++;
- }
+ vector descvec;
+
+ descvec = vector_get_item (strvec, i) ;
+ if (descvec == NULL)
+ continue ;
+
+ if (vector_length(descvec) == 1)
+ {
+ struct desc *desc;
+
+ desc = vector_get_item(descvec, 0) ;
+ if (desc != NULL)
+ if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
+ break ;
+ }
+ size++;
+ } ;
+
return size;
}
@@ -475,7 +623,19 @@ cmd_prompt (enum node_type node)
{
struct cmd_node *cnode;
- cnode = vector_slot (cmdvec, node);
+ assert(cmdvec != NULL) ;
+ assert(cmdvec->p_items != NULL) ;
+
+ cnode = NULL ;
+ if (node < cmdvec->limit)
+ cnode = vector_get_item (cmdvec, node);
+
+ if (cnode == NULL)
+ {
+ zlog_err("Could not find prompt for node %d for", node) ;
+ return NULL ;
+ } ;
+
return cnode->prompt;
}
@@ -484,14 +644,14 @@ void
install_element (enum node_type ntype, struct cmd_element *cmd)
{
struct cmd_node *cnode;
-
+
/* cmd_init hasn't been called */
if (!cmdvec)
return;
-
- cnode = vector_slot (cmdvec, ntype);
- if (cnode == NULL)
+ cnode = vector_get_item (cmdvec, ntype);
+
+ if (cnode == NULL)
{
fprintf (stderr, "Command node %d doesn't exist, please check it\n",
ntype);
@@ -512,7 +672,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;
@@ -527,7 +687,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';
@@ -539,15 +699,18 @@ zencrypt (const char *passwd)
static int
config_write_host (struct vty *vty)
{
+ if (qpthreads_enabled)
+ vty_out (vty, "threaded%s", VTY_NEWLINE);
+
if (host.name)
vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
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
{
@@ -557,57 +720,57 @@ config_write_host (struct vty *vty)
vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
}
- if (zlog_default->default_lvl != LOG_DEBUG)
+ if (zlog_get_default_lvl(NULL) != LOG_DEBUG)
{
vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
VTY_NEWLINE);
vty_out (vty, "log trap %s%s",
- zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
+ zlog_priority[zlog_get_default_lvl(NULL)], VTY_NEWLINE);
}
- if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
+ if (host.logfile && (zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) != ZLOG_DISABLED))
{
vty_out (vty, "log file %s", host.logfile);
- if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_FILE)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) != ZLOG_DISABLED)
{
vty_out (vty, "log stdout");
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) == ZLOG_DISABLED)
vty_out(vty,"no log monitor%s",VTY_NEWLINE);
- else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
+ else if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) != zlog_get_default_lvl(NULL))
vty_out(vty,"log monitor %s%s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR)],VTY_NEWLINE);
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) != ZLOG_DISABLED)
{
vty_out (vty, "log syslog");
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->facility != LOG_DAEMON)
+ if (zlog_get_facility(NULL) != LOG_DAEMON)
vty_out (vty, "log facility %s%s",
- facility_name(zlog_default->facility), VTY_NEWLINE);
+ facility_name(zlog_get_facility(NULL)), VTY_NEWLINE);
- if (zlog_default->record_priority == 1)
+ if (zlog_get_record_priority(NULL) == 1)
vty_out (vty, "log record-priority%s", VTY_NEWLINE);
- if (zlog_default->timestamp_precision > 0)
+ if (zlog_get_timestamp_precision(NULL) > 0)
vty_out (vty, "log timestamp precision %d%s",
- zlog_default->timestamp_precision, VTY_NEWLINE);
+ zlog_get_timestamp_precision(NULL), VTY_NEWLINE);
if (host.advanced)
vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
@@ -631,7 +794,7 @@ config_write_host (struct vty *vty)
static vector
cmd_node_vector (vector v, enum node_type ntype)
{
- struct cmd_node *cnode = vector_slot (v, ntype);
+ struct cmd_node *cnode = vector_get_item (v, ntype);
return cnode->cmd_vector;
}
@@ -683,21 +846,41 @@ cmd_filter_by_symbol (char *command, char *symbol)
}
#endif
+/*==============================================================================
+ * Match functions.
+ *
+ * Is the given string a, possibly incomplete, value of the required kind ?
+ */
+
/* Completion match types. */
-enum match_type
+enum match_type
{
- no_match,
+ no_match, /* nope */
extend_match,
+
ipv4_prefix_match,
ipv4_match,
ipv6_prefix_match,
ipv6_match,
range_match,
vararg_match,
- partly_match,
- exact_match
+
+ partly_match, /* OK as far as it went */
+ exact_match /* Syntactically complete */
};
+/*------------------------------------------------------------------------------
+ * Is this an IPv4 Address:
+ *
+ * 999.999.999.999 -- where no part may be > 255
+ *
+ * TODO: cmd_ipv4_match() seems to accept leading '.' ?
+ * TODO: cmd_ipv4_match() seems to accept leading zeros ?
+ *
+ * Returns: no_match -- improperly formed
+ * partly_match -- accepts empty string
+ * exact_match -- syntactically complete
+ */
static enum match_type
cmd_ipv4_match (const char *str)
{
@@ -755,6 +938,22 @@ cmd_ipv4_match (const char *str)
return exact_match;
}
+/*------------------------------------------------------------------------------
+ * Is this an IPv4 Prefix:
+ *
+ * 999.999.999.999/99 -- where no part may be > 255,
+ * and prefix length may not be > 32
+ *
+ * TODO: cmd_ipv4_prefix_match() seems to accept leading '.' ?
+ * TODO: cmd_ipv4_prefix_match() seems to accept leading zeros ?
+ *
+ * Returns: no_match -- improperly formed
+ * partly_match -- accepts empty string
+ * exact_match -- syntactically complete
+ *
+ * NB: partly_match is returned for anything valid before the '/', but which
+ * has no '/' or no number after the '/'.
+ */
static enum match_type
cmd_ipv4_prefix_match (const char *str)
{
@@ -834,6 +1033,16 @@ cmd_ipv4_prefix_match (const char *str)
return exact_match;
}
+/*------------------------------------------------------------------------------
+ * Is this an IPv6 Address:
+ *
+ * TODO: cmd_ipv6_match() only returns "partly_match" for empty string ?
+ *
+ * Returns: no_match -- improperly formed
+ * partly_match -- accepts empty string
+ * exact_match -- syntactically complete
+ */
+
#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
#define STATE_START 1
@@ -866,7 +1075,7 @@ cmd_ipv6_match (const char *str)
* ::1.2.3.4
*/
ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-
+
if (ret == 1)
return exact_match;
@@ -952,6 +1161,19 @@ cmd_ipv6_match (const char *str)
return exact_match;
}
+/*------------------------------------------------------------------------------
+ * Is this an IPv6 Prefix:
+ *
+ * TODO: cmd_ipv6_prefix_match() hardly returns "partly_match" ?
+ * TODO: cmd_ipv6_prefix_match() possibly accepts invalid address before '/' ?
+ *
+ * Returns: no_match -- improperly formed
+ * partly_match -- accepts empty string
+ * exact_match -- syntactically complete
+ *
+ * NB: partly_match is returned for anything valid before the '/', but which
+ * has no '/' or no number after the '/'.
+ */
static enum match_type
cmd_ipv6_prefix_match (const char *str)
{
@@ -1071,7 +1293,7 @@ cmd_ipv6_prefix_match (const char *str)
if (mask < 0 || mask > 128)
return no_match;
-
+
/* I don't know why mask < 13 makes command match partly.
Forgive me to make this comments. I Want to set static default route
because of lack of function to originate default in ospf6d; sorry
@@ -1085,6 +1307,14 @@ cmd_ipv6_prefix_match (const char *str)
#endif /* HAVE_IPV6 */
+/*------------------------------------------------------------------------------
+ * Is this a decimal number in the allowed range:
+ *
+ * Returns: 1 => OK -- *including* empty string
+ * 0 => not a valid number, or not in required range
+ * (or invalid range !!)
+ */
+
#define DECIMAL_STRLEN_MAX 10
static int
@@ -1132,340 +1362,496 @@ cmd_range_match (const char *range, const char *str)
return 1;
}
-/* Make completion match and return match type flag. */
+/*==============================================================================
+ * Command "filtering".
+ *
+ * The command parsing process starts with a (shallow) copy of the cmd_vector
+ * entry for the current "node".
+ *
+ * So cmd_v contains pointers to struct cmd_element values. When match fails,
+ * the pointer is set NULL -- so parsing is a process of reducing the cmd_v
+ * down to just the entries that match.
+ *
+ * Each cmd_element has a vector "strvec", which contains an entry for each
+ * "token" position. That entry is a vector containing the possible values at
+ * that position.
+ *
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Make completion match and return match type flag.
+ *
+ * Takes: command -- address of candidate token
+ * cmd_v -- vector of commands that is being reduced/filtered
+ * index -- index of token (position in line -- 0 == first)
+ *
+ * Returns: any of the enum match_type values:
+ *
+ * no_match => no match of any kind
+ *
+ * extend_match => saw an optional token
+ * ipv4_prefix_match )
+ * ipv4_match )
+ * ipv6_prefix_match ) saw full or partial match for this
+ * ipv6_match )
+ * range_match )
+ * vararg_match )
+ *
+ * partly_match => saw partial match for a keyword
+ * exact_match => saw exact match for a keyword
+ *
+ * Note that these return values are in ascending order of preference. So,
+ * if there are multiple possibilities at this position, will return the one
+ * furthest down this list.
+ */
static enum match_type
-cmd_filter_by_completion (char *command, vector v, unsigned int index)
+cmd_filter_by_completion (char *command, vector cmd_v, unsigned int index)
{
unsigned int i;
- const char *str;
- struct cmd_element *cmd_element;
+ unsigned int k;
enum match_type match_type;
- vector descvec;
- struct desc *desc;
match_type = no_match;
- /* If command and cmd_element string does not match set NULL to vector */
- for (i = 0; i < vector_active (v); i++)
- if ((cmd_element = vector_slot (v, i)) != NULL)
- {
- if (index >= vector_active (cmd_element->strvec))
- vector_slot (v, i) = NULL;
- else
- {
- unsigned int j;
- int matched = 0;
-
- descvec = vector_slot (cmd_element->strvec, index);
-
- for (j = 0; j < vector_active (descvec); j++)
- if ((desc = vector_slot (descvec, j)))
- {
- str = desc->cmd;
-
- if (CMD_VARARG (str))
- {
- if (match_type < vararg_match)
- match_type = vararg_match;
- matched++;
- }
- else if (CMD_RANGE (str))
- {
- if (cmd_range_match (str, command))
- {
- if (match_type < range_match)
- match_type = range_match;
+ /* If command and cmd_element string does not match, remove from vector */
+ k = 0 ;
+ for (i = 0; i < vector_length (cmd_v); i++)
+ {
+ const char *str;
+ struct cmd_element *cmd_element;
+ vector descvec;
+ struct desc *desc;
+ unsigned int j;
+ int matched ;
+
+ cmd_element = vector_get_item(cmd_v, i) ;
+
+ /* Skip past cmd_v entries that have already been set NULL */
+ if (cmd_element == NULL)
+ continue ;
+
+ /* Discard cmd_v entry that has no token at the current position */
+ descvec = vector_get_item(cmd_element->strvec, index) ;
+ if (descvec == NULL)
+ continue ;
+
+ /* See if get any sort of match at current position */
+ matched = 0 ;
+ for (j = 0; j < vector_length (descvec); j++)
+ {
+ desc = vector_get_item(descvec, j) ;
+ if (desc == NULL)
+ continue ;
+
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
- matched++;
- }
- }
+ matched++;
+ }
+ }
#ifdef HAVE_IPV6
- else if (CMD_IPV6 (str))
- {
- if (cmd_ipv6_match (command))
- {
- if (match_type < ipv6_match)
- match_type = ipv6_match;
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command))
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
- matched++;
- }
- }
- else if (CMD_IPV6_PREFIX (str))
- {
- if (cmd_ipv6_prefix_match (command))
- {
- if (match_type < ipv6_prefix_match)
- match_type = ipv6_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command))
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
- matched++;
- }
- }
+ matched++;
+ }
+ }
#endif /* HAVE_IPV6 */
- else if (CMD_IPV4 (str))
- {
- if (cmd_ipv4_match (command))
- {
- if (match_type < ipv4_match)
- match_type = ipv4_match;
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command))
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
- matched++;
- }
- }
- else if (CMD_IPV4_PREFIX (str))
- {
- if (cmd_ipv4_prefix_match (command))
- {
- if (match_type < ipv4_prefix_match)
- match_type = ipv4_prefix_match;
- matched++;
- }
- }
- else
- /* Check is this point's argument optional ? */
- if (CMD_OPTION (str) || CMD_VARIABLE (str))
- {
- if (match_type < extend_match)
- match_type = extend_match;
- matched++;
- }
- else if (strncmp (command, str, strlen (command)) == 0)
- {
- if (strcmp (command, str) == 0)
- match_type = exact_match;
- else
- {
- if (match_type < partly_match)
- match_type = partly_match;
- }
- matched++;
- }
- }
- if (!matched)
- vector_slot (v, i) = NULL;
- }
- }
- return match_type;
-}
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command))
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ /* Check is this point's argument optional ? */
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else if (strncmp (command, str, strlen (command)) == 0)
+ {
+ if (strcmp (command, str) == 0)
+ match_type = exact_match;
+ else
+ {
+ if (match_type < partly_match)
+ match_type = partly_match;
+ }
+ matched++;
+ } ;
+ } ;
+
+ /* Keep cmd_v entry that has a match at this position */
+ if (matched)
+ vector_set_item(cmd_v, k++, cmd_element) ;
+ } ;
-/* Filter vector by command character with index. */
+ vector_set_length(cmd_v, k) ; /* discard what did not keep */
+
+ return match_type;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Filter vector by command character with index.
+ *
+ * This appears to be identical to cmd_filter_by_completion(), except that
+ * when matching keywords, requires an exact match.
+ *
+ * TODO: see if can merge cmd_filter_by_completion() & cmd_filter_by_string()
+ */
static enum match_type
-cmd_filter_by_string (char *command, vector v, unsigned int index)
+cmd_filter_by_string (char *command, vector cmd_v, unsigned int index)
{
- unsigned int i;
- const char *str;
- struct cmd_element *cmd_element;
+ unsigned int i ;
+ unsigned int k ;
enum match_type match_type;
- vector descvec;
- struct desc *desc;
match_type = no_match;
- /* If command and cmd_element string does not match set NULL to vector */
- for (i = 0; i < vector_active (v); i++)
- if ((cmd_element = vector_slot (v, i)) != NULL)
- {
- /* If given index is bigger than max string vector of command,
- set NULL */
- if (index >= vector_active (cmd_element->strvec))
- vector_slot (v, i) = NULL;
- else
- {
- unsigned int j;
- int matched = 0;
+ /* If command and cmd_element string do match, keep in vector */
+ k = 0 ;
+ for (i = 0; i < vector_length(cmd_v); i++)
+ {
+ unsigned int j;
+ int matched ;
+ const char *str;
+ struct cmd_element *cmd_element;
+ vector descvec;
+ struct desc *desc;
+
+ cmd_element = vector_get_item(cmd_v, i) ;
+
+ /* Skip past NULL cmd_v entries (just in case) */
+ if (cmd_element == NULL)
+ continue ;
+
+ /* Discard cmd_v entry that has no token at the current position */
+ descvec = vector_get_item (cmd_element->strvec, index) ;
+ if (descvec == NULL)
+ continue ;
+
+ /* See if have a match against any of the current possibilities */
+ matched = 0 ;
+ for (j = 0; j < vector_length(descvec); j++)
+ {
+ desc = vector_get_item (descvec, j) ;
+ if (desc == NULL)
+ continue ;
+
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
+ matched++;
+ }
+ }
+#ifdef HAVE_IPV6
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command) == exact_match)
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
+ matched++;
+ }
+ }
+#endif /* HAVE_IPV6 */
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command) == exact_match)
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else
+ {
+ if (strcmp (command, str) == 0)
+ {
+ match_type = exact_match;
+ matched++;
+ } ;
+ } ;
+ } ;
- descvec = vector_slot (cmd_element->strvec, index);
+ /* Keep cmd_element if have a match */
+ if (matched)
+ vector_set_item(cmd_v, k++, cmd_element) ;
+ } ;
- for (j = 0; j < vector_active (descvec); j++)
- if ((desc = vector_slot (descvec, j)))
- {
- str = desc->cmd;
+ vector_set_length(cmd_v, k) ; /* discard what did not keep */
- if (CMD_VARARG (str))
- {
- if (match_type < vararg_match)
- match_type = vararg_match;
- matched++;
- }
- else if (CMD_RANGE (str))
- {
- if (cmd_range_match (str, command))
- {
- if (match_type < range_match)
- match_type = range_match;
- matched++;
- }
- }
-#ifdef HAVE_IPV6
- else if (CMD_IPV6 (str))
- {
- if (cmd_ipv6_match (command) == exact_match)
- {
- if (match_type < ipv6_match)
- match_type = ipv6_match;
- matched++;
- }
- }
- else if (CMD_IPV6_PREFIX (str))
- {
- if (cmd_ipv6_prefix_match (command) == exact_match)
- {
- if (match_type < ipv6_prefix_match)
- match_type = ipv6_prefix_match;
- matched++;
- }
- }
-#endif /* HAVE_IPV6 */
- else if (CMD_IPV4 (str))
- {
- if (cmd_ipv4_match (command) == exact_match)
- {
- if (match_type < ipv4_match)
- match_type = ipv4_match;
- matched++;
- }
- }
- else if (CMD_IPV4_PREFIX (str))
- {
- if (cmd_ipv4_prefix_match (command) == exact_match)
- {
- if (match_type < ipv4_prefix_match)
- match_type = ipv4_prefix_match;
- matched++;
- }
- }
- else if (CMD_OPTION (str) || CMD_VARIABLE (str))
- {
- if (match_type < extend_match)
- match_type = extend_match;
- matched++;
- }
- else
- {
- if (strcmp (command, str) == 0)
- {
- match_type = exact_match;
- matched++;
- }
- }
- }
- if (!matched)
- vector_slot (v, i) = NULL;
- }
- }
return match_type;
}
-/* Check ambiguous match */
+/*------------------------------------------------------------------------------
+ * Check for ambiguous match
+ *
+ * Given the best that cmd_filter_by_completion() or cmd_filter_by_string()
+ * found, check as follows:
+ *
+ * 1. discard all commands for which do not have the type of match selected.
+ *
+ * See above for the ranking of matches.
+ *
+ * 2. for "partial match", look out for matching more than one keyword, and
+ * return 1 if finds that.
+ *
+ * 3. for "range match", look out for matching more than one range, and
+ * return 1 if finds that.
+ *
+ * 4. for ipv4_prefix_match and ipv6_prefix_match, if get a "partial match",
+ * return 2.
+ *
+ * This appears to catch things which are supposed to be prefixes, but
+ * do not have a '/' or do not have any digits after the '/'.
+ *
+ * Takes: command -- address of candidate token
+ * cmd_v -- vector of commands that is being reduced/filtered
+ * index -- index of token (position in line -- 0 == first)
+ * type -- as returned by cmd_filter_by_completion()
+ * or cmd_filter_by_string()
+ *
+ * Returns: 0 => not ambiguous
+ * 1 => ambiguous -- the candidate token matches more than one
+ * keyword, or the candidate number matches more
+ * than one number range.
+ * 2 => partial match for ipv4_prefix or ipv6_prefix
+ * (missing '/' or no digits after '/').
+ *
+ * NB: it is assumed that cannot find both 1 and 2 states. But in any case,
+ * returns 1 in preference.
+ */
static int
-is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
+is_cmd_ambiguous (char *command, vector cmd_v, int index, enum match_type type)
{
unsigned int i;
- unsigned int j;
- const char *str = NULL;
- struct cmd_element *cmd_element;
- const char *matched = NULL;
- vector descvec;
- struct desc *desc;
+ unsigned int k;
+ int ret ;
- for (i = 0; i < vector_active (v); i++)
- if ((cmd_element = vector_slot (v, i)) != NULL)
- {
- int match = 0;
+ ret = 0 ; /* all's well so far */
+ k = 0 ; /* nothing kept, yet */
+
+ for (i = 0; i < vector_length (cmd_v); i++)
+ {
+ unsigned int j;
+ struct cmd_element *cmd_element;
+ const char *str_matched ;
+ vector descvec;
+ struct desc *desc;
+ int matched ;
+ enum match_type mt ;
+
+ cmd_element = vector_get_item (cmd_v, i) ;
+
+ /* Skip past NULL cmd_v entries (just in case) */
+ if (cmd_element == NULL)
+ continue ;
+
+ /* The cmd_v entry MUST have a token at the current position */
+ descvec = vector_get_item (cmd_element->strvec, index) ;
+ assert(descvec != NULL) ;
+
+ /* See if have a match against any of the current possibilities
+ *
+ * str_matched is set the first time get a partial string match,
+ * or the first time get a number range match.
+ *
+ * If get a second partial string match or number range match, then
+ * unless
+ */
+ str_matched = NULL ;
+ matched = 0;
+ for (j = 0; j < vector_length (descvec); j++)
+ {
+ enum match_type ret;
+ const char *str ;
- descvec = vector_slot (cmd_element->strvec, index);
+ desc = vector_get_item (descvec, j) ;
+ if (desc == NULL)
+ continue ;
- for (j = 0; j < vector_active (descvec); j++)
- if ((desc = vector_slot (descvec, j)))
- {
- enum match_type ret;
-
- str = desc->cmd;
+ str = desc->cmd;
+
+ switch (type)
+ {
+ case exact_match:
+ if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strcmp (command, str) == 0)
+ matched++;
+ break;
+
+ case partly_match:
+ if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strncmp (command, str, strlen (command)) == 0)
+ {
+ if (str_matched && (strcmp (str_matched, str) != 0))
+ ret = 1; /* There is ambiguous match. */
+ else
+ str_matched = str;
+ matched++;
+ }
+ break;
+
+ case range_match:
+ if (cmd_range_match (str, command))
+ {
+ if (str_matched && strcmp (str_matched, str) != 0)
+ ret = 1;
+ else
+ str_matched = str;
+ matched++;
+ }
+ break;
- switch (type)
- {
- case exact_match:
- if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
- && strcmp (command, str) == 0)
- match++;
- break;
- case partly_match:
- if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
- && 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_IPV6 (str))
- 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. */
+ case ipv6_match:
+ if (CMD_IPV6 (str))
+ matched++;
+ break;
- match++;
- }
- break;
+ case ipv6_prefix_match:
+ if ((mt = cmd_ipv6_prefix_match (command)) != no_match)
+ {
+ if (mt == partly_match)
+ if (ret != 1)
+ ret = 2; /* There is incomplete match. */
+
+ matched++;
+ }
+ break;
#endif /* HAVE_IPV6 */
- case ipv4_match:
- if (CMD_IPV4 (str))
- 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 (CMD_OPTION (str) || CMD_VARIABLE (str))
- match++;
- break;
- case no_match:
- default:
- break;
- }
- }
- if (!match)
- vector_slot (v, i) = NULL;
- }
- return 0;
-}
+ case ipv4_match:
+ if (CMD_IPV4 (str))
+ matched++;
+ break;
-/* If src matches dst return dst string, otherwise return NULL */
+ case ipv4_prefix_match:
+ if ((mt = cmd_ipv4_prefix_match (command)) != no_match)
+ {
+ if (mt == partly_match)
+ if (ret != 1)
+ ret = 2; /* There is incomplete match. */
+
+ matched++;
+ }
+ break;
+
+ case extend_match:
+ if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ matched++;
+ break;
+
+ case no_match:
+ default:
+ break;
+ } ;
+ } ;
+
+ /* Keep cmd_element if have a match */
+ if (matched)
+ vector_set_item(cmd_v, k++, cmd_element) ;
+ } ;
+
+ vector_set_length(cmd_v, k) ; /* discard what did not keep */
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * If src matches dst return dst string, otherwise return NULL
+ *
+ * Returns NULL if dst is an option, variable of vararg.
+ *
+ * NULL or empty src are deemed to match.
+ */
static const char *
cmd_entry_function (const char *src, const char *dst)
{
- /* Skip variable arguments. */
- if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
- CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst))
return NULL;
- /* In case of 'command \t', given src is NULL string. */
- if (src == NULL)
+ if ((src == NULL) || (*src == '\0'))
return dst;
- /* Matched with input string. */
if (strncmp (src, dst, strlen (src)) == 0)
return dst;
@@ -1537,16 +1923,20 @@ cmd_entry_function_desc (const char *src, const char *dst)
return NULL;
}
-/* Check same string element existence. If it isn't there return
- 1. */
-static int
+/*------------------------------------------------------------------------------
+ * Check same string element existence.
+ *
+ * Returns: 0 => found same string in the vector
+ * 1 => NOT found same string in the vector
+ */
+static bool
cmd_unique_string (vector v, const char *str)
{
unsigned int i;
char *match;
- for (i = 0; i < vector_active (v); i++)
- if ((match = vector_slot (v, i)) != NULL)
+ for (i = 0; i < vector_length (v); i++)
+ if ((match = vector_get_item (v, i)) != NULL)
if (strcmp (match, str) == 0)
return 0;
return 1;
@@ -1554,35 +1944,29 @@ cmd_unique_string (vector v, const char *str)
/* Compare string to description vector. If there is same string
return 1 else return 0. */
-static int
+static bool
desc_unique_string (vector v, const char *str)
{
unsigned int i;
struct desc *desc;
- for (i = 0; i < vector_active (v); i++)
- if ((desc = vector_slot (v, i)) != NULL)
+ for (i = 0; i < vector_length (v); i++)
+ if ((desc = vector_get_item (v, i)) != NULL)
if (strcmp (desc->cmd, str) == 0)
return 1;
return 0;
}
-static int
+static bool
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 &&
- node != RESTRICTED_NODE &&
- 0 == strcmp( "do", first_word ) )
- return 1;
- return 0;
+ return (node >= MIN_DO_SHORTCUT_NODE)
+ && (first_word != NULL)
+ && (strcmp( "do", first_word) == 0) ? 1 : 0 ;
}
/* '?' describe command support. */
static vector
-cmd_describe_command_real (vector vline, struct vty *vty, int *status)
+cmd_describe_command_real (vector vline, int node, int *status)
{
unsigned int i;
vector cmd_vector;
@@ -1595,16 +1979,16 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
char *command;
/* Set index. */
- if (vector_active (vline) == 0)
+ if (vector_length (vline) == 0)
{
*status = CMD_ERR_NO_MATCH;
return NULL;
}
else
- index = vector_active (vline) - 1;
-
+ index = vector_length (vline) - 1;
+
/* Make copy vector of current node's command vector. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, node));
/* Prepare match vector */
matchvec = vector_init (INIT_MATCHVEC_SIZE);
@@ -1612,29 +1996,29 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
/* Filter commands. */
/* Only words precedes current word will be checked in this loop. */
for (i = 0; i < index; i++)
- if ((command = vector_slot (vline, i)))
+ if ((command = vector_get_item (vline, i)))
{
match = cmd_filter_by_completion (command, cmd_vector, i);
-
+
if (match == vararg_match)
{
struct cmd_element *cmd_element;
vector descvec;
unsigned int j, k;
- for (j = 0; j < vector_active (cmd_vector); j++)
- if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
- && (vector_active (cmd_element->strvec)))
+ for (j = 0; j < vector_length (cmd_vector); j++)
+ if ((cmd_element = vector_get_item (cmd_vector, j)) != NULL
+ && (vector_length (cmd_element->strvec)))
{
- descvec = vector_slot (cmd_element->strvec,
- vector_active (cmd_element->strvec) - 1);
- for (k = 0; k < vector_active (descvec); k++)
+ descvec = vector_get_item (cmd_element->strvec,
+ vector_length (cmd_element->strvec) - 1);
+ for (k = 0; k < vector_length (descvec); k++)
{
- struct desc *desc = vector_slot (descvec, k);
+ struct desc *desc = vector_get_item (descvec, k);
vector_set (matchvec, desc);
}
}
-
+
vector_set (matchvec, &desc_cr);
vector_free (cmd_vector);
@@ -1660,53 +2044,58 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
/* Prepare match vector */
/* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
- /* Make sure that cmd_vector is filtered based on current word */
- command = vector_slot (vline, index);
+ /* Make sure that cmd_vector is filtered based on current word */
+ command = vector_get_item (vline, index);
if (command)
match = cmd_filter_by_completion (command, cmd_vector, index);
/* Make description vector. */
- for (i = 0; i < vector_active (cmd_vector); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
- {
- vector strvec = cmd_element->strvec;
+ for (i = 0; i < vector_length (cmd_vector); i++)
+ {
+ vector strvec ;
+
+ cmd_element = vector_get_item (cmd_vector, i) ;
+ if (cmd_element == NULL)
+ continue ;
+
+ /* Ignore cmd_element if no tokens at index position.
+ *
+ * Deal with special case of possible <cr> completion.
+ */
+ strvec = cmd_element->strvec;
+ if (index >= vector_length (strvec))
+ {
+ if (command == NULL && index == vector_length (strvec))
+ {
+ if (!desc_unique_string (matchvec, command_cr))
+ vector_push_item(matchvec, &desc_cr);
+ }
+ continue ;
+ } ;
+
+ /* Check if command is completed. */
+ unsigned int j;
+ vector descvec = vector_get_item (strvec, index);
+ struct desc *desc;
+
+ for (j = 0; j < vector_length (descvec); j++)
+ if ((desc = vector_get_item (descvec, j)))
+ {
+ const char *string;
+
+ string = cmd_entry_function_desc (command, desc->cmd);
+ if (string)
+ {
+ /* Uniqueness check */
+ if (!desc_unique_string (matchvec, string))
+ vector_push_item(matchvec, desc);
+ }
+ } ;
+ } ;
- /* if command is NULL, index may be equal to vector_active */
- if (command && index >= vector_active (strvec))
- vector_slot (cmd_vector, i) = NULL;
- else
- {
- /* Check if command is completed. */
- if (command == NULL && index == vector_active (strvec))
- {
- if (!desc_unique_string (matchvec, command_cr))
- vector_set (matchvec, &desc_cr);
- }
- else
- {
- unsigned int j;
- vector descvec = vector_slot (strvec, index);
- struct desc *desc;
-
- for (j = 0; j < vector_active (descvec); j++)
- if ((desc = vector_slot (descvec, j)))
- {
- const char *string;
-
- string = cmd_entry_function_desc (command, desc->cmd);
- if (string)
- {
- /* Uniqueness check */
- if (!desc_unique_string (matchvec, string))
- vector_set (matchvec, desc);
- }
- }
- }
- }
- }
vector_free (cmd_vector);
- if (vector_slot (matchvec, 0) == NULL)
+ if (vector_length(matchvec) == 0)
{
vector_free (matchvec);
*status = CMD_ERR_NO_MATCH;
@@ -1717,269 +2106,285 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
return matchvec;
}
+/*------------------------------------------------------------------------------
+ * Get description of current (partial) command
+ *
+ * Returns: NULL => no description available
+ *
+ * status set to CMD_ERR_NO_MATCH or CMD_ERR_AMBIGUOUS
+ *
+ * or: address of vector of "struct desc" values available.
+ *
+ * NB: when a vector is returned it is the caller's responsibility to
+ * vector_free() it. (The contents are all effectively const, so do not
+ * themselves need to be freed.)
+ */
vector
-cmd_describe_command (vector vline, struct vty *vty, int *status)
+cmd_describe_command (vector vline, int node, int *status)
{
vector ret;
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
+ if ( cmd_try_do_shortcut(node, vector_get_item(vline, 0) ) )
{
- enum node_type onode;
- vector shifted_vline;
+ 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++)
+ for (index = 1; index < vector_length (vline); index++)
{
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
- ret = cmd_describe_command_real (shifted_vline, vty, status);
+ ret = cmd_describe_command_real (shifted_vline, ENABLE_NODE, status);
vector_free(shifted_vline);
- vty->node = onode;
return ret;
}
-
- return cmd_describe_command_real (vline, vty, status);
+ return cmd_describe_command_real (vline, node, status);
}
-
-/* Check LCD of matched command. */
+/*------------------------------------------------------------------------------
+ * Check LCD of matched command.
+ *
+ * Scan list of matched keywords, and by comparing them pair-wise, find the
+ * longest common leading substring.
+ *
+ * Returns: 0 if zero or one matched keywords
+ * length of longest common leading substring, otherwise.
+ */
static int
-cmd_lcd (char **matched)
+cmd_lcd (vector matchvec)
{
- int i;
- int j;
- int lcd = -1;
- char *s1, *s2;
- char c1, c2;
+ int n ;
+ int i ;
+ int lcd ;
+ char *sp, *sq, *ss ;
- if (matched[0] == NULL || matched[1] == NULL)
- return 0;
+ n = vector_end(matchvec) ;
+ if (n < 2)
+ return 0 ;
+
+ ss = vector_get_item(matchvec, 0) ;
+ lcd = strlen(ss) ;
- for (i = 1; matched[i] != NULL; i++)
+ for (i = 1 ; i < n ; i++)
{
- s1 = matched[i - 1];
- s2 = matched[i];
+ sq = ss ;
+ ss = vector_get_item(matchvec, i) ;
+ sp = ss ;
- for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
- if (c1 != c2)
- break;
+ while ((*sp == *sq) && (*sp != '\0'))
+ {
+ ++sp ;
+ ++sq ;
+ } ;
- if (lcd < 0)
- lcd = j;
- else
- {
- if (lcd > j)
- lcd = j;
- }
+ if (lcd > (sp - ss))
+ lcd = (sp - ss) ;
}
return lcd;
}
-/* Command line completion support. */
-static char **
-cmd_complete_command_real (vector vline, struct vty *vty, int *status)
+/*------------------------------------------------------------------------------
+ * Command line completion support.
+ */
+static vector
+cmd_complete_command_real (vector vline, int node, int *status)
{
unsigned int i;
- vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+ unsigned int ivl ;
+ unsigned int last_ivl ;
+ vector cmd_v ;
#define INIT_MATCHVEC_SIZE 10
vector matchvec;
struct cmd_element *cmd_element;
unsigned int index;
- char **match_str;
struct desc *desc;
vector descvec;
- char *command;
- int lcd;
+ char *token;
+ int n ;
- if (vector_active (vline) == 0)
+ /* Stop immediately if the vline is empty. */
+ if (vector_length (vline) == 0)
{
- vector_free (cmd_vector);
*status = CMD_ERR_NO_MATCH;
return NULL;
}
- else
- index = vector_active (vline) - 1;
- /* First, filter by preceeding command string */
- for (i = 0; i < index; i++)
- if ((command = vector_slot (vline, i)))
- {
- enum match_type match;
- int ret;
+ /* Take (shallow) copy of cmdvec for given node. */
+ cmd_v = vector_copy (cmd_node_vector (cmdvec, node));
- /* First try completion match, if there is exactly match return 1 */
- match = cmd_filter_by_completion (command, cmd_vector, i);
+ /* First, filter upto, but excluding last token */
+ last_ivl = vector_length (vline) - 1;
- /* If there is exact match then filter ambiguous match else check
- ambiguousness. */
- if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
- {
- vector_free (cmd_vector);
- *status = CMD_ERR_AMBIGUOUS;
- return NULL;
- }
- /*
- else if (ret == 2)
- {
- vector_free (cmd_vector);
+ for (ivl = 0; ivl < last_ivl; ivl++)
+ {
+ enum match_type match;
+ int ret;
+
+ /* TODO: does this test make any sense ? */
+ if ((token = vector_get_item (vline, ivl)) == NULL)
+ continue ;
+
+ /* First try completion match, return best kind of match */
+ index = ivl ;
+ match = cmd_filter_by_completion (token, cmd_v, index) ;
+
+ /* Eliminate all but the selected kind of match */
+ ret = is_cmd_ambiguous (token, cmd_v, index, match) ;
+
+ if (ret == 1)
+ {
+ /* ret == 1 => either token matches more than one keyword
+ * or token matches more than one number range
+ */
+ vector_free (cmd_v);
+ *status = CMD_ERR_AMBIGUOUS;
+ return NULL;
+ }
+#if 0
+ /* For command completion purposes do not appear to care about
+ * incomplete ipv4 or ipv6 prefixes (missing '/' or digits after).
+ */
+ else if (ret == 2)
+ {
+ vector_free (cmd_v);
*status = CMD_ERR_NO_MATCH;
return NULL;
- }
- */
+ }
+#endif
}
-
- /* Prepare match vector. */
+
+ /* Prepare match vector. */
matchvec = vector_init (INIT_MATCHVEC_SIZE);
- /* Now we got into completion */
- for (i = 0; i < vector_active (cmd_vector); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)))
- {
- const char *string;
- vector strvec = cmd_element->strvec;
+ /* Now we got into completion */
+ index = last_ivl ;
+ token = vector_get_item(vline, last_ivl) ; /* is now the last token */
- /* Check field length */
- if (index >= vector_active (strvec))
- vector_slot (cmd_vector, i) = NULL;
- else
- {
- unsigned int j;
+ for (i = 0; i < vector_length (cmd_v); i++)
+ {
+ unsigned int j;
+ const char *string;
- descvec = vector_slot (strvec, index);
- for (j = 0; j < vector_active (descvec); j++)
- if ((desc = vector_slot (descvec, j)))
- {
- if ((string =
- cmd_entry_function (vector_slot (vline, index),
- desc->cmd)))
- if (cmd_unique_string (matchvec, string))
- vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
- }
- }
- }
+ if ((cmd_element = vector_get_item (cmd_v, i)) == NULL)
+ continue ;
- /* We don't need cmd_vector any more. */
- vector_free (cmd_vector);
+ descvec = vector_get_item (cmd_element->strvec, index);
+ if (descvec == NULL)
+ continue ;
+
+ for (j = 0; j < vector_length (descvec); j++)
+ {
+ desc = vector_get_item (descvec, j) ;
+ if (desc == NULL)
+ continue ;
+
+ string = cmd_entry_function(token, desc->cmd) ;
+ if ((string != NULL) && cmd_unique_string(matchvec, string))
+ cmd_add_to_strvec (matchvec, string) ;
+ } ;
+ } ;
+
+ n = vector_length(matchvec) ; /* number of entries in the matchvec */
+
+ /* We don't need cmd_v any more. */
+ vector_free (cmd_v);
/* No matched command */
- if (vector_slot (matchvec, 0) == NULL)
+ if (n == 0)
{
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;
+ if (*token == '\0')
+ *status = CMD_COMPLETE_ALREADY;
else
*status = CMD_ERR_NO_MATCH;
return NULL;
}
- /* Only one matched */
- if (vector_slot (matchvec, 1) == NULL)
+ /* Only one matched */
+ if (n == 1)
{
- match_str = (char **) matchvec->index;
- vector_only_wrapper_free (matchvec);
*status = CMD_COMPLETE_FULL_MATCH;
- return match_str;
+ return matchvec ;
}
- /* Make it sure last element is NULL. */
- vector_set (matchvec, NULL);
- /* Check LCD of matched strings. */
- if (vector_slot (vline, index) != NULL)
+ /* Check LCD of matched strings. */
+ if (token != NULL)
{
- lcd = cmd_lcd ((char **) matchvec->index);
+ unsigned lcd = cmd_lcd (matchvec) ;
- if (lcd)
+ if (lcd != 0)
{
- int len = strlen (vector_slot (vline, index));
-
- if (len < lcd)
+ if (strlen(token) < lcd)
{
char *lcdstr;
lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
- memcpy (lcdstr, matchvec->index[0], lcd);
+ memcpy (lcdstr, vector_get_item(matchvec, 0), lcd) ;
lcdstr[lcd] = '\0';
- /* match_str = (char **) &lcdstr; */
+ cmd_free_strvec(matchvec) ; /* discard the match vector */
- /* Free matchvec. */
- for (i = 0; i < vector_active (matchvec); i++)
- {
- if (vector_slot (matchvec, i))
- XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
- }
- vector_free (matchvec);
-
- /* Make new matchvec. */
- matchvec = vector_init (INIT_MATCHVEC_SIZE);
- vector_set (matchvec, lcdstr);
- match_str = (char **) matchvec->index;
- vector_only_wrapper_free (matchvec);
+ matchvec = vector_init (1);
+ vector_push_item(matchvec, lcdstr) ;
*status = CMD_COMPLETE_MATCH;
- return match_str;
+ return matchvec ;
}
}
}
- match_str = (char **) matchvec->index;
- vector_only_wrapper_free (matchvec);
*status = CMD_COMPLETE_LIST_MATCH;
- return match_str;
+ return matchvec ;
}
-char **
-cmd_complete_command (vector vline, struct vty *vty, int *status)
+/*------------------------------------------------------------------------------
+ * Can the current command be completed ?
+ */
+extern vector
+cmd_complete_command (vector vline, int node, int *status)
{
- char **ret;
+ vector ret;
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
+ if ( cmd_try_do_shortcut(node, vector_get_item(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++)
+ for (index = 1; index < vector_length (vline); index++)
{
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
- ret = cmd_complete_command_real (shifted_vline, vty, status);
+ ret = cmd_complete_command_real (shifted_vline, ENABLE_NODE, status);
vector_free(shifted_vline);
- vty->node = onode;
return ret;
}
-
- return cmd_complete_command_real (vline, vty, status);
+ return cmd_complete_command_real (vline, node, status);
}
-/* return parent node */
-/* MUST eventually converge on CONFIG_NODE */
+/*------------------------------------------------------------------------------
+ * Return parent node
+ *
+ * All nodes > CONFIG_NODE are descended from CONFIG_NODE
+ */
enum node_type
node_parent ( enum node_type node )
{
- enum node_type ret;
-
assert (node > CONFIG_NODE);
switch (node)
@@ -1989,493 +2394,585 @@ node_parent ( enum node_type node )
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
- ret = BGP_NODE;
- break;
+ return BGP_NODE;
+
case KEYCHAIN_KEY_NODE:
- ret = KEYCHAIN_NODE;
- break;
+ return KEYCHAIN_NODE;
+
default:
- ret = CONFIG_NODE;
+ return CONFIG_NODE;
}
-
- return ret;
}
-/* Execute command by argument vline vector. */
-static int
-cmd_execute_command_real (vector vline, struct vty *vty,
- struct cmd_element **cmd)
+/*------------------------------------------------------------------------------
+ * Initialise a new struct cmd_parsed, allocating if required
+ */
+extern cmd_parsed
+cmd_parse_init_new(cmd_parsed parsed)
{
- 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;
- int varflag;
- char *command;
+ if (parsed == NULL)
+ parsed = XCALLOC(MTYPE_CMD_PARSED, sizeof(*parsed)) ;
+ else
+ memset(parsed, 0, sizeof(*parsed)) ;
+
+ /* Zeroising the structure has set:
+ *
+ * cmd = NULL -- no command parsed, yet
+ * cnode -- no node set, yet
+ *
+ * do_shortcut -- false
+ * onode -- not material (do_shortcut is false)
+ *
+ * line = zeroised qstring -- empty
+ * words = zeroised qstring -- empty
+ *
+ * vline = zeroised vector -- empty
+ *
+ * so nothing else to do
+ */
- /* Make copy of command elements. */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+ return parsed ;
+} ;
- for (index = 0; index < vector_active (vline); index++)
- if ((command = vector_slot (vline, index)))
- {
- int ret;
+/*------------------------------------------------------------------------------
+ * Initialise a new struct cmd_parsed, allocating if required
+ */
+extern cmd_parsed
+cmd_parse_reset(cmd_parsed parsed, bool free_structure)
+{
+ if (parsed != NULL)
+ {
+ qs_reset_keep(&parsed->words) ;
+ vector_reset_keep(&parsed->vline) ;
- match = cmd_filter_by_completion (command, cmd_vector, index);
+ if (free_structure)
+ XFREE(MTYPE_CMD_PARSED, parsed) ; /* sets parsed = NULL */
+ else
+ cmd_parse_init_new(parsed) ;
+ } ;
+
+ return parsed ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Parse a command in the given "node", if possible, ready for execution.
+ *
+ * If 'strict': use cmd_filter_by_string()
+ * otherwise: use cmd_filter_by_completion()
+ *
+ * If 'do': see if there is a 'do' at the front and proceed accordingly.
+ *
+ * If 'tree': move up the node tree to find command if not found in the
+ * current node.
+ */
+
+static enum cmd_return_code
+cmd_parse_this(struct cmd_parsed* parsed, bool strict) ;
+
+/*------------------------------------------------------------------------------
+ * Parse a command in the given "node", or (if required) any of its ancestors.
+ *
+ * Returns: CMD_SUCCESS => successfully parsed command, and the result is
+ * in the given parsed structure, ready for execution.
+ *
+ * NB: parsed->cnode may have changed.
+ *
+ * NB: parsed->cmd->daemon => daemon
+ *
+ * CMD_EMPTY => empty or comment line
+ *
+ * NB: parsed->cmd == NULL
+ *
+ * CMD_SUCCESS_DAEMON => parsed successfully. Something for vtysh ??
+ *
+ * CMD_ERR_NO_MATCH )
+ * CMD_ERR_AMBIGUOUS ) failed to parse
+ * CMD_ERR_INCOMPLETE )
+ *
+ * NB: if has failed to parse in the current node
+ * and in any ancestor nodes, returns the error
+ * from the attempt to parse in the current node
+ * (parsed->cnode which is returned unchanged).
+ *
+ * NB: the command line MUST be preserved until the parsed command is no
+ * longer required -- no copy is made.
+ *
+ * NB: expects to have free run of everything in the vty structure (except
+ * the contents of the vty_io sub-structure) until the command completes.
+ *
+ * See elsewhere for description of parsed structure.
+ */
+extern enum cmd_return_code
+cmd_parse_command(struct vty* vty, enum cmd_parse_type type)
+{
+ enum cmd_return_code ret ;
+ enum cmd_return_code first_ret ;
+ cmd_parsed parsed ;
- if (match == vararg_match)
- break;
-
- ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+ /* Initialise the parsed structure -- assuming no 'do' */
+ if (vty->parsed == NULL)
+ vty->parsed = cmd_parse_init_new(NULL) ;
+ parsed = vty->parsed ;
- if (ret == 1)
- {
- vector_free (cmd_vector);
- return CMD_ERR_AMBIGUOUS;
- }
- else if (ret == 2)
- {
- vector_free (cmd_vector);
- return CMD_ERR_NO_MATCH;
- }
- }
+ parsed->onode = parsed->cnode = vty->node ;
- /* Check matched count. */
- matched_element = NULL;
- matched_count = 0;
- incomplete_count = 0;
+ parsed->cmd = NULL ;
+ parsed->do_shortcut = 0 ;
- for (i = 0; i < vector_active (cmd_vector); i++)
- if ((cmd_element = vector_slot (cmd_vector, i)))
- {
- if (match == vararg_match || index >= cmd_element->cmdsize)
- {
- matched_element = cmd_element;
-#if 0
- printf ("DEBUG: %s\n", cmd_element->string);
-#endif
- matched_count++;
- }
- else
- {
- incomplete_count++;
- }
- }
+ /* Parse the line into words -- set up parsed->words and parsed->vline */
+ cmd_make_vline(&parsed->vline, &parsed->words, vty->buf) ;
- /* Finish of using cmd_vector. */
- vector_free (cmd_vector);
+ if (vector_length(&parsed->vline) == 0)
+ return CMD_EMPTY ; /* NB: parsed->cmd == NULL */
- /* To execute command, matched_count must be 1. */
- if (matched_count == 0)
+ /* If allowed to 'do', see if there.
+ *
+ * 'do' forces command to be parsed in ENABLE_NODE (if allowed)
+ */
+ if ((type & cmd_parse_do) &&
+ cmd_try_do_shortcut(parsed->cnode, vector_get_item(&parsed->vline, 0)))
{
- if (incomplete_count)
- return CMD_ERR_INCOMPLETE;
- else
- return CMD_ERR_NO_MATCH;
- }
+ parsed->cnode = ENABLE_NODE ;
+ parsed->do_shortcut = 1 ;
+ } ;
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
+ /* Try in the current node */
+ ret = cmd_parse_this(parsed, ((type & cmd_parse_strict) != 0)) ;
- /* Argument treatment */
- varflag = 0;
- argc = 0;
-
- for (i = 0; i < vector_active (vline); i++)
+ if (ret != CMD_SUCCESS)
{
- if (varflag)
- argv[argc++] = vector_slot (vline, i);
- else
- {
- vector descvec = vector_slot (matched_element->strvec, i);
+ if (((type & cmd_parse_tree) == 0) || parsed->do_shortcut)
+ return ret ; /* done if not allowed to walk tree
+ or just tried to parse a 'do' */
- if (vector_active (descvec) == 1)
- {
- struct desc *desc = vector_slot (descvec, 0);
+ /* Try in parent node(s) */
+ first_ret = ret ;
- if (CMD_VARARG (desc->cmd))
- varflag = 1;
-
- if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
- argv[argc++] = vector_slot (vline, i);
- }
- else
- argv[argc++] = vector_slot (vline, i);
- }
+ while (ret != CMD_SUCCESS)
+ {
+ if (parsed->cnode <= CONFIG_NODE)
+ {
+ parsed->cnode = parsed->onode ; /* restore node state */
+ return first_ret ; /* return original result */
+ } ;
+
+ parsed->cnode = node_parent(parsed->cnode) ;
+ ret = cmd_parse_this(parsed, ((type & cmd_parse_strict) != 0)) ;
+ } ;
+ } ;
+
+ return vty->parsed->cmd->daemon ? CMD_SUCCESS_DAEMON
+ : CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Work function for cmd_parse_command
+ *
+ * Takes a parsed structure, with the:
+ *
+ * cnode -- node to parse in
+ * vline -- the line broken into words
+ * do_shortcut -- true if first word is 'do' (to be ignored)
+ *
+ * and parses either strictly or with command completion.
+ *
+ * If successful, reduces the vline structure down to the variable portions,
+ * ie to the argv[] for the command function.
+ *
+ * Returns: CMD_SUCCESS -- parsed successfully
+ * CMD_ERR_NO_MATCH )
+ * CMD_ERR_AMBIGUOUS ) failed to parse
+ * CMD_ERR_INCOMPLETE )
+ */
+static enum cmd_return_code
+cmd_parse_this(cmd_parsed parsed, bool strict)
+{
+ unsigned int i ;
+ unsigned int ivl ;
+ unsigned index ;
+ unsigned first ;
+ unsigned argc ;
+ vector cmd_v;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ enum match_type match = 0;
+ int varflag;
+ char *command;
- if (argc >= CMD_ARGC_MAX)
- return CMD_ERR_EXEED_ARGC_MAX;
- }
+ /* Need length of vline, discounting the first entry if required */
+ first = parsed->do_shortcut ? 1 : 0 ;
- /* For vtysh execution. */
- if (cmd)
- *cmd = matched_element;
+ assert(vector_length(&parsed->vline) >= first) ;
+ ivl = vector_length(&parsed->vline) - first ;
- if (matched_element->daemon)
- return CMD_SUCCESS_DAEMON;
+ /* Make copy of command elements. */
+ cmd_v = vector_copy (cmd_node_vector (cmdvec, parsed->cnode));
- /* Execute matched command. */
- return (*matched_element->func) (matched_element, vty, argc, argv);
-}
+ /* Look for an unambiguous result */
+ for (index = 0 ; index < ivl; index++)
+ {
+ int ret ;
-int
-cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
- int vtysh) {
- int ret, saved_ret, tried = 0;
- enum node_type onode, try_node;
+ command = vector_get_item(&parsed->vline, index + first) ;
+ if (command == NULL)
+ continue ;
- onode = try_node = vty->node;
+ match = strict ? cmd_filter_by_string(command, cmd_v, index)
+ : cmd_filter_by_completion(command, cmd_v, index) ;
- if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
- {
- vector shifted_vline;
- unsigned int index;
+ if (match == vararg_match)
+ break;
- vty->node = ENABLE_NODE;
- /* We can try it on enable node, cos' the vty is authenticated */
+ ret = is_cmd_ambiguous (command, cmd_v, index, match);
- 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));
+ if (ret != 0)
+ {
+ assert((ret == 1) || (ret == 2)) ;
+ vector_free (cmd_v);
+ return (ret == 1) ? CMD_ERR_AMBIGUOUS : CMD_ERR_NO_MATCH ;
}
+ } ;
- ret = cmd_execute_command_real (shifted_vline, vty, cmd);
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
- vector_free(shifted_vline);
- vty->node = onode;
- return ret;
- }
+ for (i = 0; i < vector_length(cmd_v); i++)
+ {
+ cmd_element = vector_get_item(cmd_v, i) ;
+ if (cmd_element == NULL)
+ continue ;
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+#if 0
+ printf ("DEBUG: %s\n", cmd_element->string);
+#endif
+ matched_count++;
+ }
+ else
+ {
+ incomplete_count++;
+ }
+ } ;
- saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
+ /* Finished with cmd_v. */
+ vector_free (cmd_v);
- if (vtysh)
- return saved_ret;
+ /* To execute command, matched_count must be 1. */
+ if (matched_count != 1)
+ {
+ if (matched_count == 0)
+ return (incomplete_count) ? CMD_ERR_INCOMPLETE : CMD_ERR_NO_MATCH ;
+ else
+ return CMD_ERR_AMBIGUOUS ;
+ } ;
+
+ /* Found command -- process the arguments ready for execution */
+ varflag = 0 ;
+ argc = 0 ;
- /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
- while ( ret != CMD_SUCCESS && ret != CMD_WARNING
- && vty->node > CONFIG_NODE )
+ for (index = 0; index < ivl ; index++)
{
- try_node = node_parent(try_node);
- vty->node = try_node;
- ret = cmd_execute_command_real (vline, vty, cmd);
- tried = 1;
- if (ret == CMD_SUCCESS || ret == CMD_WARNING)
+ int take = varflag ;
+
+ if (!varflag)
{
- /* succesfull command, leave the node as is */
- return ret;
+ vector descvec = vector_get_item (matched_element->strvec, index);
+
+ if (vector_length (descvec) == 1)
+ {
+ struct desc *desc = vector_get_item (descvec, 0);
+
+ if (CMD_VARARG (desc->cmd))
+ take = varflag = 1 ;
+ else
+ take = (CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) ;
+ }
+ else
+ take = 1 ;
}
- }
- /* no command succeeded, reset the vty to the original node and
- return the error for this node */
- if ( tried )
- vty->node = onode;
- return saved_ret;
-}
-/* Execute command by argument readline. */
-int
-cmd_execute_command_strict (vector vline, struct vty *vty,
- 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];
- int varflag;
- enum match_type match = 0;
- char *command;
+ if (take)
+ vector_assign_item(&parsed->vline, argc++, index + first) ;
+ } ;
- /* Make copy of command element */
- cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+ vector_set_length(&parsed->vline, argc) ; /* set to new length */
- for (index = 0; index < vector_active (vline); index++)
- if ((command = vector_slot (vline, index)))
- {
- int ret;
-
- match = cmd_filter_by_string (vector_slot (vline, index),
- cmd_vector, index);
+ /* Everything checks out... ready to execute command */
+ parsed->cmd = matched_element ;
- /* If command meets '.VARARG' then finish matching. */
- if (match == vararg_match)
- break;
-
- ret = is_cmd_ambiguous (command, cmd_vector, index, match);
- if (ret == 1)
- {
- vector_free (cmd_vector);
- return CMD_ERR_AMBIGUOUS;
- }
- if (ret == 2)
- {
- vector_free (cmd_vector);
- return CMD_ERR_NO_MATCH;
- }
- }
+ return CMD_SUCCESS ;
+} ;
- /* Check matched count. */
- matched_element = NULL;
- matched_count = 0;
- incomplete_count = 0;
- for (i = 0; i < vector_active (cmd_vector); i++)
- if (vector_slot (cmd_vector, i) != NULL)
- {
- cmd_element = vector_slot (cmd_vector, i);
+/*------------------------------------------------------------------------------
+ * Dispatch a parsed command.
+ *
+ * Returns: command return code. NB: may be CMD_QUEUED (unless no_queue).
+ *
+ * NB: expects to have free run of everything in the vty structure (except
+ * the contents of the vty_io sub-structure) until the command completes.
+ */
+extern enum cmd_return_code
+cmd_dispatch(struct vty* vty, bool no_queue)
+{
+ cmd_parsed parsed = vty->parsed ;
+ enum cmd_return_code ret ;
- if (match == vararg_match || index >= cmd_element->cmdsize)
- {
- matched_element = cmd_element;
- matched_count++;
- }
- else
- incomplete_count++;
- }
+ if (parsed->cmd == NULL)
+ return CMD_SUCCESS ; /* NULL commands are easy */
- /* Finish of using cmd_vector. */
- vector_free (cmd_vector);
+ vty->node = parsed->cnode ;
- /* To execute command, matched_count must be 1. */
- if (matched_count == 0)
+ if (no_queue || !vty_cli_nexus)
{
- if (incomplete_count)
- return CMD_ERR_INCOMPLETE;
- else
- return CMD_ERR_NO_MATCH;
+ ret = cmd_dispatch_call(vty) ;
+ cmd_post_command(vty, ret) ;
}
-
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
-
- /* Argument treatment */
- varflag = 0;
- argc = 0;
-
- for (i = 0; i < vector_active (vline); i++)
+ else
{
- if (varflag)
- argv[argc++] = vector_slot (vline, i);
+ /* Don't do it now, but send to bgp qpthread */
+ if (parsed->cmd->attr & CMD_ATTR_CALL)
+ cq_enqueue(vty, vty_cli_nexus) ;
else
- {
- vector descvec = vector_slot (matched_element->strvec, i);
+ cq_enqueue(vty, vty_cmd_nexus) ;
+
+ ret = CMD_QUEUED ;
+ } ;
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Tidy up after executing command.
+ *
+ * This is separated out so that can be called when queued command completes.
+ *
+ * If have just processed a "do" shortcut command, and it has not set the
+ * vty->node to something other than ENABLE_NODE, then restore to the original
+ * state.
+ *
+ * Arguments: ret = CMD_XXXX -- NB: CMD_QUEUED => command revoked
+ */
+extern void
+cmd_post_command(struct vty* vty, int ret)
+{
+ if (vty->parsed->do_shortcut)
+ {
+ if (vty->node == ENABLE_NODE)
+ vty->node = vty->parsed->onode ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Parse and execute a command.
+ *
+ * The command is given by vty->buf and vty->node.
+ *
+ * Uses vty->parsed.
+ *
+ * -- use strict/completion parsing, as required.
+ *
+ * -- parse in current node and in ancestors, as required
+ *
+ * If does not find in any ancestor, return error from current node.
+ *
+ * -- implement the "do" shortcut, as required
+ *
+ * If qpthreads_enabled, then may queue the command rather than execute it
+ * here.
+ *
+ * The vty->node may be changed during the execution of the command, and may
+ * be returned changed once the command has completed.
+ *
+ * NB: expects to have free run of everything in the vty structure (except
+ * the contents of the vty_io sub-structure) until the command completes.
+ */
+extern enum cmd_return_code
+cmd_execute_command(struct vty *vty,
+ enum cmd_parse_type type, struct cmd_element **cmd)
+{
+ enum cmd_return_code ret ;
+
+ /* Try to parse in vty->node or, if required, ancestors thereof. */
+ ret = cmd_parse_command(vty, type) ;
+
+ if (cmd != NULL)
+ *cmd = vty->parsed->cmd ; /* for vtysh */
+
+ if (ret == CMD_SUCCESS)
+ ret = cmd_dispatch(vty, 0) ;
+ else if (ret == CMD_EMPTY)
+ ret = CMD_SUCCESS ;
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Read configuration from file.
+ *
+ * In the qpthreads world this assumes that it is running with the vty
+ * locked, and that all commands are to be executed directly.
+ *
+ * If the 'first_cmd' argument is not NULL it is the address of the first
+ * command that is expected to appear. If the first command is not this, then
+ * the 'first_cmd' is called with argv == NULL (and argc == 0) to signal the
+ * command is being invoked by default.
+ *
+ * Command processing continues while CMD_SUCCESS is returned by the command
+ * parser and command execution.
+ *
+ * If 'ignore_warning' is set, then any CMD_WARNING returned by command
+ * execution is converted to CMD_SUCCESS. Note that any CMD_WARNING returned
+ * by command parsing (or in execution of any default 'first_cmd').
+ *
+ * Returns: cmd_return_code for last command
+ * vty->buf is last line processed
+ * vty->lineno is number of last line processed (1 is first)
+ *
+ * If the file is empty, will return CMD_SUCCESS.
+ *
+ * Never returns CMD_EMPTY -- that counts as CMD_SUCCESS.
+ *
+ * If
+ *
+ * If return code is not CMD_SUCCESS, the the output buffering contains the
+ * output from the last command attempted.
+ */
+extern enum cmd_return_code
+config_from_file (struct vty *vty, FILE *fp, struct cmd_element* first_cmd,
+ qstring buf, bool ignore_warning)
+{
+ enum cmd_return_code ret;
- if (vector_active (descvec) == 1)
- {
- struct desc *desc = vector_slot (descvec, 0);
+ vty->buf = buf->body ;
+ vty->lineno = 0 ;
- if (CMD_VARARG (desc->cmd))
- varflag = 1;
+ ret = CMD_SUCCESS ; /* in case file is empty */
+ vty_out_clear(vty) ;
- if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
- argv[argc++] = vector_slot (vline, i);
- }
- else
- argv[argc++] = vector_slot (vline, i);
- }
+ while (fgets (buf->body, buf->size, fp))
+ {
+ ++vty->lineno ;
- if (argc >= CMD_ARGC_MAX)
- return CMD_ERR_EXEED_ARGC_MAX;
- }
+ /* Execute configuration command : this is strict match */
+ ret = cmd_parse_command(vty, cmd_parse_strict + cmd_parse_tree) ;
- /* For vtysh execution. */
- if (cmd)
- *cmd = matched_element;
+ if (ret == CMD_EMPTY)
+ continue ; /* skip empty/comment */
- if (matched_element->daemon)
- return CMD_SUCCESS_DAEMON;
+ if (ret != CMD_SUCCESS)
+ break ; /* stop on *any* parsing issue */
- /* Now execute matched command */
- return (*matched_element->func) (matched_element, vty, argc, argv);
-}
+ /* special handling before of first command */
+ if (first_cmd != NULL)
+ {
+ if (first_cmd != vty->parsed->cmd)
+ {
+ ret = (*first_cmd->func)(first_cmd, vty, 0, NULL) ;
+ if (ret != CMD_SUCCESS)
+ break ; /* stop on *any* issue with "default" */
+ } ;
+ first_cmd = NULL ;
+ }
-/* Configration make from file. */
-int
-config_from_file (struct vty *vty, FILE *fp)
-{
- int ret;
- vector vline;
+ /* Standard command handling */
+ ret = cmd_dispatch(vty, cmd_no_queue) ;
- while (fgets (vty->buf, VTY_BUFSIZ, fp))
- {
- vline = cmd_make_strvec (vty->buf);
+ if (ret != CMD_SUCCESS)
+ {
+ /* Ignore CMD_WARNING if required
+ *
+ * Ignore CMD_CLOSE at all times.
+ */
+ if ( ((ret == CMD_WARNING) && ignore_warning)
+ || (ret == CMD_CLOSE) )
+ ret = CMD_SUCCESS ; /* in case at EOF */
+ else
+ break ; /* stop */
+ } ;
- /* In case of comment line */
- if (vline == NULL)
- continue;
- /* Execute configuration command : this is strict match */
- ret = cmd_execute_command_strict (vline, vty, NULL);
+ vty_out_clear(vty) ;
+ } ;
- /* Try again with setting node to CONFIG_NODE */
- while (ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
- {
- vty->node = node_parent(vty->node);
- ret = cmd_execute_command_strict (vline, vty, NULL);
- }
+ if (ret == CMD_EMPTY)
+ ret = CMD_SUCCESS ; /* OK if end on empty line */
- cmd_free_strvec (vline);
+ return ret ;
+} ;
- if (ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_ERR_NOTHING_TODO)
- return ret;
- }
- return CMD_SUCCESS;
-}
+/*----------------------------------------------------------------------------*/
/* Configration from terminal */
-DEFUN (config_terminal,
+DEFUN_CALL (config_terminal,
config_terminal_cmd,
"configure terminal",
"Configuration from vty interface\n"
"Configuration terminal\n")
{
- if (vty_config_lock (vty))
- vty->node = CONFIG_NODE;
- else
- {
- vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
+ if (vty_config_lock (vty, CONFIG_NODE))
+ return CMD_SUCCESS;
+
+ vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
+ return CMD_WARNING;
}
/* Enable command */
-DEFUN (enable,
+DEFUN_CALL (enable,
config_enable_cmd,
"enable",
"Turn on privileged mode command\n")
{
/* If enable password is NULL, change to ENABLE_NODE */
if ((host.enable == NULL && host.enable_encrypt == NULL) ||
- vty->type == VTY_SHELL_SERV)
- vty->node = ENABLE_NODE;
+ vty_shell_serv(vty))
+ vty_set_node(vty, ENABLE_NODE);
else
- vty->node = AUTH_ENABLE_NODE;
+ vty_set_node(vty, AUTH_ENABLE_NODE);
return CMD_SUCCESS;
}
/* Disable command */
-DEFUN (disable,
+DEFUN_CALL (disable,
config_disable_cmd,
"disable",
"Turn off privileged mode command\n")
{
- if (vty->node == ENABLE_NODE)
- vty->node = VIEW_NODE;
+ if (vty_get_node(vty) == ENABLE_NODE)
+ vty_set_node(vty, VIEW_NODE);
return CMD_SUCCESS;
}
/* Down vty node level. */
-DEFUN (config_exit,
+DEFUN_CALL (config_exit,
config_exit_cmd,
"exit",
"Exit current mode and down to previous mode\n")
{
- switch (vty->node)
- {
- case VIEW_NODE:
- case ENABLE_NODE:
- case RESTRICTED_NODE:
- if (vty_shell (vty))
- exit (0);
- else
- vty->status = VTY_CLOSE;
- break;
- case CONFIG_NODE:
- vty->node = ENABLE_NODE;
- vty_config_unlock (vty);
- break;
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case BGP_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case MASC_NODE:
- case RMAP_NODE:
- case VTY_NODE:
- vty->node = CONFIG_NODE;
- break;
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- vty->node = BGP_NODE;
- break;
- case KEYCHAIN_KEY_NODE:
- vty->node = KEYCHAIN_NODE;
- break;
- default:
- break;
- }
- return CMD_SUCCESS;
+ return vty_cmd_exit(vty) ;
}
/* quit is alias of exit. */
-ALIAS (config_exit,
+ALIAS_CALL (config_exit,
config_quit_cmd,
"quit",
"Exit current mode and down to previous mode\n")
-
+
/* End of configuration. */
-DEFUN (config_end,
+DEFUN_CALL (config_end,
config_end_cmd,
"end",
"End current mode and change to enable mode.")
{
- switch (vty->node)
- {
- case VIEW_NODE:
- case ENABLE_NODE:
- case RESTRICTED_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- vty_config_unlock (vty);
- vty->node = ENABLE_NODE;
- break;
- default:
- break;
- }
- return CMD_SUCCESS;
+ return vty_cmd_end(vty) ;
}
/* Show version. */
-DEFUN (show_version,
+DEFUN_CALL (show_version,
show_version_cmd,
"show version",
SHOW_STR
@@ -2489,12 +2986,12 @@ DEFUN (show_version,
}
/* Help display function for all node. */
-DEFUN (config_help,
+DEFUN_CALL (config_help,
config_help_cmd,
"help",
"Description of the interactive help system\n")
{
- vty_out (vty,
+ vty_out (vty,
"Quagga VTY provides advanced help feature. When you need help,%s\
anytime at the command line please press '?'.%s\
%s\
@@ -2513,39 +3010,38 @@ argument.%s\
}
/* Help display function for all node. */
-DEFUN (config_list,
+DEFUN_CALL (config_list,
config_list_cmd,
"list",
"Print command list\n")
{
unsigned int i;
- struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
+ struct cmd_node *cnode = vector_get_item (cmdvec, vty_get_node(vty));
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))
+ for (i = 0; i < vector_length (cnode->cmd_vector); i++)
+ if ((cmd = vector_get_item (cnode->cmd_vector, i)) != NULL
+ && !(cmd->attr & (CMD_ATTR_DEPRECATED | CMD_ATTR_HIDDEN)))
vty_out (vty, " %s%s", cmd->string,
VTY_NEWLINE);
return CMD_SUCCESS;
}
/* Write current configuration into file. */
-DEFUN (config_write_file,
+DEFUN (config_write_file,
config_write_file_cmd,
- "write file",
+ "write file",
"Write running configuration to memory, network, or terminal\n"
"Write to configuration file\n")
{
unsigned int i;
int fd;
+ int err;
struct cmd_node *node;
char *config_file;
char *config_file_tmp = NULL;
char *config_file_sav = NULL;
int ret = CMD_WARNING;
- struct vty *file_vty;
/* Check and see if we are operating under vtysh configuration */
if (host.config == NULL)
@@ -2557,7 +3053,7 @@ DEFUN (config_write_file,
/* 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);
@@ -2566,7 +3062,7 @@ 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)
@@ -2575,62 +3071,74 @@ DEFUN (config_write_file,
VTY_NEWLINE);
goto finished;
}
-
+
/* Make vty for configuration file. */
- file_vty = vty_new ();
- file_vty->fd = fd;
- file_vty->type = VTY_FILE;
+ vty_open_config_write(vty, fd) ;
/* Config file header print. */
- vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
- vty_time_print (file_vty, 1);
- vty_out (file_vty, "!\n");
+ vty_out (vty, "!\n! Zebra configuration saved from vty\n! ");
+ vty_time_print (vty, 1);
+ vty_out (vty, "!\n");
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((node = vector_slot (cmdvec, i)) && node->func)
+ for (i = 0; i < vector_length (cmdvec); i++)
+ if ((node = vector_get_item (cmdvec, i)) && node->func)
{
- if ((*node->func) (file_vty))
- vty_out (file_vty, "!\n");
+ if ((*node->func) (vty))
+ vty_out (vty, "!\n");
}
- vty_close (file_vty);
+
+ err = vty_close_config_write(vty) ;
+ close(fd) ;
+
+ if (err != 0)
+ {
+ vty_out (vty, "Failed while writing configuration file %s.%s",
+ config_file_tmp, VTY_NEWLINE);
+ goto finished;
+ }
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);
+ 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);
+ vty_out (vty, "Can't backup old configuration file %s.%s",
+ config_file_sav, VTY_NEWLINE);
goto finished;
- }
- sync ();
+ } ;
+
+ sync () ;
+
if (unlink (config_file) != 0)
{
- vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
- VTY_NEWLINE);
+ 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_out (vty, "Can't save configuration file %s.%s",
+ config_file, 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 (%s).\n",
+ config_file, errtostr(errno, 0).str, errtoname(errno, 0).str);
goto finished;
}
- vty_out (vty, "Configuration saved to %s%s", config_file,
- VTY_NEWLINE);
+ vty_out (vty, "Configuration saved to %s\n", config_file);
+
ret = CMD_SUCCESS;
finished:
@@ -2640,20 +3148,20 @@ finished:
return ret;
}
-ALIAS (config_write_file,
+ALIAS (config_write_file,
config_write_cmd,
- "write",
+ "write",
"Write running configuration to memory, network, or terminal\n")
-ALIAS (config_write_file,
+ALIAS (config_write_file,
config_write_memory_cmd,
- "write memory",
+ "write memory",
"Write running configuration to memory, network, or terminal\n"
"Write configuration to the file (same as write file)\n")
-ALIAS (config_write_file,
+ALIAS (config_write_file,
copy_runningconfig_startupconfig_cmd,
- "copy running-config startup-config",
+ "copy running-config startup-config",
"Copy configuration\n"
"Copy running config to... \n"
"Copy running config to startup config (same as write file)\n")
@@ -2668,10 +3176,10 @@ DEFUN (config_write_terminal,
unsigned int i;
struct cmd_node *node;
- if (vty->type == VTY_SHELL_SERV)
+ if (vty_shell_serv(vty))
{
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+ for (i = 0; i < vector_length (cmdvec); i++)
+ if ((node = vector_get_item (cmdvec, i)) && node->func && node->vtysh)
{
if ((*node->func) (vty))
vty_out (vty, "!%s", VTY_NEWLINE);
@@ -2683,8 +3191,8 @@ DEFUN (config_write_terminal,
VTY_NEWLINE);
vty_out (vty, "!%s", VTY_NEWLINE);
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((node = vector_slot (cmdvec, i)) && node->func)
+ for (i = 0; i < vector_length (cmdvec); i++)
+ if ((node = vector_get_item (cmdvec, i)) && node->func)
{
if ((*node->func) (vty))
vty_out (vty, "!%s", VTY_NEWLINE);
@@ -2736,7 +3244,7 @@ DEFUN (show_startup_config,
}
/* Hostname configuration */
-DEFUN (config_hostname,
+DEFUN_CALL (config_hostname,
hostname_cmd,
"hostname WORD",
"Set system's network name\n"
@@ -2748,28 +3256,40 @@ DEFUN (config_hostname,
return CMD_WARNING;
}
+ VTY_LOCK() ;
+
if (host.name)
XFREE (MTYPE_HOST, host.name);
-
+
host.name = XSTRDUP (MTYPE_HOST, argv[0]);
+ uty_set_host_name(host.name) ;
+
+ VTY_UNLOCK() ;
+
return CMD_SUCCESS;
}
-DEFUN (config_no_hostname,
+DEFUN_CALL (config_no_hostname,
no_hostname_cmd,
"no hostname [HOSTNAME]",
NO_STR
"Reset system's network name\n"
"Host name of this router\n")
{
+ VTY_LOCK() ;
+
if (host.name)
XFREE (MTYPE_HOST, host.name);
host.name = NULL;
+ uty_set_host_name(host.name) ;
+
+ VTY_UNLOCK() ;
+
return CMD_SUCCESS;
}
/* VTY interface password set. */
-DEFUN (config_password, password_cmd,
+DEFUN_CALL (config_password, password_cmd,
"password (8|) WORD",
"Assign the terminal connection password\n"
"Specifies a HIDDEN password will follow\n"
@@ -2804,7 +3324,7 @@ DEFUN (config_password, password_cmd,
if (!isalnum ((int) *argv[0]))
{
- vty_out (vty,
+ vty_out (vty,
"Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2825,13 +3345,13 @@ DEFUN (config_password, password_cmd,
return CMD_SUCCESS;
}
-ALIAS (config_password, password_text_cmd,
+ALIAS_CALL (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,
+DEFUN_CALL (config_enable_password, enable_password_cmd,
"enable password (8|) WORD",
"Modify enable password parameters\n"
"Assign the privileged level password\n"
@@ -2870,7 +3390,7 @@ DEFUN (config_enable_password, enable_password_cmd,
if (!isalnum ((int) *argv[0]))
{
- vty_out (vty,
+ vty_out (vty,
"Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2892,7 +3412,7 @@ DEFUN (config_enable_password, enable_password_cmd,
return CMD_SUCCESS;
}
-ALIAS (config_enable_password,
+ALIAS_CALL (config_enable_password,
enable_password_text_cmd,
"enable password LINE",
"Modify enable password parameters\n"
@@ -2900,7 +3420,7 @@ ALIAS (config_enable_password,
"The UNENCRYPTED (cleartext) 'enable' password\n")
/* VTY enable password delete. */
-DEFUN (no_config_enable_password, no_enable_password_cmd,
+DEFUN_CALL (no_config_enable_password, no_enable_password_cmd,
"no enable password",
NO_STR
"Modify enable password parameters\n"
@@ -2916,8 +3436,8 @@ DEFUN (no_config_enable_password, no_enable_password_cmd,
return CMD_SUCCESS;
}
-
-DEFUN (service_password_encrypt,
+
+DEFUN_CALL (service_password_encrypt,
service_password_encrypt_cmd,
"service password-encryption",
"Set up miscellaneous service\n"
@@ -2944,7 +3464,7 @@ DEFUN (service_password_encrypt,
return CMD_SUCCESS;
}
-DEFUN (no_service_password_encrypt,
+DEFUN_CALL (no_service_password_encrypt,
no_service_password_encrypt_cmd,
"no service password-encryption",
NO_STR
@@ -2967,7 +3487,7 @@ DEFUN (no_service_password_encrypt,
return CMD_SUCCESS;
}
-DEFUN (config_terminal_length, config_terminal_length_cmd,
+DEFUN_CALL (config_terminal_length, config_terminal_length_cmd,
"terminal length <0-512>",
"Set terminal line parameters\n"
"Set number of lines on a screen\n"
@@ -2982,22 +3502,22 @@ DEFUN (config_terminal_length, config_terminal_length_cmd,
vty_out (vty, "length is malformed%s", VTY_NEWLINE);
return CMD_WARNING;
}
- vty->lines = lines;
+ vty_set_lines(vty, lines);
return CMD_SUCCESS;
}
-DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
+DEFUN_CALL (config_terminal_no_length, config_terminal_no_length_cmd,
"terminal no length",
"Set terminal line parameters\n"
NO_STR
"Set number of lines on a screen\n")
{
- vty->lines = -1;
+ vty_set_lines(vty, -1);
return CMD_SUCCESS;
}
-DEFUN (service_terminal_length, service_terminal_length_cmd,
+DEFUN_CALL (service_terminal_length, service_terminal_length_cmd,
"service terminal-length <0-512>",
"Set up miscellaneous service\n"
"System wide terminal length configuration\n"
@@ -3017,7 +3537,7 @@ DEFUN (service_terminal_length, service_terminal_length_cmd,
return CMD_SUCCESS;
}
-DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
+DEFUN_CALL (no_service_terminal_length, no_service_terminal_length_cmd,
"no service terminal-length [<0-512>]",
NO_STR
"Set up miscellaneous service\n"
@@ -3028,7 +3548,7 @@ DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
return CMD_SUCCESS;
}
-DEFUN_HIDDEN (do_echo,
+DEFUN_HID_CALL (do_echo,
echo_cmd,
"echo .MESSAGE",
"Echo a message back to the vty\n"
@@ -3043,7 +3563,7 @@ DEFUN_HIDDEN (do_echo,
return CMD_SUCCESS;
}
-DEFUN (config_logmsg,
+DEFUN_CALL (config_logmsg,
config_logmsg_cmd,
"logmsg "LOG_LEVELS" .MESSAGE",
"Send a message to enabled logging destinations\n"
@@ -3056,76 +3576,79 @@ DEFUN (config_logmsg,
if ((level = level_match(argv[0])) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
- zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
+ message = argv_concat(argv, argc, 1);
+ zlog(NULL, level, "%s", (message ? message : ""));
if (message)
XFREE(MTYPE_TMP, message);
return CMD_SUCCESS;
}
-DEFUN (show_logging,
+DEFUN_CALL (show_logging,
show_logging_cmd,
"show logging",
SHOW_STR
"Show current logging configuration\n")
{
- struct zlog *zl = zlog_default;
-
vty_out (vty, "Syslog logging: ");
- if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) == ZLOG_DISABLED)
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[zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG)],
+ facility_name(zlog_get_facility(NULL)), zlog_get_ident(NULL));
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Stdout logging: ");
- if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) == ZLOG_DISABLED)
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT)]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Monitor logging: ");
- if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) == ZLOG_DISABLED)
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR)]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "File logging: ");
- if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
- !zl->fp)
+ if ((zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) == ZLOG_DISABLED) ||
+ !zlog_is_file(NULL))
vty_out (vty, "disabled");
else
- vty_out (vty, "level %s, filename %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
- zl->filename);
+ {
+ char * filename = zlog_get_filename(NULL);
+ vty_out (vty, "level %s, filename %s",
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_FILE)],
+ filename);
+ free(filename);
+ }
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Protocol name: %s%s",
- zlog_proto_names[zl->protocol], VTY_NEWLINE);
+ zlog_get_proto_name(NULL), VTY_NEWLINE);
vty_out (vty, "Record priority: %s%s",
- (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
+ (zlog_get_record_priority(NULL) ? "enabled" : "disabled"), VTY_NEWLINE);
vty_out (vty, "Timestamp precision: %d%s",
- zl->timestamp_precision, VTY_NEWLINE);
+ zlog_get_timestamp_precision(NULL), VTY_NEWLINE);
return CMD_SUCCESS;
}
-DEFUN (config_log_stdout,
+DEFUN_CALL (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);
+ zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
-DEFUN (config_log_stdout_level,
+DEFUN_CALL (config_log_stdout_level,
config_log_stdout_level_cmd,
"log stdout "LOG_LEVELS,
"Logging control\n"
@@ -3140,7 +3663,7 @@ DEFUN (config_log_stdout_level,
return CMD_SUCCESS;
}
-DEFUN (no_config_log_stdout,
+DEFUN_CALL (no_config_log_stdout,
no_config_log_stdout_cmd,
"no log stdout [LEVEL]",
NO_STR
@@ -3152,17 +3675,17 @@ DEFUN (no_config_log_stdout,
return CMD_SUCCESS;
}
-DEFUN (config_log_monitor,
+DEFUN_CALL (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);
+ zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
-DEFUN (config_log_monitor_level,
+DEFUN_CALL (config_log_monitor_level,
config_log_monitor_level_cmd,
"log monitor "LOG_LEVELS,
"Logging control\n"
@@ -3177,7 +3700,7 @@ DEFUN (config_log_monitor_level,
return CMD_SUCCESS;
}
-DEFUN (no_config_log_monitor,
+DEFUN_CALL (no_config_log_monitor,
no_config_log_monitor_cmd,
"no log monitor [LEVEL]",
NO_STR
@@ -3195,19 +3718,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)
{
@@ -3239,17 +3762,17 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
return CMD_SUCCESS;
}
-DEFUN (config_log_file,
+DEFUN_CALL (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);
+ return set_log_file(vty, argv[0], zlog_get_default_lvl(NULL));
}
-DEFUN (config_log_file_level,
+DEFUN_CALL (config_log_file_level,
config_log_file_level_cmd,
"log file FILENAME "LOG_LEVELS,
"Logging control\n"
@@ -3264,7 +3787,7 @@ DEFUN (config_log_file_level,
return set_log_file(vty, argv[0], level);
}
-DEFUN (no_config_log_file,
+DEFUN_CALL (no_config_log_file,
no_config_log_file_cmd,
"no log file [FILENAME]",
NO_STR
@@ -3282,7 +3805,7 @@ DEFUN (no_config_log_file,
return CMD_SUCCESS;
}
-ALIAS (no_config_log_file,
+ALIAS_CALL (no_config_log_file,
no_config_log_file_level_cmd,
"no log file FILENAME LEVEL",
NO_STR
@@ -3291,17 +3814,17 @@ ALIAS (no_config_log_file,
"Logging file name\n"
"Logging level\n")
-DEFUN (config_log_syslog,
+DEFUN_CALL (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);
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
-DEFUN (config_log_syslog_level,
+DEFUN_CALL (config_log_syslog_level,
config_log_syslog_level_cmd,
"log syslog "LOG_LEVELS,
"Logging control\n"
@@ -3316,7 +3839,7 @@ DEFUN (config_log_syslog_level,
return CMD_SUCCESS;
}
-DEFUN_DEPRECATED (config_log_syslog_facility,
+DEFUN_DEP_CALL (config_log_syslog_facility,
config_log_syslog_facility_cmd,
"log syslog facility "LOG_FACILITIES,
"Logging control\n"
@@ -3329,12 +3852,12 @@ DEFUN_DEPRECATED (config_log_syslog_facility,
if ((facility = facility_match(argv[0])) < 0)
return CMD_ERR_NO_MATCH;
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
- zlog_default->facility = facility;
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_get_default_lvl(NULL));
+ zlog_set_facility(NULL, facility);
return CMD_SUCCESS;
}
-DEFUN (no_config_log_syslog,
+DEFUN_CALL (no_config_log_syslog,
no_config_log_syslog_cmd,
"no log syslog [LEVEL]",
NO_STR
@@ -3346,7 +3869,7 @@ DEFUN (no_config_log_syslog,
return CMD_SUCCESS;
}
-ALIAS (no_config_log_syslog,
+ALIAS_CALL (no_config_log_syslog,
no_config_log_syslog_facility_cmd,
"no log syslog facility "LOG_FACILITIES,
NO_STR
@@ -3355,7 +3878,7 @@ ALIAS (no_config_log_syslog,
"Facility parameter for syslog messages\n"
LOG_FACILITY_DESC)
-DEFUN (config_log_facility,
+DEFUN_CALL (config_log_facility,
config_log_facility_cmd,
"log facility "LOG_FACILITIES,
"Logging control\n"
@@ -3366,11 +3889,11 @@ DEFUN (config_log_facility,
if ((facility = facility_match(argv[0])) < 0)
return CMD_ERR_NO_MATCH;
- zlog_default->facility = facility;
+ zlog_set_facility(NULL, facility);
return CMD_SUCCESS;
}
-DEFUN (no_config_log_facility,
+DEFUN_CALL (no_config_log_facility,
no_config_log_facility_cmd,
"no log facility [FACILITY]",
NO_STR
@@ -3378,11 +3901,11 @@ DEFUN (no_config_log_facility,
"Reset syslog facility to default (daemon)\n"
"Syslog facility\n")
{
- zlog_default->facility = LOG_DAEMON;
+ zlog_set_facility(NULL, LOG_DAEMON);
return CMD_SUCCESS;
}
-DEFUN_DEPRECATED (config_log_trap,
+DEFUN_DEP_CALL (config_log_trap,
config_log_trap_cmd,
"log trap "LOG_LEVELS,
"Logging control\n"
@@ -3390,19 +3913,15 @@ DEFUN_DEPRECATED (config_log_trap,
LOG_LEVEL_DESC)
{
int new_level ;
- int i;
-
+
if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
- zlog_default->default_lvl = new_level;
- for (i = 0; i < ZLOG_NUM_DESTS; i++)
- if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
- zlog_default->maxlvl[i] = new_level;
+ zlog_set_default_lvl_dest (NULL, new_level);
return CMD_SUCCESS;
}
-DEFUN_DEPRECATED (no_config_log_trap,
+DEFUN_DEP_CALL (no_config_log_trap,
no_config_log_trap_cmd,
"no log trap [LEVEL]",
NO_STR
@@ -3410,32 +3929,32 @@ DEFUN_DEPRECATED (no_config_log_trap,
"Permit all logging information\n"
"Logging level\n")
{
- zlog_default->default_lvl = LOG_DEBUG;
+ zlog_set_default_lvl(NULL, LOG_DEBUG);
return CMD_SUCCESS;
}
-DEFUN (config_log_record_priority,
+DEFUN_CALL (config_log_record_priority,
config_log_record_priority_cmd,
"log record-priority",
"Logging control\n"
"Log the priority of the message within the message\n")
{
- zlog_default->record_priority = 1 ;
+ zlog_set_record_priority(NULL, 1) ;
return CMD_SUCCESS;
}
-DEFUN (no_config_log_record_priority,
+DEFUN_CALL (no_config_log_record_priority,
no_config_log_record_priority_cmd,
"no log record-priority",
NO_STR
"Logging control\n"
"Do not log the priority of the message within the message\n")
{
- zlog_default->record_priority = 0 ;
+ zlog_set_record_priority(NULL, 0) ;
return CMD_SUCCESS;
}
-DEFUN (config_log_timestamp_precision,
+DEFUN_CALL (config_log_timestamp_precision,
config_log_timestamp_precision_cmd,
"log timestamp precision <0-6>",
"Logging control\n"
@@ -3443,6 +3962,8 @@ DEFUN (config_log_timestamp_precision,
"Set the timestamp precision\n"
"Number of subsecond digits\n")
{
+ int timestamp_precision;
+
if (argc != 1)
{
vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
@@ -3450,11 +3971,13 @@ DEFUN (config_log_timestamp_precision,
}
VTY_GET_INTEGER_RANGE("Timestamp Precision",
- zlog_default->timestamp_precision, argv[0], 0, 6);
+ timestamp_precision, argv[0], 0, 6);
+ zlog_set_timestamp_precision(NULL, timestamp_precision);
+
return CMD_SUCCESS;
}
-DEFUN (no_config_log_timestamp_precision,
+DEFUN_CALL (no_config_log_timestamp_precision,
no_config_log_timestamp_precision_cmd,
"no log timestamp precision",
NO_STR
@@ -3462,11 +3985,11 @@ DEFUN (no_config_log_timestamp_precision,
"Timestamp configuration\n"
"Reset the timestamp precision to the default value of 0\n")
{
- zlog_default->timestamp_precision = 0 ;
+ zlog_set_timestamp_precision(NULL, 0);
return CMD_SUCCESS;
}
-DEFUN (banner_motd_file,
+DEFUN_CALL (banner_motd_file,
banner_motd_file_cmd,
"banner motd file [FILE]",
"Set banner\n"
@@ -3481,7 +4004,7 @@ DEFUN (banner_motd_file,
return CMD_SUCCESS;
}
-DEFUN (banner_motd_default,
+DEFUN_CALL (banner_motd_default,
banner_motd_default_cmd,
"banner motd default",
"Set banner string\n"
@@ -3492,7 +4015,7 @@ DEFUN (banner_motd_default,
return CMD_SUCCESS;
}
-DEFUN (no_banner_motd,
+DEFUN_CALL (no_banner_motd,
no_banner_motd_cmd,
"no banner motd",
NO_STR
@@ -3500,7 +4023,7 @@ 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;
@@ -3540,7 +4063,7 @@ cmd_init (int terminal)
desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
/* Allocate initial top vector of commands. */
- cmdvec = vector_init (VECTOR_MIN_SIZE);
+ cmdvec = vector_init (0);
/* Default host value settings. */
host.name = NULL;
@@ -3604,7 +4127,7 @@ cmd_init (int terminal)
install_default (CONFIG_NODE);
}
-
+
install_element (CONFIG_NODE, &hostname_cmd);
install_element (CONFIG_NODE, &no_hostname_cmd);
@@ -3669,39 +4192,52 @@ cmd_terminate ()
if (cmdvec)
{
- for (i = 0; i < vector_active (cmdvec); i++)
- if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
- {
- cmd_node_v = cmd_node->cmd_vector;
+ for (i = 0; i < vector_length (cmdvec); i++)
+ {
+ cmd_node = vector_get_item (cmdvec, i) ;
+ if (cmd_node == NULL)
+ continue ;
- for (j = 0; j < vector_active (cmd_node_v); j++)
- if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
- cmd_element->strvec != NULL)
- {
- cmd_element_v = cmd_element->strvec;
-
- for (k = 0; k < vector_active (cmd_element_v); k++)
- if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
- {
- for (l = 0; l < vector_active (desc_v); l++)
- if ((desc = vector_slot (desc_v, l)) != NULL)
- {
- if (desc->cmd)
- XFREE (MTYPE_STRVEC, desc->cmd);
- if (desc->str)
- XFREE (MTYPE_STRVEC, desc->str);
-
- XFREE (MTYPE_DESC, desc);
- }
- vector_free (desc_v);
- }
-
- cmd_element->strvec = NULL;
- vector_free (cmd_element_v);
- }
+ cmd_node_v = cmd_node->cmd_vector;
+
+ for (j = 0; j < vector_length (cmd_node_v); j++)
+ {
+ cmd_element = vector_get_item (cmd_node_v, j) ;
+ if (cmd_element == NULL)
+ continue ;
- vector_free (cmd_node_v);
- }
+ cmd_element_v = cmd_element->strvec ;
+ if (cmd_element_v == NULL)
+ continue ;
+
+ for (k = 0; k < vector_length (cmd_element_v); k++)
+ {
+ desc_v = vector_get_item (cmd_element_v, k) ;
+ if (desc_v == NULL)
+ continue ;
+
+ for (l = 0; l < vector_length (desc_v); l++)
+ {
+ desc = vector_get_item (desc_v, l) ;
+ if (desc == NULL)
+ continue ;
+
+ if (desc->cmd)
+ XFREE (MTYPE_STRVEC, desc->cmd);
+ if (desc->str)
+ XFREE (MTYPE_STRVEC, desc->str);
+
+ XFREE (MTYPE_DESC, desc);
+ } ;
+ vector_free (desc_v);
+ } ;
+
+ cmd_element->strvec = NULL;
+ vector_free (cmd_element_v);
+ } ;
+
+ vector_free (cmd_node_v);
+ } ;
vector_free (cmdvec);
cmdvec = NULL;