text: /*
   * 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-2001 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
  };
  
  /* 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);
        bcopy (start, token, strlen);
        *(token + strlen) = '\0';
        vector_set (strvec, token);
  
        while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
  	     *cp != '\0')
  	cp++;
  
        if (*cp == '\0' || *cp == '!' || *cp == '#') 
  	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);
    bcopy (start, token, 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 = XMALLOC (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 (;;)
      {
        bzero (buf, 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 (;;)
      {
        bzero (buf, 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;
      }
  
    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_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_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-2001, 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_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);
  	  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);
  }
  
  /* 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, &show_running_config_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));
  }
  