summaryrefslogtreecommitdiff
path: root/lib/command.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /lib/command.c
Initial revision
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c2981
1 files changed, 2981 insertions, 0 deletions
diff --git a/lib/command.c b/lib/command.c
new file mode 100644
index 00000000..8cbecce1
--- /dev/null
+++ b/lib/command.c
@@ -0,0 +1,2981 @@
+/* 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
+option) any later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "log.h"
+#include "version.h"
+
+/* Command vector which includes some level of command lists. Normally
+ each daemon maintains each own cmdvec. */
+vector cmdvec;
+
+/* Host information structure. */
+struct host host;
+
+/* Default motd string. */
+char *default_motd =
+"\r\n\
+Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\
+Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
+\r\n";
+
+/* Standard command node structures. */
+struct cmd_node auth_node =
+{
+ AUTH_NODE,
+ "Password: ",
+};
+
+struct cmd_node view_node =
+{
+ VIEW_NODE,
+ "%s> ",
+};
+
+struct cmd_node auth_enable_node =
+{
+ AUTH_ENABLE_NODE,
+ "Password: ",
+};
+
+struct cmd_node enable_node =
+{
+ ENABLE_NODE,
+ "%s# ",
+};
+
+struct cmd_node config_node =
+{
+ CONFIG_NODE,
+ "%s(config)# ",
+ 1
+};
+
+/* Utility function to concatenate argv argument into a single string
+ with inserting ' ' character between each argument. */
+char *
+argv_concat (char **argv, int argc, int shift)
+{
+ int i;
+ int len;
+ int index;
+ char *str;
+
+ str = NULL;
+ index = 0;
+
+ for (i = shift; i < argc; i++)
+ {
+ len = strlen (argv[i]);
+
+ if (i == shift)
+ {
+ str = XSTRDUP (MTYPE_TMP, argv[i]);
+ index = len;
+ }
+ else
+ {
+ str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
+ str[index++] = ' ';
+ memcpy (str + index, argv[i], len);
+ index += len;
+ str[index] = '\0';
+ }
+ }
+ 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);
+}
+
+/* Compare two command's string. Used in sort_node (). */
+int
+cmp_node (const void *p, const void *q)
+{
+ struct cmd_element *a = *(struct cmd_element **)p;
+ struct cmd_element *b = *(struct cmd_element **)q;
+
+ return strcmp (a->string, b->string);
+}
+
+int
+cmp_desc (const void *p, const void *q)
+{
+ struct desc *a = *(struct desc **)p;
+ struct desc *b = *(struct desc **)q;
+
+ return strcmp (a->cmd, b->cmd);
+}
+
+/* Sort each node's command element according to command string. */
+void
+sort_node ()
+{
+ int i, j;
+ struct cmd_node *cnode;
+ vector descvec;
+ struct cmd_element *cmd_element;
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((cnode = vector_slot (cmdvec, i)) != NULL)
+ {
+ vector cmd_vector = cnode->cmd_vector;
+ qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
+ }
+ }
+}
+
+/* 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 (char *string)
+{
+ char *cp, *start, *token;
+ int strlen;
+ vector strvec;
+
+ if (string == NULL)
+ return NULL;
+
+ cp = string;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ if (*cp == '!' || *cp == '#')
+ return NULL;
+
+ /* Prepare return vector. */
+ strvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Copy each command piece and set into vector. */
+ while (1)
+ {
+ start = cp;
+ while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
+ *cp != '\0')
+ cp++;
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+ vector_set (strvec, token);
+
+ while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
+ *cp != '\0')
+ cp++;
+
+ if (*cp == '\0')
+ return strvec;
+ }
+}
+
+/* Free allocated string vector. */
+void
+cmd_free_strvec (vector v)
+{
+ int i;
+ char *cp;
+
+ if (!v)
+ return;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cp = vector_slot (v, i)) != NULL)
+ XFREE (MTYPE_STRVEC, cp);
+
+ vector_free (v);
+}
+
+/* Fetch next description. Used in cmd_make_descvec(). */
+char *
+cmd_desc_str (char **string)
+{
+ char *cp, *start, *token;
+ int strlen;
+
+ cp = *string;
+
+ if (cp == NULL)
+ return NULL;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ start = cp;
+
+ while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
+ cp++;
+
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+
+ *string = cp;
+
+ return token;
+}
+
+/* New string vector. */
+vector
+cmd_make_descvec (char *string, char *descstr)
+{
+ int multiple = 0;
+ char *sp;
+ char *token;
+ int len;
+ char *cp;
+ char *dp;
+ vector allvec;
+ vector strvec = NULL;
+ struct desc *desc;
+
+ cp = string;
+ dp = descstr;
+
+ if (cp == NULL)
+ return NULL;
+
+ allvec = vector_init (VECTOR_MIN_SIZE);
+
+ while (1)
+ {
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+ if (*cp == ')')
+ {
+ multiple = 0;
+ cp++;
+ }
+ if (*cp == '|')
+ {
+ if (! multiple)
+ {
+ fprintf (stderr, "Command parse error!: %s\n", string);
+ exit (1);
+ }
+ cp++;
+ }
+
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+
+ if (*cp == '\0')
+ return allvec;
+
+ sp = cp;
+
+ while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
+ cp++;
+
+ len = cp - sp;
+
+ token = XMALLOC (MTYPE_STRVEC, len + 1);
+ memcpy (token, sp, len);
+ *(token + len) = '\0';
+
+ desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
+ desc->cmd = token;
+ desc->str = cmd_desc_str (&dp);
+
+ if (multiple)
+ {
+ if (multiple == 1)
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ multiple++;
+ }
+ else
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ vector_set (strvec, desc);
+ }
+}
+
+/* Count mandantory string vector size. This is to determine inputed
+ command has enough command length. */
+int
+cmd_cmdsize (vector strvec)
+{
+ int i;
+ char *str;
+ int size = 0;
+ vector descvec;
+
+ for (i = 0; i < vector_max (strvec); i++)
+ {
+ descvec = vector_slot (strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+
+ str = desc->cmd;
+
+ if (str == NULL || CMD_OPTION (str))
+ return size;
+ else
+ size++;
+ }
+ else
+ size++;
+ }
+ return size;
+}
+
+/* Return prompt character of specified node. */
+char *
+cmd_prompt (enum node_type node)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, node);
+ return cnode->prompt;
+}
+
+/* Install a command into a node. */
+void
+install_element (enum node_type ntype, struct cmd_element *cmd)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, ntype);
+
+ if (cnode == NULL)
+ {
+ fprintf (stderr, "Command node %d doesn't exist, please check it\n",
+ ntype);
+ exit (1);
+ }
+
+ vector_set (cnode->cmd_vector, cmd);
+
+ cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
+ cmd->cmdsize = cmd_cmdsize (cmd->strvec);
+}
+
+static unsigned char itoa64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+to64(char *s, long v, int n)
+{
+ while (--n >= 0)
+ {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+char *zencrypt (char *passwd)
+{
+ char salt[6];
+ struct timeval tv;
+ char *crypt (const char *, const char *);
+
+ gettimeofday(&tv,0);
+
+ to64(&salt[0], random(), 3);
+ to64(&salt[3], tv.tv_usec, 3);
+ salt[5] = '\0';
+
+ return crypt (passwd, salt);
+}
+
+/* This function write configuration of this host. */
+int
+config_write_host (struct vty *vty)
+{
+ 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);
+ if (host.enable_encrypt)
+ vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
+ }
+ else
+ {
+ if (host.password)
+ vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
+ if (host.enable)
+ vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
+ }
+
+ if (host.logfile)
+ vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
+
+ if (host.log_stdout)
+ vty_out (vty, "log stdout%s", VTY_NEWLINE);
+
+ if (host.log_syslog)
+ vty_out (vty, "log syslog%s", VTY_NEWLINE);
+
+ if (zlog_default->maskpri != LOG_DEBUG)
+ vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
+
+ if (zlog_default->record_priority == 1)
+ vty_out (vty, "log record-priority%s", VTY_NEWLINE);
+
+ if (host.advanced)
+ vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
+
+ if (host.encrypt)
+ vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
+
+ if (host.lines >= 0)
+ vty_out (vty, "service terminal-length %d%s", host.lines,
+ VTY_NEWLINE);
+
+ if (! host.motd)
+ vty_out (vty, "no banner motd%s", VTY_NEWLINE);
+
+ return 1;
+}
+
+/* Utility function for getting command vector. */
+vector
+cmd_node_vector (vector v, enum node_type ntype)
+{
+ struct cmd_node *cnode = vector_slot (v, ntype);
+ return cnode->cmd_vector;
+}
+
+/* Filter command vector by symbol */
+int
+cmd_filter_by_symbol (char *command, char *symbol)
+{
+ int i, lim;
+
+ if (strcmp (symbol, "IPV4_ADDRESS") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "STRING") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "IFNAME") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! isalnum ((int) command[i]))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* Completion match types. */
+enum match_type
+{
+ no_match,
+ extend_match,
+ ipv4_prefix_match,
+ ipv4_match,
+ ipv6_prefix_match,
+ ipv6_match,
+ range_match,
+ vararg_match,
+ partly_match,
+ exact_match
+};
+
+enum match_type
+cmd_ipv4_match (char *str)
+{
+ char *sp;
+ int dots = 0, nums = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0')
+ {
+ if (*str == '.')
+ {
+ if (dots >= 3)
+ return no_match;
+
+ if (*(str + 1) == '.')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ nums++;
+
+ if (*str == '\0')
+ break;
+
+ str++;
+ }
+
+ if (nums < 4)
+ return partly_match;
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv4_prefix_match (char *str)
+{
+ char *sp;
+ int dots = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0' && *str != '/')
+ {
+ if (*str == '.')
+ {
+ if (dots == 3)
+ return no_match;
+
+ if (*(str + 1) == '.' || *(str + 1) == '/')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ if (dots == 3)
+ {
+ if (*str == '/')
+ {
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ str++;
+ break;
+ }
+ else if (*str == '\0')
+ return partly_match;
+ }
+
+ if (*str == '\0')
+ return partly_match;
+
+ str++;
+ }
+
+ sp = str;
+ while (*str != '\0')
+ {
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (atoi (sp) > 32)
+ return no_match;
+
+ return exact_match;
+}
+
+#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
+#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
+#define STATE_START 1
+#define STATE_COLON 2
+#define STATE_DOUBLE 3
+#define STATE_ADDR 4
+#define STATE_DOT 5
+#define STATE_SLASH 6
+#define STATE_MASK 7
+
+enum match_type
+cmd_ipv6_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ char *sp = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_ADDR_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0')
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0')
+ colons++;
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums++;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '\0')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ nums++;
+ state = STATE_COLON;
+ }
+ if (*(str + 1) == '.')
+ state = STATE_DOT;
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 8)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+#if 0
+ if (nums < 11)
+ return partly_match;
+#endif /* 0 */
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv6_prefix_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ int mask;
+ char *sp = NULL;
+ char *endptr = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0' && state != STATE_MASK)
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == '/')
+ return no_match;
+ else if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0' && *(str + 1) != '/')
+ colons++;
+ sp = str + 1;
+
+ if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ else
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums += 1;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '.'
+ || *(str + 1) == '\0' || *(str + 1) == '/')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ for (; sp <= str; sp++)
+ if (*sp == '/')
+ return no_match;
+
+ nums++;
+
+ if (*(str + 1) == ':')
+ state = STATE_COLON;
+ else if (*(str + 1) == '.')
+ state = STATE_DOT;
+ else if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ }
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ case STATE_SLASH:
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ state = STATE_MASK;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 11)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+ if (state < STATE_MASK)
+ return partly_match;
+
+ mask = strtol (str, &endptr, 10);
+ if (*endptr != '\0')
+ return no_match;
+
+ 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
+ yasu
+ if (mask < 13)
+ return partly_match;
+*/
+
+ return exact_match;
+}
+
+#define DECIMAL_STRLEN_MAX 10
+
+int
+cmd_range_match (char *range, char *str)
+{
+ char *p;
+ char buf[DECIMAL_STRLEN_MAX + 1];
+ char *endptr = NULL;
+ unsigned long min, max, val;
+
+ if (str == NULL)
+ return 1;
+
+ val = strtoul (str, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range++;
+ p = strchr (range, '-');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ min = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range = p + 1;
+ p = strchr (range, '>');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ max = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ if (val < min || val > max)
+ return 0;
+
+ return 1;
+}
+
+/* Make completion match and return match type flag. */
+enum match_type
+cmd_filter_by_completion (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ 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_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ if (index >= vector_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ 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;
+
+ matched++;
+ }
+ }
+ 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_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;
+}
+
+/* Filter vector by command character with index. */
+enum match_type
+cmd_filter_by_string (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ 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_max (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_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ 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;
+ matched++;
+ }
+ }
+ 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++;
+ }
+ }
+ 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 */
+int
+is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
+{
+ int i;
+ int j;
+ char *str = NULL;
+ struct cmd_element *cmd_element;
+ char *matched = NULL;
+ vector descvec;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ int match = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ enum match_type ret;
+
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ 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;
+ 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. */
+
+ match++;
+ }
+ break;
+ 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;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+char *
+cmd_entry_function (char *src, 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))
+ return NULL;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ /* Matched with input string. */
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+
+ return NULL;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+/* This version will return the dst string always if it is
+ CMD_VARIABLE for '?' key processing */
+char *
+cmd_entry_function_desc (char *src, char *dst)
+{
+ if (CMD_VARARG (dst))
+ return dst;
+
+ if (CMD_RANGE (dst))
+ {
+ if (cmd_range_match (dst, src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6 (dst))
+ {
+ if (cmd_ipv6_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6_PREFIX (dst))
+ {
+ if (cmd_ipv6_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4 (dst))
+ {
+ if (cmd_ipv4_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4_PREFIX (dst))
+ {
+ if (cmd_ipv4_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ /* Optional or variable commands always match on '?' */
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
+ return dst;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+ else
+ return NULL;
+}
+
+/* Check same string element existence. If it isn't there return
+ 1. */
+int
+cmd_unique_string (vector v, char *str)
+{
+ int i;
+ char *match;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((match = vector_slot (v, i)) != NULL)
+ if (strcmp (match, str) == 0)
+ return 0;
+ return 1;
+}
+
+/* Compare string to description vector. If there is same string
+ return 1 else return 0. */
+int
+desc_unique_string (vector v, char *str)
+{
+ int i;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((desc = vector_slot (v, i)) != NULL)
+ if (strcmp (desc->cmd, str) == 0)
+ return 1;
+ return 0;
+}
+
+/* '?' describe command support. */
+vector
+cmd_describe_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector;
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index;
+ static struct desc desc_cr = { "<cr>", "" };
+
+ /* Set index. */
+ index = vector_max (vline) - 1;
+
+ /* Make copy vector of current node's command vector. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ /* Prepare match vector */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Filter commands. */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ char *command;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ if (match == vararg_match)
+ {
+ struct cmd_element *cmd_element;
+ vector descvec;
+ int j, k;
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ for (k = 0; k < vector_max (descvec); k++)
+ {
+ struct desc *desc = vector_slot (descvec, k);
+ vector_set (matchvec, desc);
+ }
+ }
+
+ vector_set (matchvec, &desc_cr);
+
+ vector_free (cmd_vector);
+
+ return matchvec;
+ }
+
+ 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);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ }
+
+ /* Prepare match vector */
+ /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
+
+ /* Make description vector. */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string = NULL;
+ vector strvec = cmd_element->strvec;
+
+ if (index > vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ /* Check is command is completed. */
+ if (index == vector_max (strvec))
+ {
+ string = "<cr>";
+ if (! desc_unique_string (matchvec, string))
+ vector_set (matchvec, &desc_cr);
+ }
+ else
+ {
+ int j;
+ vector descvec = vector_slot (strvec, index);
+ struct desc *desc;
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ string = cmd_entry_function_desc (vector_slot (vline, index), 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)
+ {
+ vector_free (matchvec);
+ *status= CMD_ERR_NO_MATCH;
+ }
+ else
+ *status = CMD_SUCCESS;
+
+ return matchvec;
+}
+
+/* Check LCD of matched command. */
+int
+cmd_lcd (char **matched)
+{
+ int i;
+ int j;
+ int lcd = -1;
+ char *s1, *s2;
+ char c1, c2;
+
+ if (matched[0] == NULL || matched[1] == NULL)
+ return 0;
+
+ for (i = 1; matched[i] != NULL; i++)
+ {
+ s1 = matched[i - 1];
+ s2 = matched[i];
+
+ for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
+ if (c1 != c2)
+ break;
+
+ if (lcd < 0)
+ lcd = j;
+ else
+ {
+ if (lcd > j)
+ lcd = j;
+ }
+ }
+ return lcd;
+}
+
+/* Command line completion support. */
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index = vector_max (vline) - 1;
+ char **match_str;
+ struct desc *desc;
+ vector descvec;
+ char *command;
+ int lcd;
+
+ /* First, filter by preceeding command string */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ /* First try completion match, if there is exactly match return 1 */
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ /* 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);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ */
+ }
+
+ /* Prepare match vector. */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Now we got into completion */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string;
+ vector strvec = cmd_element->strvec;
+
+ /* Check field length */
+ if (index >= vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ int j;
+
+ descvec = vector_slot (strvec, index);
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ 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));
+ }
+ }
+ }
+
+ /* We don't need cmd_vector any more. */
+ vector_free (cmd_vector);
+
+ /* No matched command */
+ if (vector_slot (matchvec, 0) == NULL)
+ {
+ vector_free (matchvec);
+
+ /* In case of 'command \t' pattern. Do you need '?' command at
+ the end of the line. */
+ if (vector_slot (vline, index) == '\0')
+ *status = CMD_ERR_NOTHING_TODO;
+ else
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+
+ /* Only one matched */
+ if (vector_slot (matchvec, 1) == NULL)
+ {
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_FULL_MATCH;
+ return match_str;
+ }
+ /* Make it sure last element is NULL. */
+ vector_set (matchvec, NULL);
+
+ /* Check LCD of matched strings. */
+ if (vector_slot (vline, index) != NULL)
+ {
+ lcd = cmd_lcd ((char **) matchvec->index);
+
+ if (lcd)
+ {
+ int len = strlen (vector_slot (vline, index));
+
+ if (len < lcd)
+ {
+ char *lcdstr;
+
+ lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
+ memcpy (lcdstr, matchvec->index[0], lcd);
+ lcdstr[lcd] = '\0';
+
+ /* match_str = (char **) &lcdstr; */
+
+ /* Free matchvec. */
+ for (i = 0; i < vector_max (matchvec); i++)
+ {
+ if (vector_slot (matchvec, i))
+ XFREE (MTYPE_TMP, 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);
+
+ *status = CMD_COMPLETE_MATCH;
+ return match_str;
+ }
+ }
+ }
+
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_LIST_MATCH;
+ return match_str;
+}
+
+/* Execute command by argument vline vector. */
+int
+cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ enum match_type match = 0;
+ int varflag;
+ char *command;
+
+ /* Make copy of command elements. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_completion (command, cmd_vector, index);
+
+ 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;
+ }
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_NO_MATCH;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ 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++;
+ }
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Execute matched command. */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Execute command by argument readline. */
+int
+cmd_execute_command_strict (vector vline, struct vty *vty,
+ struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ int varflag;
+ enum match_type match = 0;
+ char *command;
+
+ /* Make copy of command element */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_string (vector_slot (vline, index),
+ cmd_vector, index);
+
+ /* 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;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ cmd_element = vector_slot (cmd_vector,i);
+
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+ matched_count++;
+ }
+ else
+ incomplete_count++;
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Now execute matched command */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Configration make from file. */
+int
+config_from_file (struct vty *vty, FILE *fp)
+{
+ int ret;
+ vector vline;
+
+ while (fgets (vty->buf, VTY_BUFSIZ, fp))
+ {
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of comment line */
+ if (vline == NULL)
+ continue;
+ /* Execute configuration command : this is strict match */
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ /* Try again with setting node to CONFIG_NODE */
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ if (vty->node == KEYCHAIN_KEY_NODE)
+ {
+ vty->node = KEYCHAIN_NODE;
+
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+ else
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+
+ cmd_free_strvec (vline);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ return ret;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Configration from terminal */
+DEFUN (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;
+}
+
+/* Enable command */
+DEFUN (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;
+ else
+ vty->node = AUTH_ENABLE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+/* Disable command */
+DEFUN (disable,
+ config_disable_cmd,
+ "disable",
+ "Turn off privileged mode command\n")
+{
+ if (vty->node == ENABLE_NODE)
+ vty->node = VIEW_NODE;
+ return CMD_SUCCESS;
+}
+
+/* Down vty node level. */
+DEFUN (config_exit,
+ config_exit_cmd,
+ "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_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 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:
+ vty->node = BGP_NODE;
+ break;
+ case KEYCHAIN_KEY_NODE:
+ vty->node = KEYCHAIN_NODE;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* quit is alias of exit. */
+ALIAS (config_exit,
+ config_quit_cmd,
+ "quit",
+ "Exit current mode and down to previous mode\n")
+
+/* End of configuration. */
+DEFUN (config_end,
+ config_end_cmd,
+ "end",
+ "End current mode and change to enable mode.")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_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 RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_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;
+}
+
+/* Show version. */
+DEFUN (show_version,
+ show_version_cmd,
+ "show version",
+ SHOW_STR
+ "Displays zebra version\n")
+{
+ vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
+ host_name,
+ VTY_NEWLINE);
+ vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_help,
+ config_help_cmd,
+ "help",
+ "Description of the interactive help system\n")
+{
+ vty_out (vty,
+ "Zebra VTY provides advanced help feature. When you need help,%s\
+anytime at the command line please press '?'.%s\
+%s\
+If nothing matches, the help list will be empty and you must backup%s\
+ until entering a '?' shows the available options.%s\
+Two styles of help are provided:%s\
+1. Full help is available when you are ready to enter a%s\
+command argument (e.g. 'show ?') and describes each possible%s\
+argument.%s\
+2. Partial help is provided when an abbreviated argument is entered%s\
+ and you want to know what arguments match the input%s\
+ (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_list,
+ config_list_cmd,
+ "list",
+ "Print command list\n")
+{
+ int i;
+ struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
+ struct cmd_element *cmd;
+
+ for (i = 0; i < vector_max (cnode->cmd_vector); i++)
+ if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
+ vty_out (vty, " %s%s", cmd->string,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into file. */
+DEFUN (config_write_file,
+ config_write_file_cmd,
+ "write file",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to configuration file\n")
+{
+ int i;
+ int fd;
+ struct cmd_node *node;
+ char *config_file;
+ char *config_file_tmp = NULL;
+ char *config_file_sav = NULL;
+ struct vty *file_vty;
+
+ /* Check and see if we are operating under vtysh configuration */
+ if (host.config == NULL)
+ {
+ vty_out (vty, "Can't save to configuration file, using vtysh.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get filename. */
+ config_file = host.config;
+
+ config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
+ strcpy (config_file_sav, config_file);
+ strcat (config_file_sav, CONF_BACKUP_EXT);
+
+
+ config_file_tmp = malloc (strlen (config_file) + 8);
+ sprintf (config_file_tmp, "%s.XXXXXX", config_file);
+
+ /* Open file to configuration write. */
+ fd = mkstemp (config_file_tmp);
+ if (fd < 0)
+ {
+ vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
+ VTY_NEWLINE);
+ free (config_file_tmp);
+ free (config_file_sav);
+ return CMD_WARNING;
+ }
+
+ /* Make vty for configuration file. */
+ file_vty = vty_new ();
+ file_vty->fd = fd;
+ file_vty->type = VTY_FILE;
+
+ /* 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");
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (file_vty))
+ vty_out (file_vty, "!\n");
+ }
+ vty_close (file_vty);
+
+ 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);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file, config_file_sav) != 0)
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ sync ();
+ if (unlink (config_file) != 0)
+ {
+ vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file_tmp, config_file) != 0)
+ {
+ vty_out (vty, "Can't save configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ unlink (config_file_tmp);
+ sync ();
+
+ free (config_file_sav);
+ free (config_file_tmp);
+ vty_out (vty, "Configuration saved to %s%s", config_file,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_write_file,
+ config_write_cmd,
+ "write",
+ "Write running configuration to memory, network, or terminal\n")
+
+ALIAS (config_write_file,
+ config_write_memory_cmd,
+ "write memory",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write configuration to the file (same as write file)\n")
+
+ALIAS (config_write_file,
+ copy_runningconfig_startupconfig_cmd,
+ "copy running-config startup-config",
+ "Copy configuration\n"
+ "Copy running config to... \n"
+ "Copy running config to startup config (same as write file)\n")
+
+/* Write current configuration into the terminal. */
+DEFUN (config_write_terminal,
+ config_write_terminal_cmd,
+ "write terminal",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to terminal\n")
+{
+ int i;
+ struct cmd_node *node;
+
+ if (vty->type == VTY_SHELL_SERV)
+ {
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ }
+ else
+ {
+ vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+ VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "end%s",VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into the terminal. */
+ALIAS (config_write_terminal,
+ show_running_config_cmd,
+ "show running-config",
+ SHOW_STR
+ "running configuration\n")
+
+/* Write startup configuration into the terminal. */
+DEFUN (show_startup_config,
+ show_startup_config_cmd,
+ "show startup-config",
+ SHOW_STR
+ "Contentes of startup configuration\n")
+{
+ char buf[BUFSIZ];
+ FILE *confp;
+
+ confp = fopen (host.config, "r");
+ if (confp == NULL)
+ {
+ vty_out (vty, "Can't open configuration file [%s]%s",
+ host.config, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ while (fgets (buf, BUFSIZ, confp))
+ {
+ char *cp = buf;
+
+ while (*cp != '\r' && *cp != '\n' && *cp != '\0')
+ cp++;
+ *cp = '\0';
+
+ vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ }
+
+ fclose (confp);
+
+ return CMD_SUCCESS;
+}
+
+/* Hostname configuration */
+DEFUN (config_hostname,
+ hostname_cmd,
+ "hostname WORD",
+ "Set system's network name\n"
+ "This system's network name\n")
+{
+ if (!isalpha((int) *argv[0]))
+ {
+ vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.name)
+ XFREE (0, host.name);
+
+ host.name = strdup (argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_no_hostname,
+ no_hostname_cmd,
+ "no hostname [HOSTNAME]",
+ NO_STR
+ "Reset system's network name\n"
+ "Host name of this router\n")
+{
+ if (host.name)
+ XFREE (0, host.name);
+ host.name = NULL;
+ return CMD_SUCCESS;
+}
+
+/* VTY interface password set. */
+DEFUN (config_password, password_cmd,
+ "password (8|) WORD",
+ "Assign the terminal connection password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN line password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+
+ if (host.encrypt)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.password = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_password, password_text_cmd,
+ "password LINE",
+ "Assign the terminal connection password\n"
+ "The UNENCRYPTED (cleartext) line password\n")
+
+/* VTY enable password set. */
+DEFUN (config_enable_password, enable_password_cmd,
+ "enable password (8|) WORD",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN 'enable' password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Crypt type is specified. */
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, argv[1]);
+
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ /* Plain password input. */
+ if (host.encrypt)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.enable = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_enable_password,
+ enable_password_text_cmd,
+ "enable password LINE",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "The UNENCRYPTED (cleartext) 'enable' password\n")
+
+/* VTY enable password delete. */
+DEFUN (no_config_enable_password, no_enable_password_cmd,
+ "no enable password",
+ NO_STR
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n")
+{
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_password_encrypt,
+ service_password_encrypt_cmd,
+ "service password-encryption",
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 1;
+
+ if (host.password)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
+ }
+ if (host.enable)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_password_encrypt,
+ no_service_password_encrypt_cmd,
+ "no service password-encryption",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (! host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 0;
+
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_length, config_terminal_length_cmd,
+ "terminal length <0-512>",
+ "Set terminal line parameters\n"
+ "Set number of lines on a screen\n"
+ "Number of lines on screen (0 for no pausing)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty->lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (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;
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_terminal_length, service_terminal_length_cmd,
+ "service terminal-length <0-512>",
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ host.lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
+ "no service terminal-length [<0-512>]",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ host.lines = -1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_stdout,
+ config_log_stdout_cmd,
+ "log stdout",
+ "Logging control\n"
+ "Logging goes to stdout\n")
+{
+ zlog_set_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_stdout,
+ no_config_log_stdout_cmd,
+ "no log stdout",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to stdout\n")
+{
+ zlog_reset_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_file,
+ config_log_file_cmd,
+ "log file FILENAME",
+ "Logging control\n"
+ "Logging to file\n"
+ "Logging filename\n")
+{
+ int ret;
+ char *cwd;
+ char *fullpath;
+
+ /* Path detection. */
+ if (! IS_DIRECTORY_SEP (*argv[0]))
+ {
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (argv[0]) + 2);
+ sprintf (fullpath, "%s/%s", cwd, argv[0]);
+ }
+ else
+ fullpath = argv[0];
+
+ ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
+
+ if (!ret)
+ {
+ vty_out (vty, "can't open logfile %s\n", argv[0]);
+ return CMD_WARNING;
+ }
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = strdup (argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_file,
+ no_config_log_file_cmd,
+ "no log file [FILENAME]",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to file\n"
+ "Logging file name\n")
+{
+ zlog_reset_file (NULL);
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_syslog,
+ config_log_syslog_cmd,
+ "log syslog",
+ "Logging control\n"
+ "Logging goes to syslog\n")
+{
+ zlog_set_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_syslog,
+ no_config_log_syslog_cmd,
+ "no log syslog",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to syslog\n")
+{
+ zlog_reset_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_trap,
+ config_log_trap_cmd,
+ "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
+ "Logging control\n"
+ "Limit logging to specifed level\n")
+{
+ int new_level ;
+
+ for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
+ {
+ if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
+ /* found new logging level */
+ {
+ zlog_default->maskpri = new_level;
+ return CMD_SUCCESS;
+ }
+ }
+ return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_config_log_trap,
+ no_config_log_trap_cmd,
+ "no log trap",
+ NO_STR
+ "Logging control\n"
+ "Permit all logging information\n")
+{
+ zlog_default->maskpri = LOG_DEBUG;
+ return CMD_SUCCESS;
+}
+
+DEFUN (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 ;
+ return CMD_SUCCESS;
+}
+
+DEFUN (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 ;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (banner_motd_default,
+ banner_motd_default_cmd,
+ "banner motd default",
+ "Set banner string\n"
+ "Strings for motd\n"
+ "Default string\n")
+{
+ host.motd = default_motd;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_banner_motd,
+ no_banner_motd_cmd,
+ "no banner motd",
+ NO_STR
+ "Set banner string\n"
+ "Strings for motd\n")
+{
+ host.motd = NULL;
+ return CMD_SUCCESS;
+}
+
+/* Set config filename. Called from vty.c */
+void
+host_config_set (char *filename)
+{
+ host.config = strdup (filename);
+}
+
+void
+install_default (enum node_type node)
+{
+ install_element (node, &config_exit_cmd);
+ install_element (node, &config_quit_cmd);
+ install_element (node, &config_end_cmd);
+ install_element (node, &config_help_cmd);
+ install_element (node, &config_list_cmd);
+
+ install_element (node, &config_write_terminal_cmd);
+ install_element (node, &config_write_file_cmd);
+ install_element (node, &config_write_memory_cmd);
+ install_element (node, &config_write_cmd);
+ install_element (node, &show_running_config_cmd);
+}
+
+/* Initialize command interface. Install basic nodes and commands. */
+void
+cmd_init (int terminal)
+{
+ /* Allocate initial top vector of commands. */
+ cmdvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Default host value settings. */
+ host.name = NULL;
+ host.password = NULL;
+ host.enable = NULL;
+ host.logfile = NULL;
+ host.config = NULL;
+ host.lines = -1;
+ host.motd = default_motd;
+
+ /* Install top nodes. */
+ install_node (&view_node, NULL);
+ install_node (&enable_node, NULL);
+ install_node (&auth_node, NULL);
+ install_node (&auth_enable_node, NULL);
+ install_node (&config_node, config_write_host);
+
+ /* Each node's basic commands. */
+ install_element (VIEW_NODE, &show_version_cmd);
+ if (terminal)
+ {
+ install_element (VIEW_NODE, &config_list_cmd);
+ install_element (VIEW_NODE, &config_exit_cmd);
+ install_element (VIEW_NODE, &config_quit_cmd);
+ install_element (VIEW_NODE, &config_help_cmd);
+ install_element (VIEW_NODE, &config_enable_cmd);
+ install_element (VIEW_NODE, &config_terminal_length_cmd);
+ install_element (VIEW_NODE, &config_terminal_no_length_cmd);
+ }
+
+ if (terminal)
+ {
+ install_default (ENABLE_NODE);
+ install_element (ENABLE_NODE, &config_disable_cmd);
+ install_element (ENABLE_NODE, &config_terminal_cmd);
+ install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+ }
+ install_element (ENABLE_NODE, &show_startup_config_cmd);
+ install_element (ENABLE_NODE, &show_version_cmd);
+ install_element (ENABLE_NODE, &config_terminal_length_cmd);
+ install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
+
+ if (terminal)
+ install_default (CONFIG_NODE);
+ install_element (CONFIG_NODE, &hostname_cmd);
+ install_element (CONFIG_NODE, &no_hostname_cmd);
+ install_element (CONFIG_NODE, &password_cmd);
+ install_element (CONFIG_NODE, &password_text_cmd);
+ install_element (CONFIG_NODE, &enable_password_cmd);
+ install_element (CONFIG_NODE, &enable_password_text_cmd);
+ install_element (CONFIG_NODE, &no_enable_password_cmd);
+ if (terminal)
+ {
+ install_element (CONFIG_NODE, &config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &config_log_file_cmd);
+ install_element (CONFIG_NODE, &no_config_log_file_cmd);
+ install_element (CONFIG_NODE, &config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &config_log_trap_cmd);
+ install_element (CONFIG_NODE, &no_config_log_trap_cmd);
+ install_element (CONFIG_NODE, &config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &banner_motd_default_cmd);
+ install_element (CONFIG_NODE, &no_banner_motd_cmd);
+ install_element (CONFIG_NODE, &service_terminal_length_cmd);
+ install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
+ }
+
+ srand(time(NULL));
+}