LCOV - code coverage report
Current view: top level - lib - command.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 664 1794 37.0 %
Date: 2015-11-19 Functions: 42 120 35.0 %

          Line data    Source code
       1             : /*
       2             :    Command interpreter routine for virtual terminal [aka TeletYpe]
       3             :    Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
       4             :    Copyright (C) 2013 by Open Source Routing.
       5             :    Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
       6             : 
       7             : This file is part of GNU Zebra.
       8             :  
       9             : GNU Zebra is free software; you can redistribute it and/or modify
      10             : it under the terms of the GNU General Public License as published
      11             : by the Free Software Foundation; either version 2, or (at your
      12             : option) any later version.
      13             : 
      14             : GNU Zebra is distributed in the hope that it will be useful, but
      15             : WITHOUT ANY WARRANTY; without even the implied warranty of
      16             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             : General Public License for more details.
      18             : 
      19             : You should have received a copy of the GNU General Public License
      20             : along with GNU Zebra; see the file COPYING.  If not, write to the
      21             : Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      22             : Boston, MA 02111-1307, USA.  */
      23             : 
      24             : #include <zebra.h>
      25             : 
      26             : 
      27             : #include "memory.h"
      28             : #include "log.h"
      29             : #include <lib/version.h>
      30             : #include "thread.h"
      31             : #include "vector.h"
      32             : #include "vty.h"
      33             : #include "command.h"
      34             : #include "workqueue.h"
      35             : 
      36             : /* Command vector which includes some level of command lists. Normally
      37             :    each daemon maintains each own cmdvec. */
      38             : vector cmdvec = NULL;
      39             : 
      40             : struct cmd_token token_cr;
      41             : char *command_cr = NULL;
      42             : 
      43             : enum filter_type
      44             : {
      45             :   FILTER_RELAXED,
      46             :   FILTER_STRICT
      47             : };
      48             : 
      49             : enum matcher_rv
      50             : {
      51             :   MATCHER_OK,
      52             :   MATCHER_COMPLETE,
      53             :   MATCHER_INCOMPLETE,
      54             :   MATCHER_NO_MATCH,
      55             :   MATCHER_AMBIGUOUS,
      56             :   MATCHER_EXCEED_ARGC_MAX
      57             : };
      58             : 
      59             : #define MATCHER_ERROR(matcher_rv) \
      60             :   (   (matcher_rv) == MATCHER_INCOMPLETE \
      61             :    || (matcher_rv) == MATCHER_NO_MATCH \
      62             :    || (matcher_rv) == MATCHER_AMBIGUOUS \
      63             :    || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
      64             :   )
      65             : 
      66             : /* Host information structure. */
      67             : struct host host;
      68             : 
      69             : /* Standard command node structures. */
      70             : static struct cmd_node auth_node =
      71             : {
      72             :   AUTH_NODE,
      73             :   "Password: ",
      74             : };
      75             : 
      76             : static struct cmd_node view_node =
      77             : {
      78             :   VIEW_NODE,
      79             :   "%s> ",
      80             : };
      81             : 
      82             : static struct cmd_node restricted_node =
      83             : {
      84             :   RESTRICTED_NODE,
      85             :   "%s$ ",
      86             : };
      87             : 
      88             : static struct cmd_node auth_enable_node =
      89             : {
      90             :   AUTH_ENABLE_NODE,
      91             :   "Password: ",
      92             : };
      93             : 
      94             : static struct cmd_node enable_node =
      95             : {
      96             :   ENABLE_NODE,
      97             :   "%s# ",
      98             : };
      99             : 
     100             : static struct cmd_node config_node =
     101             : {
     102             :   CONFIG_NODE,
     103             :   "%s(config)# ",
     104             :   1
     105             : };
     106             : 
     107             : /* Default motd string. */
     108             : static const char *default_motd =
     109             : "\r\n\
     110             : Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
     111             : " QUAGGA_COPYRIGHT "\r\n\
     112             : " GIT_INFO "\r\n";
     113             : 
     114             : 
     115             : static const struct facility_map {
     116             :   int facility;
     117             :   const char *name;
     118             :   size_t match;
     119             : } syslog_facilities[] = 
     120             :   {
     121             :     { LOG_KERN, "kern", 1 },
     122             :     { LOG_USER, "user", 2 },
     123             :     { LOG_MAIL, "mail", 1 },
     124             :     { LOG_DAEMON, "daemon", 1 },
     125             :     { LOG_AUTH, "auth", 1 },
     126             :     { LOG_SYSLOG, "syslog", 1 },
     127             :     { LOG_LPR, "lpr", 2 },
     128             :     { LOG_NEWS, "news", 1 },
     129             :     { LOG_UUCP, "uucp", 2 },
     130             :     { LOG_CRON, "cron", 1 },
     131             : #ifdef LOG_FTP
     132             :     { LOG_FTP, "ftp", 1 },
     133             : #endif
     134             :     { LOG_LOCAL0, "local0", 6 },
     135             :     { LOG_LOCAL1, "local1", 6 },
     136             :     { LOG_LOCAL2, "local2", 6 },
     137             :     { LOG_LOCAL3, "local3", 6 },
     138             :     { LOG_LOCAL4, "local4", 6 },
     139             :     { LOG_LOCAL5, "local5", 6 },
     140             :     { LOG_LOCAL6, "local6", 6 },
     141             :     { LOG_LOCAL7, "local7", 6 },
     142             :     { 0, NULL, 0 },
     143             :   };
     144             : 
     145             : static const char *
     146           0 : facility_name(int facility)
     147             : {
     148             :   const struct facility_map *fm;
     149             : 
     150           0 :   for (fm = syslog_facilities; fm->name; fm++)
     151           0 :     if (fm->facility == facility)
     152           0 :       return fm->name;
     153           0 :   return "";
     154             : }
     155             : 
     156             : static int
     157           0 : facility_match(const char *str)
     158             : {
     159             :   const struct facility_map *fm;
     160             : 
     161           0 :   for (fm = syslog_facilities; fm->name; fm++)
     162           0 :     if (!strncmp(str,fm->name,fm->match))
     163           0 :       return fm->facility;
     164           0 :   return -1;
     165             : }
     166             : 
     167             : static int
     168           0 : level_match(const char *s)
     169             : {
     170             :   int level ;
     171             :   
     172           0 :   for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
     173           0 :     if (!strncmp (s, zlog_priority[level], 2))
     174           0 :       return level;
     175           0 :   return ZLOG_DISABLED;
     176             : }
     177             : 
     178             : /* This is called from main when a daemon is invoked with -v or --version. */
     179             : void
     180           0 : print_version (const char *progname)
     181             : {
     182           0 :   printf ("%s version %s\n", progname, QUAGGA_VERSION);
     183           0 :   printf ("%s\n", QUAGGA_COPYRIGHT);
     184           0 : }
     185             : 
     186             : 
     187             : /* Utility function to concatenate argv argument into a single string
     188             :    with inserting ' ' character between each argument.  */
     189             : char *
     190           0 : argv_concat (const char **argv, int argc, int shift)
     191             : {
     192             :   int i;
     193             :   size_t len;
     194             :   char *str;
     195             :   char *p;
     196             : 
     197           0 :   len = 0;
     198           0 :   for (i = shift; i < argc; i++)
     199           0 :     len += strlen(argv[i])+1;
     200           0 :   if (!len)
     201           0 :     return NULL;
     202           0 :   p = str = XMALLOC(MTYPE_TMP, len);
     203           0 :   for (i = shift; i < argc; i++)
     204             :     {
     205             :       size_t arglen;
     206           0 :       memcpy(p, argv[i], (arglen = strlen(argv[i])));
     207           0 :       p += arglen;
     208           0 :       *p++ = ' ';
     209             :     }
     210           0 :   *(p-1) = '\0';
     211           0 :   return str;
     212             : }
     213             : 
     214             : /* Install top node of command vector. */
     215             : void
     216         810 : install_node (struct cmd_node *node, 
     217             :               int (*func) (struct vty *))
     218             : {
     219         810 :   vector_set_index (cmdvec, node->node, node);
     220         810 :   node->func = func;
     221         810 :   node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
     222         810 : }
     223             : 
     224             : /* Breaking up string into each command piece. I assume given
     225             :    character is separated by a space character. Return value is a
     226             :    vector which includes char ** data element. */
     227             : vector
     228         581 : cmd_make_strvec (const char *string)
     229             : {
     230             :   const char *cp, *start;
     231             :   char *token;
     232             :   int strlen;
     233             :   vector strvec;
     234             :   
     235         581 :   if (string == NULL)
     236           0 :     return NULL;
     237             :   
     238         581 :   cp = string;
     239             : 
     240             :   /* Skip white spaces. */
     241        1162 :   while (isspace ((int) *cp) && *cp != '\0')
     242           0 :     cp++;
     243             : 
     244             :   /* Return if there is only white spaces */
     245         581 :   if (*cp == '\0')
     246           0 :     return NULL;
     247             : 
     248         581 :   if (*cp == '!' || *cp == '#')
     249           0 :     return NULL;
     250             : 
     251             :   /* Prepare return vector. */
     252         581 :   strvec = vector_init (VECTOR_MIN_SIZE);
     253             : 
     254             :   /* Copy each command piece and set into vector. */
     255             :   while (1) 
     256             :     {
     257        1646 :       start = cp;
     258       21276 :       while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
     259        9229 :              *cp != '\0')
     260        8755 :         cp++;
     261        1646 :       strlen = cp - start;
     262        1646 :       token = XMALLOC (MTYPE_STRVEC, strlen + 1);
     263        1646 :       memcpy (token, start, strlen);
     264        1646 :       *(token + strlen) = '\0';
     265        1646 :       vector_set (strvec, token);
     266             : 
     267        5636 :       while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
     268        1172 :              *cp != '\0')
     269        1172 :         cp++;
     270             : 
     271        1646 :       if (*cp == '\0')
     272         581 :         return strvec;
     273        1065 :     }
     274             : }
     275             : 
     276             : /* Free allocated string vector. */
     277             : void
     278         581 : cmd_free_strvec (vector v)
     279             : {
     280             :   unsigned int i;
     281             :   char *cp;
     282             : 
     283         581 :   if (!v)
     284           0 :     return;
     285             : 
     286        2227 :   for (i = 0; i < vector_active (v); i++)
     287        1646 :     if ((cp = vector_slot (v, i)) != NULL)
     288        1646 :       XFREE (MTYPE_STRVEC, cp);
     289             : 
     290         581 :   vector_free (v);
     291             : }
     292             : 
     293             : struct format_parser_state
     294             : {
     295             :   vector topvect; /* Top level vector */
     296             :   vector intvect; /* Intermediate level vector, used when there's
     297             :                    * a multiple in a keyword. */
     298             :   vector curvect; /* current vector where read tokens should be
     299             :                      appended. */
     300             : 
     301             :   const char *string; /* pointer to command string, not modified */
     302             :   const char *cp; /* pointer in command string, moved along while
     303             :                      parsing */
     304             :   const char *dp;  /* pointer in description string, moved along while
     305             :                      parsing */
     306             : 
     307             :   int in_keyword; /* flag to remember if we are in a keyword group */
     308             :   int in_multiple; /* flag to remember if we are in a multiple group */
     309             :   int just_read_word; /* flag to remember if the last thing we red was a
     310             :                        * real word and not some abstract token */
     311             : };
     312             : 
     313             : static void
     314           0 : format_parser_error(struct format_parser_state *state, const char *message)
     315             : {
     316           0 :   int offset = state->cp - state->string + 1;
     317             : 
     318           0 :   fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
     319           0 :   fprintf(stderr, "                        %*c\n", offset, '^');
     320           0 :   fprintf(stderr, "%s at offset %d.\n", message, offset);
     321           0 :   fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
     322           0 :   exit(1);
     323             : }
     324             : 
     325             : static char *
     326      108720 : format_parser_desc_str(struct format_parser_state *state)
     327             : {
     328             :   const char *cp, *start;
     329             :   char *token;
     330             :   int strlen;
     331             : 
     332      108720 :   cp = state->dp;
     333             : 
     334      108720 :   if (cp == NULL)
     335           0 :     return NULL;
     336             : 
     337             :   /* Skip white spaces. */
     338      306450 :   while (isspace ((int) *cp) && *cp != '\0')
     339       89010 :     cp++;
     340             : 
     341             :   /* Return if there is only white spaces */
     342      108720 :   if (*cp == '\0')
     343        1890 :     return NULL;
     344             : 
     345      106830 :   start = cp;
     346             : 
     347     3019275 :   while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
     348     2805615 :     cp++;
     349             : 
     350      106830 :   strlen = cp - start;
     351      106830 :   token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
     352      106830 :   memcpy (token, start, strlen);
     353      106830 :   *(token + strlen) = '\0';
     354             : 
     355      106830 :   state->dp = cp;
     356             : 
     357      106830 :   return token;
     358             : }
     359             : 
     360             : static void
     361           0 : format_parser_begin_keyword(struct format_parser_state *state)
     362             : {
     363             :   struct cmd_token *token;
     364             :   vector keyword_vect;
     365             : 
     366           0 :   if (state->in_keyword
     367           0 :       || state->in_multiple)
     368           0 :     format_parser_error(state, "Unexpected '{'");
     369             : 
     370           0 :   state->cp++;
     371           0 :   state->in_keyword = 1;
     372             : 
     373           0 :   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
     374           0 :   token->type = TOKEN_KEYWORD;
     375           0 :   token->keyword = vector_init(VECTOR_MIN_SIZE);
     376             : 
     377           0 :   keyword_vect = vector_init(VECTOR_MIN_SIZE);
     378           0 :   vector_set(token->keyword, keyword_vect);
     379             : 
     380           0 :   vector_set(state->curvect, token);
     381           0 :   state->curvect = keyword_vect;
     382           0 : }
     383             : 
     384             : static void
     385       10755 : format_parser_begin_multiple(struct format_parser_state *state)
     386             : {
     387             :   struct cmd_token *token;
     388             : 
     389       10755 :   if (state->in_keyword == 1)
     390           0 :     format_parser_error(state, "Keyword starting with '('");
     391             : 
     392       10755 :   if (state->in_multiple)
     393           0 :     format_parser_error(state, "Nested group");
     394             : 
     395       10755 :   state->cp++;
     396       10755 :   state->in_multiple = 1;
     397       10755 :   state->just_read_word = 0;
     398             : 
     399       10755 :   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
     400       10755 :   token->type = TOKEN_MULTIPLE;
     401       10755 :   token->multiple = vector_init(VECTOR_MIN_SIZE);
     402             : 
     403       10755 :   vector_set(state->curvect, token);
     404       10755 :   if (state->curvect != state->topvect)
     405           0 :     state->intvect = state->curvect;
     406       10755 :   state->curvect = token->multiple;
     407       10755 : }
     408             : 
     409             : static void
     410           0 : format_parser_end_keyword(struct format_parser_state *state)
     411             : {
     412           0 :   if (state->in_multiple
     413           0 :       || !state->in_keyword)
     414           0 :     format_parser_error(state, "Unexpected '}'");
     415             : 
     416           0 :   if (state->in_keyword == 1)
     417           0 :     format_parser_error(state, "Empty keyword group");
     418             : 
     419           0 :   state->cp++;
     420           0 :   state->in_keyword = 0;
     421           0 :   state->curvect = state->topvect;
     422           0 : }
     423             : 
     424             : static void
     425       10755 : format_parser_end_multiple(struct format_parser_state *state)
     426             : {
     427             :   char *dummy;
     428             : 
     429       10755 :   if (!state->in_multiple)
     430           0 :     format_parser_error(state, "Unepexted ')'");
     431             : 
     432       10755 :   if (vector_active(state->curvect) == 0)
     433           0 :     format_parser_error(state, "Empty multiple section");
     434             : 
     435       10755 :   if (!state->just_read_word)
     436             :     {
     437             :       /* There are constructions like
     438             :        * 'show ip ospf database ... (self-originate|)'
     439             :        * in use.
     440             :        * The old parser reads a description string for the
     441             :        * word '' between |) which will never match.
     442             :        * Simulate this behvaior by dropping the next desc
     443             :        * string in such a case. */
     444             : 
     445         990 :       dummy = format_parser_desc_str(state);
     446         990 :       XFREE(MTYPE_CMD_TOKENS, dummy);
     447             :     }
     448             : 
     449       10755 :   state->cp++;
     450       10755 :   state->in_multiple = 0;
     451             : 
     452       10755 :   if (state->intvect)
     453           0 :     state->curvect = state->intvect;
     454             :   else
     455       10755 :     state->curvect = state->topvect;
     456       10755 : }
     457             : 
     458             : static void
     459       16335 : format_parser_handle_pipe(struct format_parser_state *state)
     460             : {
     461             :   struct cmd_token *keyword_token;
     462             :   vector keyword_vect;
     463             : 
     464       16335 :   if (state->in_multiple)
     465             :     {
     466       16335 :       state->just_read_word = 0;
     467       16335 :       state->cp++;
     468             :     }
     469           0 :   else if (state->in_keyword)
     470             :     {
     471           0 :       state->in_keyword = 1;
     472           0 :       state->cp++;
     473             : 
     474           0 :       keyword_token = vector_slot(state->topvect,
     475             :                                   vector_active(state->topvect) - 1);
     476           0 :       keyword_vect = vector_init(VECTOR_MIN_SIZE);
     477           0 :       vector_set(keyword_token->keyword, keyword_vect);
     478           0 :       state->curvect = keyword_vect;
     479             :     }
     480             :   else
     481             :     {
     482           0 :       format_parser_error(state, "Unexpected '|'");
     483             :     }
     484       16335 : }
     485             : 
     486             : static void
     487      107730 : format_parser_read_word(struct format_parser_state *state)
     488             : {
     489             :   const char *start;
     490             :   int len;
     491             :   char *cmd;
     492             :   struct cmd_token *token;
     493             : 
     494      107730 :   start = state->cp;
     495             : 
     496      883215 :   while (state->cp[0] != '\0'
     497      758745 :          && !strchr("\r\n(){}|", state->cp[0])
     498      732645 :          && !isspace((int)state->cp[0]))
     499      667755 :     state->cp++;
     500             : 
     501      107730 :   len = state->cp - start;
     502      107730 :   cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
     503      107730 :   memcpy(cmd, start, len);
     504      107730 :   cmd[len] = '\0';
     505             : 
     506      107730 :   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
     507      107730 :   token->type = TOKEN_TERMINAL;
     508      107730 :   token->cmd = cmd;
     509      107730 :   token->desc = format_parser_desc_str(state);
     510      107730 :   vector_set(state->curvect, token);
     511             : 
     512      107730 :   if (state->in_keyword == 1)
     513           0 :     state->in_keyword = 2;
     514             : 
     515      107730 :   state->just_read_word = 1;
     516      107730 : }
     517             : 
     518             : /**
     519             :  * Parse a given command format string and build a tree of tokens from
     520             :  * it that is suitable to be used by the command subsystem.
     521             :  *
     522             :  * @param string Command format string.
     523             :  * @param descstr Description string.
     524             :  * @return A vector of struct cmd_token representing the given command,
     525             :  *         or NULL on error.
     526             :  */
     527             : static vector
     528       19620 : cmd_parse_format(const char *string, const char *descstr)
     529             : {
     530             :   struct format_parser_state state;
     531             : 
     532       19620 :   if (string == NULL)
     533           0 :     return NULL;
     534             : 
     535       19620 :   memset(&state, 0, sizeof(state));
     536       19620 :   state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
     537       19620 :   state.cp = state.string = string;
     538       19620 :   state.dp = descstr;
     539             : 
     540             :   while (1)
     541             :     {
     542      403155 :       while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
     543       72765 :         state.cp++;
     544             : 
     545      165195 :       switch (state.cp[0])
     546             :         {
     547             :         case '\0':
     548       19620 :           if (state.in_keyword
     549       19620 :               || state.in_multiple)
     550           0 :             format_parser_error(&state, "Unclosed group/keyword");
     551       19620 :           return state.topvect;
     552             :         case '{':
     553           0 :           format_parser_begin_keyword(&state);
     554           0 :           break;
     555             :         case '(':
     556       10755 :           format_parser_begin_multiple(&state);
     557       10755 :           break;
     558             :         case '}':
     559           0 :           format_parser_end_keyword(&state);
     560           0 :           break;
     561             :         case ')':
     562       10755 :           format_parser_end_multiple(&state);
     563       10755 :           break;
     564             :         case '|':
     565       16335 :           format_parser_handle_pipe(&state);
     566       16335 :           break;
     567             :         default:
     568      107730 :           format_parser_read_word(&state);
     569             :         }
     570      145575 :     }
     571             : }
     572             : 
     573             : /* Return prompt character of specified node. */
     574             : const char *
     575         626 : cmd_prompt (enum node_type node)
     576             : {
     577             :   struct cmd_node *cnode;
     578             : 
     579         626 :   cnode = vector_slot (cmdvec, node);
     580         626 :   return cnode->prompt;
     581             : }
     582             : 
     583             : /* Install a command into a node. */
     584             : void
     585       25965 : install_element (enum node_type ntype, struct cmd_element *cmd)
     586             : {
     587             :   struct cmd_node *cnode;
     588             :   
     589             :   /* cmd_init hasn't been called */
     590       25965 :   if (!cmdvec)
     591           0 :     return;
     592             :   
     593       25965 :   cnode = vector_slot (cmdvec, ntype);
     594             : 
     595       25965 :   if (cnode == NULL) 
     596             :     {
     597           0 :       fprintf (stderr, "Command node %d doesn't exist, please check it\n",
     598             :                ntype);
     599           0 :       exit (1);
     600             :     }
     601             : 
     602       25965 :   vector_set (cnode->cmd_vector, cmd);
     603       25965 :   if (cmd->tokens == NULL)
     604       19620 :     cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
     605             : }
     606             : 
     607             : static const unsigned char itoa64[] =
     608             : "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     609             : 
     610             : static void
     611           0 : to64(char *s, long v, int n)
     612             : {
     613           0 :   while (--n >= 0) 
     614             :     {
     615           0 :       *s++ = itoa64[v&0x3f];
     616           0 :       v >>= 6;
     617             :     }
     618           0 : }
     619             : 
     620             : static char *
     621           0 : zencrypt (const char *passwd)
     622             : {
     623             :   char salt[6];
     624             :   struct timeval tv;
     625             :   char *crypt (const char *, const char *);
     626             : 
     627           0 :   gettimeofday(&tv,0);
     628             :   
     629           0 :   to64(&salt[0], random(), 3);
     630           0 :   to64(&salt[3], tv.tv_usec, 3);
     631           0 :   salt[5] = '\0';
     632             : 
     633           0 :   return crypt (passwd, salt);
     634             : }
     635             : 
     636             : /* This function write configuration of this host. */
     637             : static int
     638           0 : config_write_host (struct vty *vty)
     639             : {
     640           0 :   if (host.name)
     641           0 :     vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
     642             : 
     643           0 :   if (host.encrypt)
     644             :     {
     645           0 :       if (host.password_encrypt)
     646           0 :         vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); 
     647           0 :       if (host.enable_encrypt)
     648           0 :         vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); 
     649             :     }
     650             :   else
     651             :     {
     652           0 :       if (host.password)
     653           0 :         vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
     654           0 :       if (host.enable)
     655           0 :         vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
     656             :     }
     657             : 
     658           0 :   if (zlog_default->default_lvl != LOG_DEBUG)
     659             :     {
     660           0 :       vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
     661           0 :                VTY_NEWLINE);
     662           0 :       vty_out (vty, "log trap %s%s",
     663           0 :                zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
     664             :     }
     665             : 
     666           0 :   if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
     667             :     {
     668           0 :       vty_out (vty, "log file %s", host.logfile);
     669           0 :       if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
     670           0 :         vty_out (vty, " %s",
     671           0 :                  zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
     672           0 :       vty_out (vty, "%s", VTY_NEWLINE);
     673             :     }
     674             : 
     675           0 :   if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
     676             :     {
     677           0 :       vty_out (vty, "log stdout");
     678           0 :       if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
     679           0 :         vty_out (vty, " %s",
     680           0 :                  zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
     681           0 :       vty_out (vty, "%s", VTY_NEWLINE);
     682             :     }
     683             : 
     684           0 :   if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
     685           0 :     vty_out(vty,"no log monitor%s",VTY_NEWLINE);
     686           0 :   else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
     687           0 :     vty_out(vty,"log monitor %s%s",
     688           0 :             zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
     689             : 
     690           0 :   if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
     691             :     {
     692           0 :       vty_out (vty, "log syslog");
     693           0 :       if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
     694           0 :         vty_out (vty, " %s",
     695           0 :                  zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
     696           0 :       vty_out (vty, "%s", VTY_NEWLINE);
     697             :     }
     698             : 
     699           0 :   if (zlog_default->facility != LOG_DAEMON)
     700           0 :     vty_out (vty, "log facility %s%s",
     701           0 :              facility_name(zlog_default->facility), VTY_NEWLINE);
     702             : 
     703           0 :   if (zlog_default->record_priority == 1)
     704           0 :     vty_out (vty, "log record-priority%s", VTY_NEWLINE);
     705             : 
     706           0 :   if (zlog_default->timestamp_precision > 0)
     707           0 :     vty_out (vty, "log timestamp precision %d%s",
     708           0 :              zlog_default->timestamp_precision, VTY_NEWLINE);
     709             : 
     710           0 :   if (host.advanced)
     711           0 :     vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
     712             : 
     713           0 :   if (host.encrypt)
     714           0 :     vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
     715             : 
     716           0 :   if (host.lines >= 0)
     717           0 :     vty_out (vty, "service terminal-length %d%s", host.lines,
     718           0 :              VTY_NEWLINE);
     719             : 
     720           0 :   if (host.motdfile)
     721           0 :     vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
     722           0 :   else if (! host.motd)
     723           0 :     vty_out (vty, "no banner motd%s", VTY_NEWLINE);
     724             : 
     725           0 :   return 1;
     726             : }
     727             : 
     728             : /* Utility function for getting command vector. */
     729             : static vector
     730         594 : cmd_node_vector (vector v, enum node_type ntype)
     731             : {
     732         594 :   struct cmd_node *cnode = vector_slot (v, ntype);
     733         594 :   return cnode->cmd_vector;
     734             : }
     735             : 
     736             : #if 0
     737             : /* Filter command vector by symbol.  This function is not actually used;
     738             :  * should it be deleted? */
     739             : static int
     740             : cmd_filter_by_symbol (char *command, char *symbol)
     741             : {
     742             :   int i, lim;
     743             : 
     744             :   if (strcmp (symbol, "IPV4_ADDRESS") == 0)
     745             :     {
     746             :       i = 0;
     747             :       lim = strlen (command);
     748             :       while (i < lim)
     749             :         {
     750             :           if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
     751             :             return 1;
     752             :           i++;
     753             :         }
     754             :       return 0;
     755             :     }
     756             :   if (strcmp (symbol, "STRING") == 0)
     757             :     {
     758             :       i = 0;
     759             :       lim = strlen (command);
     760             :       while (i < lim)
     761             :         {
     762             :           if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
     763             :             return 1;
     764             :           i++;
     765             :         }
     766             :       return 0;
     767             :     }
     768             :   if (strcmp (symbol, "IFNAME") == 0)
     769             :     {
     770             :       i = 0;
     771             :       lim = strlen (command);
     772             :       while (i < lim)
     773             :         {
     774             :           if (! isalnum ((int) command[i]))
     775             :             return 1;
     776             :           i++;
     777             :         }
     778             :       return 0;
     779             :     }
     780             :   return 0;
     781             : }
     782             : #endif
     783             : 
     784             : /* Completion match types. */
     785             : enum match_type 
     786             : {
     787             :   no_match,
     788             :   extend_match,
     789             :   ipv4_prefix_match,
     790             :   ipv4_match,
     791             :   ipv6_prefix_match,
     792             :   ipv6_match,
     793             :   range_match,
     794             :   vararg_match,
     795             :   partly_match,
     796             :   exact_match 
     797             : };
     798             : 
     799             : static enum match_type
     800          89 : cmd_ipv4_match (const char *str)
     801             : {
     802             :   const char *sp;
     803          89 :   int dots = 0, nums = 0;
     804             :   char buf[4];
     805             : 
     806          89 :   if (str == NULL)
     807           0 :     return partly_match;
     808             : 
     809             :   for (;;)
     810             :     {
     811         293 :       memset (buf, 0, sizeof (buf));
     812         293 :       sp = str;
     813        1070 :       while (*str != '\0')
     814             :         {
     815         732 :           if (*str == '.')
     816             :             {
     817         204 :               if (dots >= 3)
     818           0 :                 return no_match;
     819             : 
     820         204 :               if (*(str + 1) == '.')
     821           0 :                 return no_match;
     822             : 
     823         204 :               if (*(str + 1) == '\0')
     824           0 :                 return partly_match;
     825             : 
     826         204 :               dots++;
     827         204 :               break;
     828             :             }
     829         528 :           if (!isdigit ((int) *str))
     830          44 :             return no_match;
     831             : 
     832         484 :           str++;
     833             :         }
     834             : 
     835         249 :       if (str - sp > 3)
     836           0 :         return no_match;
     837             : 
     838         249 :       strncpy (buf, sp, str - sp);
     839         249 :       if (atoi (buf) > 255)
     840           0 :         return no_match;
     841             : 
     842         249 :       nums++;
     843             : 
     844         249 :       if (*str == '\0')
     845          45 :         break;
     846             : 
     847         204 :       str++;
     848         204 :     }
     849             : 
     850          45 :   if (nums < 4)
     851           0 :     return partly_match;
     852             : 
     853          45 :   return exact_match;
     854             : }
     855             : 
     856             : static enum match_type
     857         192 : cmd_ipv4_prefix_match (const char *str)
     858             : {
     859             :   const char *sp;
     860         192 :   int dots = 0;
     861             :   char buf[4];
     862             : 
     863         192 :   if (str == NULL)
     864           0 :     return partly_match;
     865             : 
     866             :   for (;;)
     867             :     {
     868         705 :       memset (buf, 0, sizeof (buf));
     869         705 :       sp = str;
     870        2651 :       while (*str != '\0' && *str != '/')
     871             :         {
     872        1775 :           if (*str == '.')
     873             :             {
     874         513 :               if (dots == 3)
     875           0 :                 return no_match;
     876             : 
     877         513 :               if (*(str + 1) == '.' || *(str + 1) == '/')
     878           0 :                 return no_match;
     879             : 
     880         513 :               if (*(str + 1) == '\0')
     881           0 :                 return partly_match;
     882             : 
     883         513 :               dots++;
     884         513 :               break;
     885             :             }
     886             : 
     887        1262 :           if (!isdigit ((int) *str))
     888          21 :             return no_match;
     889             : 
     890        1241 :           str++;
     891             :         }
     892             : 
     893         684 :       if (str - sp > 3)
     894           0 :         return no_match;
     895             : 
     896         684 :       strncpy (buf, sp, str - sp);
     897         684 :       if (atoi (buf) > 255)
     898           0 :         return no_match;
     899             : 
     900         684 :       if (dots == 3)
     901             :         {
     902         342 :           if (*str == '/')
     903             :             {
     904         171 :               if (*(str + 1) == '\0')
     905           0 :                 return partly_match;
     906             : 
     907         171 :               str++;
     908         171 :               break;
     909             :             }
     910         171 :           else if (*str == '\0')
     911           0 :             return partly_match;
     912             :         }
     913             : 
     914         513 :       if (*str == '\0')
     915           0 :         return partly_match;
     916             : 
     917         513 :       str++;
     918         513 :     }
     919             : 
     920         171 :   sp = str;
     921         684 :   while (*str != '\0')
     922             :     {
     923         342 :       if (!isdigit ((int) *str))
     924           0 :         return no_match;
     925             : 
     926         342 :       str++;
     927             :     }
     928             : 
     929         171 :   if (atoi (sp) > 32)
     930           0 :     return no_match;
     931             : 
     932         171 :   return exact_match;
     933             : }
     934             : 
     935             : #define IPV6_ADDR_STR           "0123456789abcdefABCDEF:.%"
     936             : #define IPV6_PREFIX_STR         "0123456789abcdefABCDEF:.%/"
     937             : #define STATE_START             1
     938             : #define STATE_COLON             2
     939             : #define STATE_DOUBLE            3
     940             : #define STATE_ADDR              4
     941             : #define STATE_DOT               5
     942             : #define STATE_SLASH             6
     943             : #define STATE_MASK              7
     944             : 
     945             : #ifdef HAVE_IPV6
     946             : 
     947             : static enum match_type
     948           0 : cmd_ipv6_match (const char *str)
     949             : {
     950             :   struct sockaddr_in6 sin6_dummy;
     951             :   int ret;
     952             : 
     953           0 :   if (str == NULL)
     954           0 :     return partly_match;
     955             : 
     956           0 :   if (strspn (str, IPV6_ADDR_STR) != strlen (str))
     957           0 :     return no_match;
     958             : 
     959             :   /* use inet_pton that has a better support,
     960             :    * for example inet_pton can support the automatic addresses:
     961             :    *  ::1.2.3.4
     962             :    */
     963           0 :   ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
     964             :    
     965           0 :   if (ret == 1)
     966           0 :     return exact_match;
     967             : 
     968           0 :   return no_match;
     969             : }
     970             : 
     971             : static enum match_type
     972           4 : cmd_ipv6_prefix_match (const char *str)
     973             : {
     974           4 :   int state = STATE_START;
     975           4 :   int colons = 0, nums = 0, double_colon = 0;
     976             :   int mask;
     977           4 :   const char *sp = NULL;
     978           4 :   char *endptr = NULL;
     979             : 
     980           4 :   if (str == NULL)
     981           0 :     return partly_match;
     982             : 
     983           4 :   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
     984           0 :     return no_match;
     985             : 
     986          60 :   while (*str != '\0' && state != STATE_MASK)
     987             :     {
     988          52 :       switch (state)
     989             :         {
     990             :         case STATE_START:
     991           4 :           if (*str == ':')
     992             :             {
     993           0 :               if (*(str + 1) != ':' && *(str + 1) != '\0')
     994           0 :                 return no_match;
     995           0 :               colons--;
     996           0 :               state = STATE_COLON;
     997             :             }
     998             :           else
     999             :             {
    1000           4 :               sp = str;
    1001           4 :               state = STATE_ADDR;
    1002             :             }
    1003             : 
    1004           4 :           continue;
    1005             :         case STATE_COLON:
    1006           8 :           colons++;
    1007           8 :           if (*(str + 1) == '/')
    1008           0 :             return no_match;
    1009           8 :           else if (*(str + 1) == ':')
    1010           4 :             state = STATE_DOUBLE;
    1011             :           else
    1012             :             {
    1013           4 :               sp = str + 1;
    1014           4 :               state = STATE_ADDR;
    1015             :             }
    1016           8 :           break;
    1017             :         case STATE_DOUBLE:
    1018           4 :           if (double_colon)
    1019           0 :             return no_match;
    1020             : 
    1021           4 :           if (*(str + 1) == ':')
    1022           0 :             return no_match;
    1023             :           else
    1024             :             {
    1025           4 :               if (*(str + 1) != '\0' && *(str + 1) != '/')
    1026           4 :                 colons++;
    1027           4 :               sp = str + 1;
    1028             : 
    1029           4 :               if (*(str + 1) == '/')
    1030           0 :                 state = STATE_SLASH;
    1031             :               else
    1032           4 :                 state = STATE_ADDR;
    1033             :             }
    1034             : 
    1035           4 :           double_colon++;
    1036           4 :           nums += 1;
    1037           4 :           break;
    1038             :         case STATE_ADDR:
    1039          32 :           if (*(str + 1) == ':' || *(str + 1) == '.'
    1040          24 :               || *(str + 1) == '\0' || *(str + 1) == '/')
    1041             :             {
    1042          12 :               if (str - sp > 3)
    1043           0 :                 return no_match;
    1044             : 
    1045          44 :               for (; sp <= str; sp++)
    1046          32 :                 if (*sp == '/')
    1047           0 :                   return no_match;
    1048             : 
    1049          12 :               nums++;
    1050             : 
    1051          12 :               if (*(str + 1) == ':')
    1052           8 :                 state = STATE_COLON;
    1053           4 :               else if (*(str + 1) == '.')
    1054             :                 {
    1055           0 :                   if (colons || double_colon)
    1056           0 :                     state = STATE_DOT;
    1057             :                   else
    1058           0 :                     return no_match;
    1059             :                 }
    1060           4 :               else if (*(str + 1) == '/')
    1061           4 :                 state = STATE_SLASH;
    1062             :             }
    1063          32 :           break;
    1064             :         case STATE_DOT:
    1065           0 :           state = STATE_ADDR;
    1066           0 :           break;
    1067             :         case STATE_SLASH:
    1068           4 :           if (*(str + 1) == '\0')
    1069           0 :             return partly_match;
    1070             : 
    1071           4 :           state = STATE_MASK;
    1072           4 :           break;
    1073             :         default:
    1074           0 :           break;
    1075             :         }
    1076             : 
    1077          48 :       if (nums > 11)
    1078           0 :         return no_match;
    1079             : 
    1080          48 :       if (colons > 7)
    1081           0 :         return no_match;
    1082             : 
    1083          48 :       str++;
    1084             :     }
    1085             : 
    1086           4 :   if (state < STATE_MASK)
    1087           0 :     return partly_match;
    1088             : 
    1089           4 :   mask = strtol (str, &endptr, 10);
    1090           4 :   if (*endptr != '\0')
    1091           0 :     return no_match;
    1092             : 
    1093           4 :   if (mask < 0 || mask > 128)
    1094           0 :     return no_match;
    1095             :   
    1096             : /* I don't know why mask < 13 makes command match partly.
    1097             :    Forgive me to make this comments. I Want to set static default route
    1098             :    because of lack of function to originate default in ospf6d; sorry
    1099             :        yasu
    1100             :   if (mask < 13)
    1101             :     return partly_match;
    1102             : */
    1103             : 
    1104           4 :   return exact_match;
    1105             : }
    1106             : 
    1107             : #endif /* HAVE_IPV6  */
    1108             : 
    1109             : #define DECIMAL_STRLEN_MAX 10
    1110             : 
    1111             : static int
    1112         565 : cmd_range_match (const char *range, const char *str)
    1113             : {
    1114             :   char *p;
    1115             :   char buf[DECIMAL_STRLEN_MAX + 1];
    1116         565 :   char *endptr = NULL;
    1117             :   unsigned long min, max, val;
    1118             : 
    1119         565 :   if (str == NULL)
    1120           0 :     return 1;
    1121             : 
    1122         565 :   val = strtoul (str, &endptr, 10);
    1123         565 :   if (*endptr != '\0')
    1124           6 :     return 0;
    1125             : 
    1126         559 :   range++;
    1127         559 :   p = strchr (range, '-');
    1128         559 :   if (p == NULL)
    1129          18 :     return 0;
    1130         541 :   if (p - range > DECIMAL_STRLEN_MAX)
    1131           0 :     return 0;
    1132         541 :   strncpy (buf, range, p - range);
    1133         541 :   buf[p - range] = '\0';
    1134         541 :   min = strtoul (buf, &endptr, 10);
    1135         541 :   if (*endptr != '\0')
    1136           0 :     return 0;
    1137             : 
    1138         541 :   range = p + 1;
    1139         541 :   p = strchr (range, '>');
    1140         541 :   if (p == NULL)
    1141           0 :     return 0;
    1142         541 :   if (p - range > DECIMAL_STRLEN_MAX)
    1143           0 :     return 0;
    1144         541 :   strncpy (buf, range, p - range);
    1145         541 :   buf[p - range] = '\0';
    1146         541 :   max = strtoul (buf, &endptr, 10);
    1147         541 :   if (*endptr != '\0')
    1148           0 :     return 0;
    1149             : 
    1150         541 :   if (val < min || val > max)
    1151         162 :     return 0;
    1152             : 
    1153         379 :   return 1;
    1154             : }
    1155             : 
    1156             : static enum match_type
    1157      152238 : cmd_word_match(struct cmd_token *token,
    1158             :                enum filter_type filter,
    1159             :                const char *word)
    1160             : {
    1161             :   const char *str;
    1162             :   enum match_type match_type;
    1163             : 
    1164      152238 :   str = token->cmd;
    1165             : 
    1166      152238 :   if (filter == FILTER_RELAXED)
    1167      152238 :     if (!word || !strlen(word))
    1168           0 :       return partly_match;
    1169             : 
    1170      152238 :   if (!word)
    1171           0 :     return no_match;
    1172             : 
    1173      152238 :   if (CMD_VARARG(str))
    1174             :     {
    1175           0 :       return vararg_match;
    1176             :     }
    1177      152238 :   else if (CMD_RANGE(str))
    1178             :     {
    1179         464 :       if (cmd_range_match(str, word))
    1180         296 :         return range_match;
    1181             :     }
    1182             : #ifdef HAVE_IPV6
    1183      151774 :   else if (CMD_IPV6(str))
    1184             :     {
    1185           0 :       match_type = cmd_ipv6_match(word);
    1186           0 :       if ((filter == FILTER_RELAXED && match_type != no_match)
    1187           0 :           || (filter == FILTER_STRICT && match_type == exact_match))
    1188           0 :         return ipv6_match;
    1189             :     }
    1190      151774 :   else if (CMD_IPV6_PREFIX(str))
    1191             :     {
    1192           3 :       match_type = cmd_ipv6_prefix_match(word);
    1193           3 :       if ((filter == FILTER_RELAXED && match_type != no_match)
    1194           0 :           || (filter == FILTER_STRICT && match_type == exact_match))
    1195           3 :         return ipv6_prefix_match;
    1196             :     }
    1197             : #endif /* HAVE_IPV6 */
    1198      151771 :   else if (CMD_IPV4(str))
    1199             :     {
    1200          89 :       match_type = cmd_ipv4_match(word);
    1201          89 :       if ((filter == FILTER_RELAXED && match_type != no_match)
    1202          44 :           || (filter == FILTER_STRICT && match_type == exact_match))
    1203          45 :         return ipv4_match;
    1204             :     }
    1205      151682 :   else if (CMD_IPV4_PREFIX(str))
    1206             :     {
    1207         146 :       match_type = cmd_ipv4_prefix_match(word);
    1208         146 :       if ((filter == FILTER_RELAXED && match_type != no_match)
    1209          21 :           || (filter == FILTER_STRICT && match_type == exact_match))
    1210         125 :         return ipv4_prefix_match;
    1211             :     }
    1212      151536 :   else if (CMD_OPTION(str) || CMD_VARIABLE(str))
    1213             :     {
    1214         832 :       return extend_match;
    1215             :     }
    1216             :   else
    1217             :     {
    1218      150704 :       if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
    1219             :         {
    1220       45221 :           if (!strcmp(str, word))
    1221       42887 :             return exact_match;
    1222        2334 :           return partly_match;
    1223             :         }
    1224      105483 :       if (filter == FILTER_STRICT && !strcmp(str, word))
    1225           0 :         return exact_match;
    1226             :     }
    1227             : 
    1228      105716 :   return no_match;
    1229             : }
    1230             : 
    1231             : struct cmd_matcher
    1232             : {
    1233             :   struct cmd_element *cmd; /* The command element the matcher is using */
    1234             :   enum filter_type filter; /* Whether to use strict or relaxed matching */
    1235             :   vector vline; /* The tokenized commandline which is to be matched */
    1236             :   unsigned int index; /* The index up to which matching should be done */
    1237             : 
    1238             :   /* If set, construct a list of matches at the position given by index */
    1239             :   enum match_type *match_type;
    1240             :   vector *match;
    1241             : 
    1242             :   unsigned int word_index; /* iterating over vline */
    1243             : };
    1244             : 
    1245             : static int
    1246        1533 : push_argument(int *argc, const char **argv, const char *arg)
    1247             : {
    1248        1533 :   if (!arg || !strlen(arg))
    1249           0 :     arg = NULL;
    1250             : 
    1251        1533 :   if (!argc || !argv)
    1252        1326 :     return 0;
    1253             : 
    1254         207 :   if (*argc >= CMD_ARGC_MAX)
    1255           0 :     return -1;
    1256             : 
    1257         207 :   argv[(*argc)++] = arg;
    1258         207 :   return 0;
    1259             : }
    1260             : 
    1261             : static void
    1262       46522 : cmd_matcher_record_match(struct cmd_matcher *matcher,
    1263             :                          enum match_type match_type,
    1264             :                          struct cmd_token *token)
    1265             : {
    1266       46522 :   if (matcher->word_index != matcher->index)
    1267       26970 :     return;
    1268             : 
    1269       19552 :   if (matcher->match)
    1270             :     {
    1271       19552 :       if (!*matcher->match)
    1272       19542 :         *matcher->match = vector_init(VECTOR_MIN_SIZE);
    1273       19552 :       vector_set(*matcher->match, token);
    1274             :     }
    1275             : 
    1276       19552 :   if (matcher->match_type)
    1277             :     {
    1278       19552 :       if (match_type > *matcher->match_type)
    1279       19542 :         *matcher->match_type = match_type;
    1280             :     }
    1281             : }
    1282             : 
    1283             : static int
    1284      304301 : cmd_matcher_words_left(struct cmd_matcher *matcher)
    1285             : {
    1286      304301 :   return matcher->word_index < vector_active(matcher->vline);
    1287             : }
    1288             : 
    1289             : static const char*
    1290      151749 : cmd_matcher_get_word(struct cmd_matcher *matcher)
    1291             : {
    1292      151749 :   assert(cmd_matcher_words_left(matcher));
    1293             : 
    1294      151749 :   return vector_slot(matcher->vline, matcher->word_index);
    1295             : }
    1296             : 
    1297             : static enum matcher_rv
    1298      151864 : cmd_matcher_match_terminal(struct cmd_matcher *matcher,
    1299             :                            struct cmd_token *token,
    1300             :                            int *argc, const char **argv)
    1301             : {
    1302             :   const char *word;
    1303             :   enum match_type word_match;
    1304             : 
    1305      151864 :   assert(token->type == TOKEN_TERMINAL);
    1306             : 
    1307      151864 :   if (!cmd_matcher_words_left(matcher))
    1308             :     {
    1309         557 :       if (CMD_OPTION(token->cmd))
    1310           0 :         return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
    1311             :       else
    1312         557 :         return MATCHER_INCOMPLETE;
    1313             :     }
    1314             : 
    1315      151307 :   word = cmd_matcher_get_word(matcher);
    1316      151307 :   word_match = cmd_word_match(token, matcher->filter, word);
    1317      151307 :   if (word_match == no_match)
    1318      105175 :     return MATCHER_NO_MATCH;
    1319             : 
    1320             :   /* We have to record the input word as argument if it matched
    1321             :    * against a variable. */
    1322       46132 :   if (CMD_VARARG(token->cmd)
    1323       46132 :       || CMD_VARIABLE(token->cmd)
    1324       44984 :       || CMD_OPTION(token->cmd))
    1325             :     {
    1326        1166 :       if (push_argument(argc, argv, word))
    1327           0 :         return MATCHER_EXCEED_ARGC_MAX;
    1328             :     }
    1329             : 
    1330       46132 :   cmd_matcher_record_match(matcher, word_match, token);
    1331             : 
    1332       46132 :   matcher->word_index++;
    1333             : 
    1334             :   /* A vararg token should consume all left over words as arguments */
    1335       46132 :   if (CMD_VARARG(token->cmd))
    1336           0 :     while (cmd_matcher_words_left(matcher))
    1337             :       {
    1338           0 :         word = cmd_matcher_get_word(matcher);
    1339           0 :         if (word && strlen(word))
    1340           0 :           push_argument(argc, argv, word);
    1341           0 :         matcher->word_index++;
    1342             :       }
    1343             : 
    1344       46132 :   return MATCHER_OK;
    1345             : }
    1346             : 
    1347             : static enum matcher_rv
    1348         688 : cmd_matcher_match_multiple(struct cmd_matcher *matcher,
    1349             :                            struct cmd_token *token,
    1350             :                            int *argc, const char **argv)
    1351             : {
    1352             :   enum match_type multiple_match;
    1353             :   unsigned int multiple_index;
    1354             :   const char *word;
    1355             :   const char *arg;
    1356             :   struct cmd_token *word_token;
    1357             :   enum match_type word_match;
    1358             : 
    1359         688 :   assert(token->type == TOKEN_MULTIPLE);
    1360             : 
    1361         688 :   multiple_match = no_match;
    1362             : 
    1363         688 :   if (!cmd_matcher_words_left(matcher))
    1364         246 :     return MATCHER_INCOMPLETE;
    1365             : 
    1366         442 :   word = cmd_matcher_get_word(matcher);
    1367        1815 :   for (multiple_index = 0;
    1368        1373 :        multiple_index < vector_active(token->multiple);
    1369         931 :        multiple_index++)
    1370             :     {
    1371         931 :       word_token = vector_slot(token->multiple, multiple_index);
    1372             : 
    1373         931 :       word_match = cmd_word_match(word_token, matcher->filter, word);
    1374         931 :       if (word_match == no_match)
    1375         541 :         continue;
    1376             : 
    1377         390 :       cmd_matcher_record_match(matcher, word_match, word_token);
    1378             : 
    1379         390 :       if (word_match > multiple_match)
    1380             :         {
    1381         367 :           multiple_match = word_match;
    1382         367 :           arg = word;
    1383             :         }
    1384             :       /* To mimic the behavior of the old command implementation, we
    1385             :        * tolerate any ambiguities here :/ */
    1386             :     }
    1387             : 
    1388         442 :   matcher->word_index++;
    1389             : 
    1390         442 :   if (multiple_match == no_match)
    1391          75 :     return MATCHER_NO_MATCH;
    1392             : 
    1393         367 :   if (push_argument(argc, argv, arg))
    1394           0 :     return MATCHER_EXCEED_ARGC_MAX;
    1395             : 
    1396         367 :   return MATCHER_OK;
    1397             : }
    1398             : 
    1399             : static enum matcher_rv
    1400           0 : cmd_matcher_read_keywords(struct cmd_matcher *matcher,
    1401             :                           struct cmd_token *token,
    1402             :                           vector args_vector)
    1403             : {
    1404             :   unsigned int i;
    1405             :   unsigned long keyword_mask;
    1406             :   unsigned int keyword_found;
    1407             :   enum match_type keyword_match;
    1408             :   enum match_type word_match;
    1409             :   vector keyword_vector;
    1410             :   struct cmd_token *word_token;
    1411             :   const char *word;
    1412             :   int keyword_argc;
    1413             :   const char **keyword_argv;
    1414             :   enum matcher_rv rv;
    1415             : 
    1416           0 :   keyword_mask = 0;
    1417             :   while (1)
    1418             :     {
    1419           0 :       if (!cmd_matcher_words_left(matcher))
    1420           0 :         return MATCHER_OK;
    1421             : 
    1422           0 :       word = cmd_matcher_get_word(matcher);
    1423             : 
    1424           0 :       keyword_found = -1;
    1425           0 :       keyword_match = no_match;
    1426           0 :       for (i = 0; i < vector_active(token->keyword); i++)
    1427             :         {
    1428           0 :           if (keyword_mask & (1 << i))
    1429           0 :             continue;
    1430             : 
    1431           0 :           keyword_vector = vector_slot(token->keyword, i);
    1432           0 :           word_token = vector_slot(keyword_vector, 0);
    1433             : 
    1434           0 :           word_match = cmd_word_match(word_token, matcher->filter, word);
    1435           0 :           if (word_match == no_match)
    1436           0 :             continue;
    1437             : 
    1438           0 :           cmd_matcher_record_match(matcher, word_match, word_token);
    1439             : 
    1440           0 :           if (word_match > keyword_match)
    1441             :             {
    1442           0 :               keyword_match = word_match;
    1443           0 :               keyword_found = i;
    1444             :             }
    1445           0 :           else if (word_match == keyword_match)
    1446             :             {
    1447           0 :               if (matcher->word_index != matcher->index || args_vector)
    1448           0 :                 return MATCHER_AMBIGUOUS;
    1449             :             }
    1450             :         }
    1451             : 
    1452           0 :       if (keyword_found == (unsigned int)-1)
    1453           0 :         return MATCHER_NO_MATCH;
    1454             : 
    1455           0 :       matcher->word_index++;
    1456             : 
    1457           0 :       if (matcher->word_index > matcher->index)
    1458           0 :         return MATCHER_OK;
    1459             : 
    1460           0 :       keyword_mask |= (1 << keyword_found);
    1461             : 
    1462           0 :       if (args_vector)
    1463             :         {
    1464           0 :           keyword_argc = 0;
    1465           0 :           keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
    1466             :           /* We use -1 as a marker for unused fields as NULL might be a valid value */
    1467           0 :           for (i = 0; i < CMD_ARGC_MAX + 1; i++)
    1468           0 :             keyword_argv[i] = (void*)-1;
    1469           0 :           vector_set_index(args_vector, keyword_found, keyword_argv);
    1470             :         }
    1471             :       else
    1472             :         {
    1473           0 :           keyword_argv = NULL;
    1474             :         }
    1475             : 
    1476           0 :       keyword_vector = vector_slot(token->keyword, keyword_found);
    1477             :       /* the keyword itself is at 0. We are only interested in the arguments,
    1478             :        * so start counting at 1. */
    1479           0 :       for (i = 1; i < vector_active(keyword_vector); i++)
    1480             :         {
    1481           0 :           word_token = vector_slot(keyword_vector, i);
    1482             : 
    1483           0 :           switch (word_token->type)
    1484             :             {
    1485             :             case TOKEN_TERMINAL:
    1486           0 :               rv = cmd_matcher_match_terminal(matcher, word_token,
    1487             :                                               &keyword_argc, keyword_argv);
    1488           0 :               break;
    1489             :             case TOKEN_MULTIPLE:
    1490           0 :               rv = cmd_matcher_match_multiple(matcher, word_token,
    1491             :                                               &keyword_argc, keyword_argv);
    1492           0 :               break;
    1493             :             case TOKEN_KEYWORD:
    1494           0 :               assert(!"Keywords should never be nested.");
    1495             :               break;
    1496             :             }
    1497             : 
    1498           0 :           if (MATCHER_ERROR(rv))
    1499           0 :             return rv;
    1500             : 
    1501           0 :           if (matcher->word_index > matcher->index)
    1502           0 :             return MATCHER_OK;
    1503             :         }
    1504           0 :     }
    1505             :   /* not reached */
    1506             : }
    1507             : 
    1508             : static enum matcher_rv
    1509           0 : cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
    1510             :                                struct cmd_token *token,
    1511             :                                int *argc, const char **argv,
    1512             :                                vector keyword_args_vector)
    1513             : {
    1514             :   unsigned int i, j;
    1515             :   const char **keyword_args;
    1516             :   vector keyword_vector;
    1517             :   struct cmd_token *word_token;
    1518             :   const char *arg;
    1519             :   enum matcher_rv rv;
    1520             : 
    1521           0 :   rv = MATCHER_OK;
    1522             : 
    1523           0 :   if (keyword_args_vector == NULL)
    1524           0 :     return rv;
    1525             : 
    1526           0 :   for (i = 0; i < vector_active(token->keyword); i++)
    1527             :     {
    1528           0 :       keyword_vector = vector_slot(token->keyword, i);
    1529           0 :       keyword_args = vector_lookup(keyword_args_vector, i);
    1530             : 
    1531           0 :       if (vector_active(keyword_vector) == 1)
    1532             :         {
    1533             :           /* this is a keyword without arguments */
    1534           0 :           if (keyword_args)
    1535             :             {
    1536           0 :               word_token = vector_slot(keyword_vector, 0);
    1537           0 :               arg = word_token->cmd;
    1538             :             }
    1539             :           else
    1540             :             {
    1541           0 :               arg = NULL;
    1542             :             }
    1543             : 
    1544           0 :           if (push_argument(argc, argv, arg))
    1545           0 :             rv = MATCHER_EXCEED_ARGC_MAX;
    1546             :         }
    1547             :       else
    1548             :         {
    1549             :           /* this is a keyword with arguments */
    1550           0 :           if (keyword_args)
    1551             :             {
    1552             :               /* the keyword was present, so just fill in the arguments */
    1553           0 :               for (j = 0; keyword_args[j] != (void*)-1; j++)
    1554           0 :                 if (push_argument(argc, argv, keyword_args[j]))
    1555           0 :                   rv = MATCHER_EXCEED_ARGC_MAX;
    1556           0 :               XFREE(MTYPE_TMP, keyword_args);
    1557             :             }
    1558             :           else
    1559             :             {
    1560             :               /* the keyword was not present, insert NULL for the arguments
    1561             :                * the keyword would have taken. */
    1562           0 :               for (j = 1; j < vector_active(keyword_vector); j++)
    1563             :                 {
    1564           0 :                   word_token = vector_slot(keyword_vector, j);
    1565           0 :                   if ((word_token->type == TOKEN_TERMINAL
    1566           0 :                        && (CMD_VARARG(word_token->cmd)
    1567           0 :                            || CMD_VARIABLE(word_token->cmd)
    1568           0 :                            || CMD_OPTION(word_token->cmd)))
    1569           0 :                       || word_token->type == TOKEN_MULTIPLE)
    1570             :                     {
    1571           0 :                       if (push_argument(argc, argv, NULL))
    1572           0 :                         rv = MATCHER_EXCEED_ARGC_MAX;
    1573             :                     }
    1574             :                 }
    1575             :             }
    1576             :         }
    1577             :     }
    1578           0 :   vector_free(keyword_args_vector);
    1579           0 :   return rv;
    1580             : }
    1581             : 
    1582             : static enum matcher_rv
    1583           0 : cmd_matcher_match_keyword(struct cmd_matcher *matcher,
    1584             :                           struct cmd_token *token,
    1585             :                           int *argc, const char **argv)
    1586             : {
    1587             :   vector keyword_args_vector;
    1588             :   enum matcher_rv reader_rv;
    1589             :   enum matcher_rv builder_rv;
    1590             : 
    1591           0 :   assert(token->type == TOKEN_KEYWORD);
    1592             : 
    1593           0 :   if (argc && argv)
    1594           0 :     keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
    1595             :   else
    1596           0 :     keyword_args_vector = NULL;
    1597             : 
    1598           0 :   reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
    1599           0 :   builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
    1600             :                                               argv, keyword_args_vector);
    1601             :   /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
    1602             : 
    1603           0 :   if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
    1604           0 :     return builder_rv;
    1605             : 
    1606           0 :   return reader_rv;
    1607             : }
    1608             : 
    1609             : static void
    1610      126762 : cmd_matcher_init(struct cmd_matcher *matcher,
    1611             :                  struct cmd_element *cmd,
    1612             :                  enum filter_type filter,
    1613             :                  vector vline,
    1614             :                  unsigned int index,
    1615             :                  enum match_type *match_type,
    1616             :                  vector *match)
    1617             : {
    1618      126762 :   memset(matcher, 0, sizeof(*matcher));
    1619             : 
    1620      126762 :   matcher->cmd = cmd;
    1621      126762 :   matcher->filter = filter;
    1622      126762 :   matcher->vline = vline;
    1623      126762 :   matcher->index = index;
    1624             : 
    1625      126762 :   matcher->match_type = match_type;
    1626      126762 :   if (matcher->match_type)
    1627      124797 :     *matcher->match_type = no_match;
    1628      126762 :   matcher->match = match;
    1629             : 
    1630      126762 :   matcher->word_index = 0;
    1631      126762 : }
    1632             : 
    1633             : static enum matcher_rv
    1634      126762 : cmd_element_match(struct cmd_element *cmd_element,
    1635             :                   enum filter_type filter,
    1636             :                   vector vline,
    1637             :                   unsigned int index,
    1638             :                   enum match_type *match_type,
    1639             :                   vector *match,
    1640             :                   int *argc,
    1641             :                   const char **argv)
    1642             : {
    1643             :   struct cmd_matcher matcher;
    1644             :   unsigned int token_index;
    1645             :   enum matcher_rv rv;
    1646             : 
    1647      126762 :   cmd_matcher_init(&matcher, cmd_element, filter,
    1648             :                    vline, index, match_type, match);
    1649             : 
    1650      126762 :   if (argc != NULL)
    1651         581 :     *argc = 0;
    1652             : 
    1653      280481 :   for (token_index = 0;
    1654      153719 :        token_index < vector_active(cmd_element->tokens);
    1655       26957 :        token_index++)
    1656             :     {
    1657      152552 :       struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
    1658             : 
    1659      152552 :       switch (token->type)
    1660             :         {
    1661             :         case TOKEN_TERMINAL:
    1662      151864 :           rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
    1663      151864 :           break;
    1664             :         case TOKEN_MULTIPLE:
    1665         688 :           rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
    1666         688 :           break;
    1667             :         case TOKEN_KEYWORD:
    1668           0 :           rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
    1669             :         }
    1670             : 
    1671      152552 :       if (MATCHER_ERROR(rv))
    1672      106053 :         return rv;
    1673             : 
    1674       46499 :       if (matcher.word_index > index)
    1675       19542 :         return MATCHER_OK;
    1676             :     }
    1677             : 
    1678             :   /* return MATCHER_COMPLETE if all words were consumed */
    1679        1167 :   if (matcher.word_index >= vector_active(vline))
    1680        1162 :     return MATCHER_COMPLETE;
    1681             : 
    1682             :   /* return MATCHER_COMPLETE also if only an empty word is left. */
    1683           5 :   if (matcher.word_index == vector_active(vline) - 1
    1684           2 :       && (!vector_slot(vline, matcher.word_index)
    1685           2 :           || !strlen((char*)vector_slot(vline, matcher.word_index))))
    1686           0 :     return MATCHER_COMPLETE;
    1687             : 
    1688           5 :   return MATCHER_NO_MATCH; /* command is too long to match */
    1689             : }
    1690             : 
    1691             : /**
    1692             :  * Filter a given vector of commands against a given commandline and
    1693             :  * calculate possible completions.
    1694             :  *
    1695             :  * @param commands A vector of struct cmd_element*. Commands that don't
    1696             :  *                 match against the given command line will be overwritten
    1697             :  *                 with NULL in that vector.
    1698             :  * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
    1699             :  *               determines how incomplete commands are handled, compare with
    1700             :  *               cmd_word_match for details.
    1701             :  * @param vline A vector of char* containing the tokenized commandline.
    1702             :  * @param index Only match up to the given token of the commandline.
    1703             :  * @param match_type Record the type of the best match here.
    1704             :  * @param matches Record the matches here. For each cmd_element in the commands
    1705             :  *                vector, a match vector will be created in the matches vector.
    1706             :  *                That vector will contain all struct command_token* of the
    1707             :  *                cmd_element which matched against the given vline at the given
    1708             :  *                index.
    1709             :  * @return A code specifying if an error occured. If all went right, it's
    1710             :  *         CMD_SUCCESS.
    1711             :  */
    1712             : static int
    1713        1711 : cmd_vector_filter(vector commands,
    1714             :                   enum filter_type filter,
    1715             :                   vector vline,
    1716             :                   unsigned int index,
    1717             :                   enum match_type *match_type,
    1718             :                   vector *matches)
    1719             : {
    1720             :   unsigned int i;
    1721             :   struct cmd_element *cmd_element;
    1722             :   enum match_type best_match;
    1723             :   enum match_type element_match;
    1724             :   enum matcher_rv matcher_rv;
    1725             : 
    1726        1711 :   best_match = no_match;
    1727        1711 :   *matches = vector_init(VECTOR_MIN_SIZE);
    1728             : 
    1729      312716 :   for (i = 0; i < vector_active (commands); i++)
    1730      311005 :     if ((cmd_element = vector_slot (commands, i)) != NULL)
    1731             :       {
    1732      124797 :         vector_set_index(*matches, i, NULL);
    1733      249594 :         matcher_rv = cmd_element_match(cmd_element, filter,
    1734             :                                        vline, index,
    1735             :                                        &element_match,
    1736      249594 :                                        (vector*)&vector_slot(*matches, i),
    1737             :                                        NULL, NULL);
    1738      124797 :         if (MATCHER_ERROR(matcher_rv))
    1739             :           {
    1740      105255 :             vector_slot(commands, i) = NULL;
    1741      105255 :             if (matcher_rv == MATCHER_AMBIGUOUS)
    1742           0 :               return CMD_ERR_AMBIGUOUS;
    1743      210510 :             if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
    1744           0 :               return CMD_ERR_EXEED_ARGC_MAX;
    1745             :           }
    1746       19542 :         else if (element_match > best_match)
    1747             :           {
    1748        1655 :             best_match = element_match;
    1749             :           }
    1750             :       }
    1751        1711 :   *match_type = best_match;
    1752        1711 :   return CMD_SUCCESS;
    1753             : }
    1754             : 
    1755             : /**
    1756             :  * Check whether a given commandline is complete if used for a specific
    1757             :  * cmd_element.
    1758             :  *
    1759             :  * @param cmd_element A cmd_element against which the commandline should be
    1760             :  *                    checked.
    1761             :  * @param vline The tokenized commandline.
    1762             :  * @return 1 if the given commandline is complete, 0 otherwise.
    1763             :  */
    1764             : static int
    1765        1384 : cmd_is_complete(struct cmd_element *cmd_element,
    1766             :                 vector vline)
    1767             : {
    1768             :   enum matcher_rv rv;
    1769             : 
    1770        1384 :   rv = cmd_element_match(cmd_element,
    1771             :                          FILTER_RELAXED,
    1772             :                          vline, -1,
    1773             :                          NULL, NULL,
    1774             :                          NULL, NULL);
    1775        1384 :   return (rv == MATCHER_COMPLETE);
    1776             : }
    1777             : 
    1778             : /**
    1779             :  * Parse a given commandline and construct a list of arguments for the
    1780             :  * given command_element.
    1781             :  *
    1782             :  * @param cmd_element The cmd_element for which we want to construct arguments.
    1783             :  * @param vline The tokenized commandline.
    1784             :  * @param argc Where to store the argument count.
    1785             :  * @param argv Where to store the argument list. Should be at least
    1786             :  *             CMD_ARGC_MAX elements long.
    1787             :  * @return CMD_SUCCESS if everything went alright, an error otherwise.
    1788             :  */
    1789             : static int
    1790         581 : cmd_parse(struct cmd_element *cmd_element,
    1791             :           vector vline,
    1792             :           int *argc, const char **argv)
    1793             : {
    1794         581 :   enum matcher_rv rv = cmd_element_match(cmd_element,
    1795             :                                          FILTER_RELAXED,
    1796             :                                          vline, -1,
    1797             :                                          NULL, NULL,
    1798             :                                          argc, argv);
    1799         581 :   switch (rv)
    1800             :     {
    1801             :     case MATCHER_COMPLETE:
    1802         581 :       return CMD_SUCCESS;
    1803             : 
    1804             :     case MATCHER_NO_MATCH:
    1805           0 :       return CMD_ERR_NO_MATCH;
    1806             : 
    1807             :     case MATCHER_AMBIGUOUS:
    1808           0 :       return CMD_ERR_AMBIGUOUS;
    1809             : 
    1810             :     case MATCHER_EXCEED_ARGC_MAX:
    1811           0 :       return CMD_ERR_EXEED_ARGC_MAX;
    1812             : 
    1813             :     default:
    1814           0 :       return CMD_ERR_INCOMPLETE;
    1815             :     }
    1816             : }
    1817             : 
    1818             : /* Check ambiguous match */
    1819             : static int
    1820        1711 : is_cmd_ambiguous (vector cmd_vector,
    1821             :                   const char *command,
    1822             :                   vector matches,
    1823             :                   enum match_type type)
    1824             : {
    1825             :   unsigned int i;
    1826             :   unsigned int j;
    1827        1711 :   const char *str = NULL;
    1828        1711 :   const char *matched = NULL;
    1829             :   vector match_vector;
    1830             :   struct cmd_token *cmd_token;
    1831             : 
    1832        1711 :   if (command == NULL)
    1833           0 :     command = "";
    1834             : 
    1835      192083 :   for (i = 0; i < vector_active (matches); i++)
    1836      190372 :     if ((match_vector = vector_slot (matches, i)) != NULL)
    1837             :       {
    1838       19542 :         int match = 0;
    1839             : 
    1840       39094 :         for (j = 0; j < vector_active (match_vector); j++)
    1841       19552 :           if ((cmd_token = vector_slot (match_vector, j)) != NULL)
    1842             :             {
    1843             :               enum match_type ret;
    1844             : 
    1845       19552 :               assert(cmd_token->type == TOKEN_TERMINAL);
    1846       19552 :               if (cmd_token->type != TOKEN_TERMINAL)
    1847           0 :                 continue;
    1848             : 
    1849       19552 :               str = cmd_token->cmd;
    1850             : 
    1851       19552 :               switch (type)
    1852             :                 {
    1853             :                 case exact_match:
    1854       19152 :                   if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
    1855       19141 :                       && strcmp (command, str) == 0)
    1856       16807 :                     match++;
    1857       19152 :                   break;
    1858             :                 case partly_match:
    1859           0 :                   if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
    1860           0 :                       && strncmp (command, str, strlen (command)) == 0)
    1861             :                     {
    1862           0 :                       if (matched && strcmp (matched, str) != 0)
    1863           0 :                         return 1;       /* There is ambiguous match. */
    1864             :                       else
    1865           0 :                         matched = str;
    1866           0 :                       match++;
    1867             :                     }
    1868           0 :                   break;
    1869             :                 case range_match:
    1870         101 :                   if (cmd_range_match (str, command))
    1871             :                     {
    1872          83 :                       if (matched && strcmp (matched, str) != 0)
    1873           0 :                         return 1;
    1874             :                       else
    1875          83 :                         matched = str;
    1876          83 :                       match++;
    1877             :                     }
    1878         101 :                   break;
    1879             : #ifdef HAVE_IPV6
    1880             :                 case ipv6_match:
    1881           0 :                   if (CMD_IPV6 (str))
    1882           0 :                     match++;
    1883           0 :                   break;
    1884             :                 case ipv6_prefix_match:
    1885           1 :                   if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
    1886             :                     {
    1887           1 :                       if (ret == partly_match)
    1888           0 :                         return 2;       /* There is incomplete match. */
    1889             : 
    1890           1 :                       match++;
    1891             :                     }
    1892           1 :                   break;
    1893             : #endif /* HAVE_IPV6 */
    1894             :                 case ipv4_match:
    1895          20 :                   if (CMD_IPV4 (str))
    1896          16 :                     match++;
    1897          20 :                   break;
    1898             :                 case ipv4_prefix_match:
    1899          46 :                   if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
    1900             :                     {
    1901          46 :                       if (ret == partly_match)
    1902           0 :                         return 2;       /* There is incomplete match. */
    1903             : 
    1904          46 :                       match++;
    1905             :                     }
    1906          46 :                   break;
    1907             :                 case extend_match:
    1908         232 :                   if (CMD_OPTION (str) || CMD_VARIABLE (str))
    1909         232 :                     match++;
    1910         232 :                   break;
    1911             :                 case no_match:
    1912             :                 default:
    1913           0 :                   break;
    1914             :                 }
    1915             :             }
    1916       19542 :         if (!match)
    1917        2357 :           vector_slot (cmd_vector, i) = NULL;
    1918             :       }
    1919        1711 :   return 0;
    1920             : }
    1921             : 
    1922             : /* If src matches dst return dst string, otherwise return NULL */
    1923             : static const char *
    1924           0 : cmd_entry_function (const char *src, const char *dst)
    1925             : {
    1926             :   /* Skip variable arguments. */
    1927           0 :   if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
    1928           0 :       CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
    1929           0 :     return NULL;
    1930             : 
    1931             :   /* In case of 'command \t', given src is NULL string. */
    1932           0 :   if (src == NULL)
    1933           0 :     return dst;
    1934             : 
    1935             :   /* Matched with input string. */
    1936           0 :   if (strncmp (src, dst, strlen (src)) == 0)
    1937           0 :     return dst;
    1938             : 
    1939           0 :   return NULL;
    1940             : }
    1941             : 
    1942             : /* If src matches dst return dst string, otherwise return NULL */
    1943             : /* This version will return the dst string always if it is
    1944             :    CMD_VARIABLE for '?' key processing */
    1945             : static const char *
    1946           0 : cmd_entry_function_desc (const char *src, const char *dst)
    1947             : {
    1948           0 :   if (CMD_VARARG (dst))
    1949           0 :     return dst;
    1950             : 
    1951           0 :   if (CMD_RANGE (dst))
    1952             :     {
    1953           0 :       if (cmd_range_match (dst, src))
    1954           0 :         return dst;
    1955             :       else
    1956           0 :         return NULL;
    1957             :     }
    1958             : 
    1959             : #ifdef HAVE_IPV6
    1960           0 :   if (CMD_IPV6 (dst))
    1961             :     {
    1962           0 :       if (cmd_ipv6_match (src))
    1963           0 :         return dst;
    1964             :       else
    1965           0 :         return NULL;
    1966             :     }
    1967             : 
    1968           0 :   if (CMD_IPV6_PREFIX (dst))
    1969             :     {
    1970           0 :       if (cmd_ipv6_prefix_match (src))
    1971           0 :         return dst;
    1972             :       else
    1973           0 :         return NULL;
    1974             :     }
    1975             : #endif /* HAVE_IPV6 */
    1976             : 
    1977           0 :   if (CMD_IPV4 (dst))
    1978             :     {
    1979           0 :       if (cmd_ipv4_match (src))
    1980           0 :         return dst;
    1981             :       else
    1982           0 :         return NULL;
    1983             :     }
    1984             : 
    1985           0 :   if (CMD_IPV4_PREFIX (dst))
    1986             :     {
    1987           0 :       if (cmd_ipv4_prefix_match (src))
    1988           0 :         return dst;
    1989             :       else
    1990           0 :         return NULL;
    1991             :     }
    1992             : 
    1993             :   /* Optional or variable commands always match on '?' */
    1994           0 :   if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
    1995           0 :     return dst;
    1996             : 
    1997             :   /* In case of 'command \t', given src is NULL string. */
    1998           0 :   if (src == NULL)
    1999           0 :     return dst;
    2000             : 
    2001           0 :   if (strncmp (src, dst, strlen (src)) == 0)
    2002           0 :     return dst;
    2003             :   else
    2004           0 :     return NULL;
    2005             : }
    2006             : 
    2007             : /**
    2008             :  * Check whether a string is already present in a vector of strings.
    2009             :  * @param v A vector of char*.
    2010             :  * @param str A char*.
    2011             :  * @return 0 if str is already present in the vector, 1 otherwise.
    2012             :  */
    2013             : static int
    2014           0 : cmd_unique_string (vector v, const char *str)
    2015             : {
    2016             :   unsigned int i;
    2017             :   char *match;
    2018             : 
    2019           0 :   for (i = 0; i < vector_active (v); i++)
    2020           0 :     if ((match = vector_slot (v, i)) != NULL)
    2021           0 :       if (strcmp (match, str) == 0)
    2022           0 :         return 0;
    2023           0 :   return 1;
    2024             : }
    2025             : 
    2026             : /**
    2027             :  * Check whether a struct cmd_token matching a given string is already
    2028             :  * present in a vector of struct cmd_token.
    2029             :  * @param v A vector of struct cmd_token*.
    2030             :  * @param str A char* which should be searched for.
    2031             :  * @return 0 if there is a struct cmd_token* with its cmd matching str,
    2032             :  *         1 otherwise.
    2033             :  */
    2034             : static int
    2035           0 : desc_unique_string (vector v, const char *str)
    2036             : {
    2037             :   unsigned int i;
    2038             :   struct cmd_token *token;
    2039             : 
    2040           0 :   for (i = 0; i < vector_active (v); i++)
    2041           0 :     if ((token = vector_slot (v, i)) != NULL)
    2042           0 :       if (strcmp (token->cmd, str) == 0)
    2043           0 :         return 0;
    2044           0 :   return 1;
    2045             : }
    2046             : 
    2047             : static int 
    2048         581 : cmd_try_do_shortcut (enum node_type node, char* first_word) {
    2049         581 :   if ( first_word != NULL &&
    2050         581 :        node != AUTH_NODE &&
    2051         581 :        node != VIEW_NODE &&
    2052         581 :        node != AUTH_ENABLE_NODE &&
    2053         402 :        node != ENABLE_NODE &&
    2054         402 :        node != RESTRICTED_NODE &&
    2055         402 :        0 == strcmp( "do", first_word ) )
    2056           0 :     return 1;
    2057         581 :   return 0;
    2058             : }
    2059             : 
    2060             : static void
    2061        1711 : cmd_matches_free(vector *matches)
    2062             : {
    2063             :   unsigned int i;
    2064             :   vector cmd_matches;
    2065             : 
    2066      192083 :   for (i = 0; i < vector_active(*matches); i++)
    2067      190372 :     if ((cmd_matches = vector_slot(*matches, i)) != NULL)
    2068       19542 :       vector_free(cmd_matches);
    2069        1711 :   vector_free(*matches);
    2070        1711 :   *matches = NULL;
    2071        1711 : }
    2072             : 
    2073             : static int
    2074           0 : cmd_describe_cmp(const void *a, const void *b)
    2075             : {
    2076           0 :   const struct cmd_token *first = *(struct cmd_token * const *)a;
    2077           0 :   const struct cmd_token *second = *(struct cmd_token * const *)b;
    2078             : 
    2079           0 :   return strcmp(first->cmd, second->cmd);
    2080             : }
    2081             : 
    2082             : static void
    2083           0 : cmd_describe_sort(vector matchvec)
    2084             : {
    2085           0 :   qsort(matchvec->index, vector_active(matchvec),
    2086             :         sizeof(void*), cmd_describe_cmp);
    2087           0 : }
    2088             : 
    2089             : /* '?' describe command support. */
    2090             : static vector
    2091           0 : cmd_describe_command_real (vector vline, struct vty *vty, int *status)
    2092             : {
    2093             :   unsigned int i;
    2094             :   vector cmd_vector;
    2095             : #define INIT_MATCHVEC_SIZE 10
    2096             :   vector matchvec;
    2097             :   struct cmd_element *cmd_element;
    2098             :   unsigned int index;
    2099             :   int ret;
    2100             :   enum match_type match;
    2101             :   char *command;
    2102           0 :   vector matches = NULL;
    2103             :   vector match_vector;
    2104             : 
    2105             :   /* Set index. */
    2106           0 :   if (vector_active (vline) == 0)
    2107             :     {
    2108           0 :       *status = CMD_ERR_NO_MATCH;
    2109           0 :       return NULL;
    2110             :     }
    2111             : 
    2112           0 :   index = vector_active (vline) - 1;
    2113             : 
    2114             :   /* Make copy vector of current node's command vector. */
    2115           0 :   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
    2116             : 
    2117             :   /* Prepare match vector */
    2118           0 :   matchvec = vector_init (INIT_MATCHVEC_SIZE);
    2119             : 
    2120             :   /* Filter commands and build a list how they could possibly continue. */
    2121           0 :   for (i = 0; i <= index; i++)
    2122             :     {
    2123           0 :       command = vector_slot (vline, i);
    2124             : 
    2125           0 :       if (matches)
    2126           0 :         cmd_matches_free(&matches);
    2127             : 
    2128           0 :       ret = cmd_vector_filter(cmd_vector,
    2129             :                               FILTER_RELAXED,
    2130             :                               vline, i,
    2131             :                               &match,
    2132             :                               &matches);
    2133             : 
    2134           0 :       if (ret != CMD_SUCCESS)
    2135             :         {
    2136           0 :           vector_free (cmd_vector);
    2137           0 :           vector_free (matchvec);
    2138           0 :           cmd_matches_free(&matches);
    2139           0 :           *status = ret;
    2140           0 :           return NULL;
    2141             :         }
    2142             : 
    2143             :       /* The last match may well be ambigious, so break here */
    2144           0 :       if (i == index)
    2145           0 :         break;
    2146             : 
    2147           0 :       if (match == vararg_match)
    2148             :         {
    2149             :           /* We found a vararg match - so we can throw out the current matches here
    2150             :            * and don't need to continue checking the command input */
    2151             :           unsigned int j, k;
    2152             : 
    2153           0 :           for (j = 0; j < vector_active (matches); j++)
    2154           0 :             if ((match_vector = vector_slot (matches, j)) != NULL)
    2155           0 :               for (k = 0; k < vector_active (match_vector); k++)
    2156             :                 {
    2157           0 :                   struct cmd_token *token = vector_slot (match_vector, k);
    2158           0 :                   vector_set (matchvec, token);
    2159             :                 }
    2160             : 
    2161           0 :           *status = CMD_SUCCESS;
    2162           0 :           vector_set(matchvec, &token_cr);
    2163           0 :           vector_free (cmd_vector);
    2164           0 :           cmd_matches_free(&matches);
    2165           0 :           cmd_describe_sort(matchvec);
    2166           0 :           return matchvec;
    2167             :         }
    2168             : 
    2169           0 :       ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
    2170           0 :       if (ret == 1)
    2171             :         {
    2172           0 :           vector_free (cmd_vector);
    2173           0 :           vector_free (matchvec);
    2174           0 :           cmd_matches_free(&matches);
    2175           0 :           *status = CMD_ERR_AMBIGUOUS;
    2176           0 :           return NULL;
    2177             :         }
    2178           0 :       else if (ret == 2)
    2179             :         {
    2180           0 :           vector_free (cmd_vector);
    2181           0 :           vector_free (matchvec);
    2182           0 :           cmd_matches_free(&matches);
    2183           0 :           *status = CMD_ERR_NO_MATCH;
    2184           0 :           return NULL;
    2185             :         }
    2186             :     }
    2187             : 
    2188             :   /* Make description vector. */
    2189           0 :   for (i = 0; i < vector_active (matches); i++)
    2190           0 :     if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
    2191             :       {
    2192             :         unsigned int j;
    2193             :         const char *last_word;
    2194             :         vector vline_trimmed;
    2195             : 
    2196           0 :         last_word = vector_slot(vline, vector_active(vline) - 1);
    2197           0 :         if (last_word == NULL || !strlen(last_word))
    2198             :           {
    2199           0 :             vline_trimmed = vector_copy(vline);
    2200           0 :             vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
    2201             : 
    2202           0 :             if (cmd_is_complete(cmd_element, vline_trimmed)
    2203           0 :                 && desc_unique_string(matchvec, command_cr))
    2204             :               {
    2205           0 :                 if (match != vararg_match)
    2206           0 :                   vector_set(matchvec, &token_cr);
    2207             :               }
    2208             : 
    2209           0 :             vector_free(vline_trimmed);
    2210             :           }
    2211             : 
    2212           0 :         match_vector = vector_slot (matches, i);
    2213           0 :         if (match_vector)
    2214           0 :           for (j = 0; j < vector_active(match_vector); j++)
    2215             :             {
    2216           0 :               struct cmd_token *token = vector_slot(match_vector, j);
    2217             :               const char *string;
    2218             : 
    2219           0 :               string = cmd_entry_function_desc(command, token->cmd);
    2220           0 :               if (string && desc_unique_string(matchvec, string))
    2221           0 :                 vector_set(matchvec, token);
    2222             :             }
    2223             :       }
    2224           0 :   vector_free (cmd_vector);
    2225           0 :   cmd_matches_free(&matches);
    2226             : 
    2227           0 :   if (vector_slot (matchvec, 0) == NULL)
    2228             :     {
    2229           0 :       vector_free (matchvec);
    2230           0 :       *status = CMD_ERR_NO_MATCH;
    2231           0 :       return NULL;
    2232             :     }
    2233             : 
    2234           0 :   *status = CMD_SUCCESS;
    2235           0 :   cmd_describe_sort(matchvec);
    2236           0 :   return matchvec;
    2237             : }
    2238             : 
    2239             : vector
    2240           0 : cmd_describe_command (vector vline, struct vty *vty, int *status)
    2241             : {
    2242             :   vector ret;
    2243             : 
    2244           0 :   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
    2245             :     {
    2246             :       enum node_type onode;
    2247             :       vector shifted_vline;
    2248             :       unsigned int index;
    2249             : 
    2250           0 :       onode = vty->node;
    2251           0 :       vty->node = ENABLE_NODE;
    2252             :       /* We can try it on enable node, cos' the vty is authenticated */
    2253             : 
    2254           0 :       shifted_vline = vector_init (vector_count(vline));
    2255             :       /* use memcpy? */
    2256           0 :       for (index = 1; index < vector_active (vline); index++) 
    2257             :         {
    2258           0 :           vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
    2259             :         }
    2260             : 
    2261           0 :       ret = cmd_describe_command_real (shifted_vline, vty, status);
    2262             : 
    2263           0 :       vector_free(shifted_vline);
    2264           0 :       vty->node = onode;
    2265           0 :       return ret;
    2266             :   }
    2267             : 
    2268             : 
    2269           0 :   return cmd_describe_command_real (vline, vty, status);
    2270             : }
    2271             : 
    2272             : 
    2273             : /* Check LCD of matched command. */
    2274             : static int
    2275           0 : cmd_lcd (char **matched)
    2276             : {
    2277             :   int i;
    2278             :   int j;
    2279           0 :   int lcd = -1;
    2280             :   char *s1, *s2;
    2281             :   char c1, c2;
    2282             : 
    2283           0 :   if (matched[0] == NULL || matched[1] == NULL)
    2284           0 :     return 0;
    2285             : 
    2286           0 :   for (i = 1; matched[i] != NULL; i++)
    2287             :     {
    2288           0 :       s1 = matched[i - 1];
    2289           0 :       s2 = matched[i];
    2290             : 
    2291           0 :       for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
    2292           0 :         if (c1 != c2)
    2293           0 :           break;
    2294             : 
    2295           0 :       if (lcd < 0)
    2296           0 :         lcd = j;
    2297             :       else
    2298             :         {
    2299           0 :           if (lcd > j)
    2300           0 :             lcd = j;
    2301             :         }
    2302             :     }
    2303           0 :   return lcd;
    2304             : }
    2305             : 
    2306             : static int
    2307           0 : cmd_complete_cmp(const void *a, const void *b)
    2308             : {
    2309           0 :   const char *first = *(char * const *)a;
    2310           0 :   const char *second = *(char * const *)b;
    2311             : 
    2312           0 :   if (!first)
    2313             :     {
    2314           0 :       if (!second)
    2315           0 :         return 0;
    2316           0 :       return 1;
    2317             :     }
    2318           0 :   if (!second)
    2319           0 :     return -1;
    2320             : 
    2321           0 :   return strcmp(first, second);
    2322             : }
    2323             : 
    2324             : static void
    2325           0 : cmd_complete_sort(vector matchvec)
    2326             : {
    2327           0 :   qsort(matchvec->index, vector_active(matchvec),
    2328             :         sizeof(void*), cmd_complete_cmp);
    2329           0 : }
    2330             : 
    2331             : /* Command line completion support. */
    2332             : static char **
    2333           0 : cmd_complete_command_real (vector vline, struct vty *vty, int *status)
    2334             : {
    2335             :   unsigned int i;
    2336           0 :   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
    2337             : #define INIT_MATCHVEC_SIZE 10
    2338             :   vector matchvec;
    2339             :   unsigned int index;
    2340             :   char **match_str;
    2341             :   struct cmd_token *token;
    2342             :   char *command;
    2343             :   int lcd;
    2344           0 :   vector matches = NULL;
    2345             :   vector match_vector;
    2346             : 
    2347           0 :   if (vector_active (vline) == 0)
    2348             :     {
    2349           0 :       vector_free (cmd_vector);
    2350           0 :       *status = CMD_ERR_NO_MATCH;
    2351           0 :       return NULL;
    2352             :     }
    2353             :   else
    2354           0 :     index = vector_active (vline) - 1;
    2355             : 
    2356             :   /* First, filter by command string */
    2357           0 :   for (i = 0; i <= index; i++)
    2358             :     {
    2359           0 :       command = vector_slot (vline, i);
    2360             :       enum match_type match;
    2361             :       int ret;
    2362             : 
    2363           0 :       if (matches)
    2364           0 :         cmd_matches_free(&matches);
    2365             : 
    2366             :       /* First try completion match, if there is exactly match return 1 */
    2367           0 :       ret = cmd_vector_filter(cmd_vector,
    2368             :                               FILTER_RELAXED,
    2369             :                               vline, i,
    2370             :                               &match,
    2371             :                               &matches);
    2372             : 
    2373           0 :       if (ret != CMD_SUCCESS)
    2374             :         {
    2375           0 :           vector_free(cmd_vector);
    2376           0 :           cmd_matches_free(&matches);
    2377           0 :           *status = ret;
    2378           0 :           return NULL;
    2379             :         }
    2380             : 
    2381             :       /* Break here - the completion mustn't be checked to be non-ambiguous */
    2382           0 :       if (i == index)
    2383           0 :         break;
    2384             : 
    2385             :       /* If there is exact match then filter ambiguous match else check
    2386             :          ambiguousness. */
    2387           0 :       ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
    2388           0 :       if (ret == 1)
    2389             :         {
    2390           0 :           vector_free (cmd_vector);
    2391           0 :           cmd_matches_free(&matches);
    2392           0 :           *status = CMD_ERR_AMBIGUOUS;
    2393           0 :           return NULL;
    2394             :         }
    2395             :       /*
    2396             :            else if (ret == 2)
    2397             :            {
    2398             :            vector_free (cmd_vector);
    2399             :            cmd_matches_free(&matches);
    2400             :            *status = CMD_ERR_NO_MATCH;
    2401             :            return NULL;
    2402             :            }
    2403             :          */
    2404             :     }
    2405             :   
    2406             :   /* Prepare match vector. */
    2407           0 :   matchvec = vector_init (INIT_MATCHVEC_SIZE);
    2408             : 
    2409             :   /* Build the possible list of continuations into a list of completions */
    2410           0 :   for (i = 0; i < vector_active (matches); i++)
    2411           0 :     if ((match_vector = vector_slot (matches, i)))
    2412             :       {
    2413             :         const char *string;
    2414             :         unsigned int j;
    2415             : 
    2416           0 :         for (j = 0; j < vector_active (match_vector); j++)
    2417           0 :           if ((token = vector_slot (match_vector, j)))
    2418             :                 {
    2419           0 :                   if ((string = 
    2420           0 :                        cmd_entry_function (vector_slot (vline, index),
    2421           0 :                                            token->cmd)))
    2422           0 :                     if (cmd_unique_string (matchvec, string))
    2423           0 :                       vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
    2424             :                 }
    2425             :       }
    2426             : 
    2427             :   /* We don't need cmd_vector any more. */
    2428           0 :   vector_free (cmd_vector);
    2429           0 :   cmd_matches_free(&matches);
    2430             : 
    2431             :   /* No matched command */
    2432           0 :   if (vector_slot (matchvec, 0) == NULL)
    2433             :     {
    2434           0 :       vector_free (matchvec);
    2435             : 
    2436             :       /* In case of 'command \t' pattern.  Do you need '?' command at
    2437             :          the end of the line. */
    2438           0 :       if (vector_slot (vline, index) == '\0')
    2439           0 :         *status = CMD_ERR_NOTHING_TODO;
    2440             :       else
    2441           0 :         *status = CMD_ERR_NO_MATCH;
    2442           0 :       return NULL;
    2443             :     }
    2444             : 
    2445             :   /* Only one matched */
    2446           0 :   if (vector_slot (matchvec, 1) == NULL)
    2447             :     {
    2448           0 :       match_str = (char **) matchvec->index;
    2449           0 :       vector_only_wrapper_free (matchvec);
    2450           0 :       *status = CMD_COMPLETE_FULL_MATCH;
    2451           0 :       return match_str;
    2452             :     }
    2453             :   /* Make it sure last element is NULL. */
    2454           0 :   vector_set (matchvec, NULL);
    2455             : 
    2456             :   /* Check LCD of matched strings. */
    2457           0 :   if (vector_slot (vline, index) != NULL)
    2458             :     {
    2459           0 :       lcd = cmd_lcd ((char **) matchvec->index);
    2460             : 
    2461           0 :       if (lcd)
    2462             :         {
    2463           0 :           int len = strlen (vector_slot (vline, index));
    2464             : 
    2465           0 :           if (len < lcd)
    2466             :             {
    2467             :               char *lcdstr;
    2468             : 
    2469           0 :               lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
    2470           0 :               memcpy (lcdstr, matchvec->index[0], lcd);
    2471           0 :               lcdstr[lcd] = '\0';
    2472             : 
    2473             :               /* match_str = (char **) &lcdstr; */
    2474             : 
    2475             :               /* Free matchvec. */
    2476           0 :               for (i = 0; i < vector_active (matchvec); i++)
    2477             :                 {
    2478           0 :                   if (vector_slot (matchvec, i))
    2479           0 :                     XFREE (MTYPE_TMP, vector_slot (matchvec, i));
    2480             :                 }
    2481           0 :               vector_free (matchvec);
    2482             : 
    2483             :               /* Make new matchvec. */
    2484           0 :               matchvec = vector_init (INIT_MATCHVEC_SIZE);
    2485           0 :               vector_set (matchvec, lcdstr);
    2486           0 :               match_str = (char **) matchvec->index;
    2487           0 :               vector_only_wrapper_free (matchvec);
    2488             : 
    2489           0 :               *status = CMD_COMPLETE_MATCH;
    2490           0 :               return match_str;
    2491             :             }
    2492             :         }
    2493             :     }
    2494             : 
    2495           0 :   match_str = (char **) matchvec->index;
    2496           0 :   cmd_complete_sort(matchvec);
    2497           0 :   vector_only_wrapper_free (matchvec);
    2498           0 :   *status = CMD_COMPLETE_LIST_MATCH;
    2499           0 :   return match_str;
    2500             : }
    2501             : 
    2502             : char **
    2503           0 : cmd_complete_command (vector vline, struct vty *vty, int *status)
    2504             : {
    2505             :   char **ret;
    2506             : 
    2507           0 :   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
    2508             :     {
    2509             :       enum node_type onode;
    2510             :       vector shifted_vline;
    2511             :       unsigned int index;
    2512             : 
    2513           0 :       onode = vty->node;
    2514           0 :       vty->node = ENABLE_NODE;
    2515             :       /* We can try it on enable node, cos' the vty is authenticated */
    2516             : 
    2517           0 :       shifted_vline = vector_init (vector_count(vline));
    2518             :       /* use memcpy? */
    2519           0 :       for (index = 1; index < vector_active (vline); index++) 
    2520             :         {
    2521           0 :           vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
    2522             :         }
    2523             : 
    2524           0 :       ret = cmd_complete_command_real (shifted_vline, vty, status);
    2525             : 
    2526           0 :       vector_free(shifted_vline);
    2527           0 :       vty->node = onode;
    2528           0 :       return ret;
    2529             :   }
    2530             : 
    2531             : 
    2532           0 :   return cmd_complete_command_real (vline, vty, status);
    2533             : }
    2534             : 
    2535             : /* return parent node */
    2536             : /* MUST eventually converge on CONFIG_NODE */
    2537             : enum node_type
    2538          13 : node_parent ( enum node_type node )
    2539             : {
    2540             :   enum node_type ret;
    2541             : 
    2542          13 :   assert (node > CONFIG_NODE);
    2543             : 
    2544          13 :   switch (node)
    2545             :     {
    2546             :     case BGP_VPNV4_NODE:
    2547             :     case BGP_IPV4_NODE:
    2548             :     case BGP_IPV4M_NODE:
    2549             :     case BGP_IPV6_NODE:
    2550             :     case BGP_IPV6M_NODE:
    2551           0 :       ret = BGP_NODE;
    2552           0 :       break;
    2553             :     case KEYCHAIN_KEY_NODE:
    2554           0 :       ret = KEYCHAIN_NODE;
    2555           0 :       break;
    2556             :     default:
    2557          13 :       ret = CONFIG_NODE;
    2558             :     }
    2559             : 
    2560          13 :   return ret;
    2561             : }
    2562             : 
    2563             : /* Execute command by argument vline vector. */
    2564             : static int
    2565         594 : cmd_execute_command_real (vector vline,
    2566             :                           enum filter_type filter,
    2567             :                           struct vty *vty,
    2568             :                           struct cmd_element **cmd)
    2569             : {
    2570             :   unsigned int i;
    2571             :   unsigned int index;
    2572             :   vector cmd_vector;
    2573             :   struct cmd_element *cmd_element;
    2574             :   struct cmd_element *matched_element;
    2575             :   unsigned int matched_count, incomplete_count;
    2576             :   int argc;
    2577             :   const char *argv[CMD_ARGC_MAX];
    2578         594 :   enum match_type match = 0;
    2579             :   char *command;
    2580             :   int ret;
    2581             :   vector matches;
    2582             : 
    2583             :   /* Make copy of command elements. */
    2584         594 :   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
    2585             : 
    2586        2305 :   for (index = 0; index < vector_active (vline); index++)
    2587             :     {
    2588        1711 :       command = vector_slot (vline, index);
    2589        1711 :       ret = cmd_vector_filter(cmd_vector,
    2590             :                               filter,
    2591             :                               vline, index,
    2592             :                               &match,
    2593             :                               &matches);
    2594             : 
    2595        1711 :       if (ret != CMD_SUCCESS)
    2596             :         {
    2597           0 :           cmd_matches_free(&matches);
    2598           0 :           return ret;
    2599             :         }
    2600             : 
    2601        1711 :       if (match == vararg_match)
    2602             :         {
    2603           0 :           cmd_matches_free(&matches);
    2604           0 :           break;
    2605             :         }
    2606             : 
    2607        1711 :       ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
    2608        1711 :       cmd_matches_free(&matches);
    2609             : 
    2610        1711 :       if (ret == 1)
    2611             :         {
    2612           0 :           vector_free(cmd_vector);
    2613           0 :           return CMD_ERR_AMBIGUOUS;
    2614             :         }
    2615        1711 :       else if (ret == 2)
    2616             :         {
    2617           0 :           vector_free(cmd_vector);
    2618           0 :           return CMD_ERR_NO_MATCH;
    2619             :         }
    2620             :     }
    2621             : 
    2622             :   /* Check matched count. */
    2623         594 :   matched_element = NULL;
    2624         594 :   matched_count = 0;
    2625         594 :   incomplete_count = 0;
    2626             : 
    2627      109590 :   for (i = 0; i < vector_active (cmd_vector); i++)
    2628      108996 :     if ((cmd_element = vector_slot (cmd_vector, i)))
    2629             :       {
    2630        1384 :         if (cmd_is_complete(cmd_element, vline))
    2631             :           {
    2632         581 :             matched_element = cmd_element;
    2633         581 :             matched_count++;
    2634             :           }
    2635             :         else
    2636             :           {
    2637         803 :             incomplete_count++;
    2638             :           }
    2639             :       }
    2640             : 
    2641             :   /* Finish of using cmd_vector. */
    2642         594 :   vector_free (cmd_vector);
    2643             : 
    2644             :   /* To execute command, matched_count must be 1. */
    2645         594 :   if (matched_count == 0)
    2646             :     {
    2647          13 :       if (incomplete_count)
    2648           0 :         return CMD_ERR_INCOMPLETE;
    2649             :       else
    2650          13 :         return CMD_ERR_NO_MATCH;
    2651             :     }
    2652             : 
    2653         581 :   if (matched_count > 1)
    2654           0 :     return CMD_ERR_AMBIGUOUS;
    2655             : 
    2656         581 :   ret = cmd_parse(matched_element, vline, &argc, argv);
    2657         581 :   if (ret != CMD_SUCCESS)
    2658           0 :     return ret;
    2659             : 
    2660             :   /* For vtysh execution. */
    2661         581 :   if (cmd)
    2662           0 :     *cmd = matched_element;
    2663             : 
    2664         581 :   if (matched_element->daemon)
    2665           0 :     return CMD_SUCCESS_DAEMON;
    2666             : 
    2667             :   /* Execute matched command. */
    2668         581 :   return (*matched_element->func) (matched_element, vty, argc, argv);
    2669             : }
    2670             : 
    2671             : /**
    2672             :  * Execute a given command, handling things like "do ..." and checking
    2673             :  * whether the given command might apply at a parent node if doesn't
    2674             :  * apply for the current node.
    2675             :  *
    2676             :  * @param vline Command line input, vector of char* where each element is
    2677             :  *              one input token.
    2678             :  * @param vty The vty context in which the command should be executed.
    2679             :  * @param cmd Pointer where the struct cmd_element of the matched command
    2680             :  *            will be stored, if any. May be set to NULL if this info is
    2681             :  *            not needed.
    2682             :  * @param vtysh If set != 0, don't lookup the command at parent nodes.
    2683             :  * @return The status of the command that has been executed or an error code
    2684             :  *         as to why no command could be executed.
    2685             :  */
    2686             : int
    2687         581 : cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
    2688             :                      int vtysh) {
    2689         581 :   int ret, saved_ret, tried = 0;
    2690             :   enum node_type onode, try_node;
    2691             : 
    2692         581 :   onode = try_node = vty->node;
    2693             : 
    2694         581 :   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
    2695             :     {
    2696             :       vector shifted_vline;
    2697             :       unsigned int index;
    2698             : 
    2699           0 :       vty->node = ENABLE_NODE;
    2700             :       /* We can try it on enable node, cos' the vty is authenticated */
    2701             : 
    2702           0 :       shifted_vline = vector_init (vector_count(vline));
    2703             :       /* use memcpy? */
    2704           0 :       for (index = 1; index < vector_active (vline); index++) 
    2705             :         {
    2706           0 :           vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
    2707             :         }
    2708             : 
    2709           0 :       ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
    2710             : 
    2711           0 :       vector_free(shifted_vline);
    2712           0 :       vty->node = onode;
    2713           0 :       return ret;
    2714             :   }
    2715             : 
    2716             : 
    2717         581 :   saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
    2718             : 
    2719         581 :   if (vtysh)
    2720           0 :     return saved_ret;
    2721             : 
    2722             :   /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
    2723        1162 :   while ( ret != CMD_SUCCESS && ret != CMD_WARNING 
    2724          13 :           && vty->node > CONFIG_NODE )
    2725             :     {
    2726          13 :       try_node = node_parent(try_node);
    2727          13 :       vty->node = try_node;
    2728          13 :       ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
    2729          13 :       tried = 1;
    2730          13 :       if (ret == CMD_SUCCESS || ret == CMD_WARNING)
    2731             :         {
    2732             :           /* succesfull command, leave the node as is */
    2733          13 :           return ret;
    2734             :         }
    2735             :     }
    2736             :   /* no command succeeded, reset the vty to the original node and
    2737             :      return the error for this node */
    2738         568 :   if ( tried )
    2739           0 :     vty->node = onode;
    2740         568 :   return saved_ret;
    2741             : }
    2742             : 
    2743             : /**
    2744             :  * Execute a given command, matching it strictly against the current node.
    2745             :  * This mode is used when reading config files.
    2746             :  *
    2747             :  * @param vline Command line input, vector of char* where each element is
    2748             :  *              one input token.
    2749             :  * @param vty The vty context in which the command should be executed.
    2750             :  * @param cmd Pointer where the struct cmd_element* of the matched command
    2751             :  *            will be stored, if any. May be set to NULL if this info is
    2752             :  *            not needed.
    2753             :  * @return The status of the command that has been executed or an error code
    2754             :  *         as to why no command could be executed.
    2755             :  */
    2756             : int
    2757           0 : cmd_execute_command_strict (vector vline, struct vty *vty,
    2758             :                             struct cmd_element **cmd)
    2759             : {
    2760           0 :   return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
    2761             : }
    2762             : 
    2763             : /* Configration make from file. */
    2764             : int
    2765          45 : config_from_file (struct vty *vty, FILE *fp)
    2766             : {
    2767             :   int ret;
    2768             :   vector vline;
    2769             : 
    2770          45 :   while (fgets (vty->buf, VTY_BUFSIZ, fp))
    2771             :     {
    2772           0 :       vline = cmd_make_strvec (vty->buf);
    2773             : 
    2774             :       /* In case of comment line */
    2775           0 :       if (vline == NULL)
    2776           0 :         continue;
    2777             :       /* Execute configuration command : this is strict match */
    2778           0 :       ret = cmd_execute_command_strict (vline, vty, NULL);
    2779             : 
    2780             :       /* Try again with setting node to CONFIG_NODE */
    2781           0 :       while (ret != CMD_SUCCESS && ret != CMD_WARNING
    2782           0 :              && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
    2783             :         {
    2784           0 :           vty->node = node_parent(vty->node);
    2785           0 :           ret = cmd_execute_command_strict (vline, vty, NULL);
    2786             :         }
    2787             : 
    2788           0 :       cmd_free_strvec (vline);
    2789             : 
    2790           0 :       if (ret != CMD_SUCCESS && ret != CMD_WARNING
    2791           0 :           && ret != CMD_ERR_NOTHING_TODO)
    2792           0 :         return ret;
    2793             :     }
    2794          45 :   return CMD_SUCCESS;
    2795             : }
    2796             : 
    2797             : /* Configration from terminal */
    2798          66 : DEFUN (config_terminal,
    2799             :        config_terminal_cmd,
    2800             :        "configure terminal",
    2801             :        "Configuration from vty interface\n"
    2802             :        "Configuration terminal\n")
    2803             : {
    2804          66 :   if (vty_config_lock (vty))
    2805          66 :     vty->node = CONFIG_NODE;
    2806             :   else
    2807             :     {
    2808           0 :       vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
    2809           0 :       return CMD_WARNING;
    2810             :     }
    2811          66 :   return CMD_SUCCESS;
    2812             : }
    2813             : 
    2814             : /* Enable command */
    2815           0 : DEFUN (enable, 
    2816             :        config_enable_cmd,
    2817             :        "enable",
    2818             :        "Turn on privileged mode command\n")
    2819             : {
    2820             :   /* If enable password is NULL, change to ENABLE_NODE */
    2821           0 :   if ((host.enable == NULL && host.enable_encrypt == NULL) ||
    2822           0 :       vty->type == VTY_SHELL_SERV)
    2823           0 :     vty->node = ENABLE_NODE;
    2824             :   else
    2825           0 :     vty->node = AUTH_ENABLE_NODE;
    2826             : 
    2827           0 :   return CMD_SUCCESS;
    2828             : }
    2829             : 
    2830             : /* Disable command */
    2831           0 : DEFUN (disable, 
    2832             :        config_disable_cmd,
    2833             :        "disable",
    2834             :        "Turn off privileged mode command\n")
    2835             : {
    2836           0 :   if (vty->node == ENABLE_NODE)
    2837           0 :     vty->node = VIEW_NODE;
    2838           0 :   return CMD_SUCCESS;
    2839             : }
    2840             : 
    2841             : /* Down vty node level. */
    2842           0 : DEFUN (config_exit,
    2843             :        config_exit_cmd,
    2844             :        "exit",
    2845             :        "Exit current mode and down to previous mode\n")
    2846             : {
    2847           0 :   switch (vty->node)
    2848             :     {
    2849             :     case VIEW_NODE:
    2850             :     case ENABLE_NODE:
    2851             :     case RESTRICTED_NODE:
    2852           0 :       if (vty_shell (vty))
    2853           0 :         exit (0);
    2854             :       else
    2855           0 :         vty->status = VTY_CLOSE;
    2856           0 :       break;
    2857             :     case CONFIG_NODE:
    2858           0 :       vty->node = ENABLE_NODE;
    2859           0 :       vty_config_unlock (vty);
    2860           0 :       break;
    2861             :     case INTERFACE_NODE:
    2862             :     case ZEBRA_NODE:
    2863             :     case BGP_NODE:
    2864             :     case RIP_NODE:
    2865             :     case RIPNG_NODE:
    2866             :     case BABEL_NODE:
    2867             :     case OSPF_NODE:
    2868             :     case OSPF6_NODE:
    2869             :     case ISIS_NODE:
    2870             :     case KEYCHAIN_NODE:
    2871             :     case MASC_NODE:
    2872             :     case RMAP_NODE:
    2873             :     case VTY_NODE:
    2874           0 :       vty->node = CONFIG_NODE;
    2875           0 :       break;
    2876             :     case BGP_VPNV4_NODE:
    2877             :     case BGP_IPV4_NODE:
    2878             :     case BGP_IPV4M_NODE:
    2879             :     case BGP_IPV6_NODE:
    2880             :     case BGP_IPV6M_NODE:
    2881           0 :       vty->node = BGP_NODE;
    2882           0 :       break;
    2883             :     case KEYCHAIN_KEY_NODE:
    2884           0 :       vty->node = KEYCHAIN_NODE;
    2885           0 :       break;
    2886             :     default:
    2887           0 :       break;
    2888             :     }
    2889           0 :   return CMD_SUCCESS;
    2890             : }
    2891             : 
    2892             : /* quit is alias of exit. */
    2893             : ALIAS (config_exit,
    2894             :        config_quit_cmd,
    2895             :        "quit",
    2896             :        "Exit current mode and down to previous mode\n")
    2897             :        
    2898             : /* End of configuration. */
    2899          66 : DEFUN (config_end,
    2900             :        config_end_cmd,
    2901             :        "end",
    2902             :        "End current mode and change to enable mode.")
    2903             : {
    2904          66 :   switch (vty->node)
    2905             :     {
    2906             :     case VIEW_NODE:
    2907             :     case ENABLE_NODE:
    2908             :     case RESTRICTED_NODE:
    2909             :       /* Nothing to do. */
    2910           0 :       break;
    2911             :     case CONFIG_NODE:
    2912             :     case INTERFACE_NODE:
    2913             :     case ZEBRA_NODE:
    2914             :     case RIP_NODE:
    2915             :     case RIPNG_NODE:
    2916             :     case BABEL_NODE:
    2917             :     case BGP_NODE:
    2918             :     case BGP_VPNV4_NODE:
    2919             :     case BGP_IPV4_NODE:
    2920             :     case BGP_IPV4M_NODE:
    2921             :     case BGP_IPV6_NODE:
    2922             :     case BGP_IPV6M_NODE:
    2923             :     case RMAP_NODE:
    2924             :     case OSPF_NODE:
    2925             :     case OSPF6_NODE:
    2926             :     case ISIS_NODE:
    2927             :     case KEYCHAIN_NODE:
    2928             :     case KEYCHAIN_KEY_NODE:
    2929             :     case MASC_NODE:
    2930             :     case VTY_NODE:
    2931          66 :       vty_config_unlock (vty);
    2932          66 :       vty->node = ENABLE_NODE;
    2933          66 :       break;
    2934             :     default:
    2935           0 :       break;
    2936             :     }
    2937          66 :   return CMD_SUCCESS;
    2938             : }
    2939             : 
    2940             : /* Show version. */
    2941           0 : DEFUN (show_version,
    2942             :        show_version_cmd,
    2943             :        "show version",
    2944             :        SHOW_STR
    2945             :        "Displays zebra version\n")
    2946             : {
    2947           0 :   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
    2948           0 :            VTY_NEWLINE);
    2949           0 :   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
    2950             : 
    2951           0 :   return CMD_SUCCESS;
    2952             : }
    2953             : 
    2954             : /* Help display function for all node. */
    2955           0 : DEFUN (config_help,
    2956             :        config_help_cmd,
    2957             :        "help",
    2958             :        "Description of the interactive help system\n")
    2959             : {
    2960           0 :   vty_out (vty, 
    2961             :            "Quagga VTY provides advanced help feature.  When you need help,%s\
    2962             : anytime at the command line please press '?'.%s\
    2963             : %s\
    2964             : If nothing matches, the help list will be empty and you must backup%s\
    2965             :  until entering a '?' shows the available options.%s\
    2966             : Two styles of help are provided:%s\
    2967             : 1. Full help is available when you are ready to enter a%s\
    2968             : command argument (e.g. 'show ?') and describes each possible%s\
    2969             : argument.%s\
    2970             : 2. Partial help is provided when an abbreviated argument is entered%s\
    2971             :    and you want to know what arguments match the input%s\
    2972           0 :    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
    2973           0 :            VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
    2974           0 :            VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
    2975           0 :   return CMD_SUCCESS;
    2976             : }
    2977             : 
    2978             : /* Help display function for all node. */
    2979           0 : DEFUN (config_list,
    2980             :        config_list_cmd,
    2981             :        "list",
    2982             :        "Print command list\n")
    2983             : {
    2984             :   unsigned int i;
    2985           0 :   struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
    2986             :   struct cmd_element *cmd;
    2987             : 
    2988           0 :   for (i = 0; i < vector_active (cnode->cmd_vector); i++)
    2989           0 :     if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
    2990           0 :         && !(cmd->attr == CMD_ATTR_DEPRECATED
    2991           0 :              || cmd->attr == CMD_ATTR_HIDDEN))
    2992           0 :       vty_out (vty, "  %s%s", cmd->string,
    2993           0 :                VTY_NEWLINE);
    2994           0 :   return CMD_SUCCESS;
    2995             : }
    2996             : 
    2997             : /* Write current configuration into file. */
    2998           0 : DEFUN (config_write_file, 
    2999             :        config_write_file_cmd,
    3000             :        "write file",  
    3001             :        "Write running configuration to memory, network, or terminal\n"
    3002             :        "Write to configuration file\n")
    3003             : {
    3004             :   unsigned int i;
    3005             :   int fd;
    3006             :   struct cmd_node *node;
    3007             :   char *config_file;
    3008           0 :   char *config_file_tmp = NULL;
    3009           0 :   char *config_file_sav = NULL;
    3010           0 :   int ret = CMD_WARNING;
    3011             :   struct vty *file_vty;
    3012             : 
    3013             :   /* Check and see if we are operating under vtysh configuration */
    3014           0 :   if (host.config == NULL)
    3015             :     {
    3016           0 :       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
    3017           0 :                VTY_NEWLINE);
    3018           0 :       return CMD_WARNING;
    3019             :     }
    3020             : 
    3021             :   /* Get filename. */
    3022           0 :   config_file = host.config;
    3023             :   
    3024           0 :   config_file_sav =
    3025           0 :     XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
    3026           0 :   strcpy (config_file_sav, config_file);
    3027           0 :   strcat (config_file_sav, CONF_BACKUP_EXT);
    3028             : 
    3029             : 
    3030           0 :   config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
    3031           0 :   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
    3032             :   
    3033             :   /* Open file to configuration write. */
    3034           0 :   fd = mkstemp (config_file_tmp);
    3035           0 :   if (fd < 0)
    3036             :     {
    3037           0 :       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
    3038           0 :                VTY_NEWLINE);
    3039           0 :       goto finished;
    3040             :     }
    3041             :   
    3042             :   /* Make vty for configuration file. */
    3043           0 :   file_vty = vty_new ();
    3044           0 :   file_vty->fd = fd;
    3045           0 :   file_vty->type = VTY_FILE;
    3046             : 
    3047             :   /* Config file header print. */
    3048           0 :   vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
    3049           0 :   vty_time_print (file_vty, 1);
    3050           0 :   vty_out (file_vty, "!\n");
    3051             : 
    3052           0 :   for (i = 0; i < vector_active (cmdvec); i++)
    3053           0 :     if ((node = vector_slot (cmdvec, i)) && node->func)
    3054             :       {
    3055           0 :         if ((*node->func) (file_vty))
    3056           0 :           vty_out (file_vty, "!\n");
    3057             :       }
    3058           0 :   vty_close (file_vty);
    3059             : 
    3060           0 :   if (unlink (config_file_sav) != 0)
    3061           0 :     if (errno != ENOENT)
    3062             :       {
    3063           0 :         vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
    3064           0 :                  VTY_NEWLINE);
    3065           0 :         goto finished;
    3066             :       }
    3067           0 :   if (link (config_file, config_file_sav) != 0)
    3068             :     {
    3069           0 :       vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
    3070           0 :                 VTY_NEWLINE);
    3071           0 :       goto finished;
    3072             :     }
    3073           0 :   sync ();
    3074           0 :   if (unlink (config_file) != 0)
    3075             :     {
    3076           0 :       vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
    3077           0 :                 VTY_NEWLINE);
    3078           0 :       goto finished;
    3079             :     }
    3080           0 :   if (link (config_file_tmp, config_file) != 0)
    3081             :     {
    3082           0 :       vty_out (vty, "Can't save configuration file %s.%s", config_file,
    3083           0 :                VTY_NEWLINE);
    3084           0 :       goto finished;
    3085             :     }
    3086           0 :   sync ();
    3087             :   
    3088           0 :   if (chmod (config_file, CONFIGFILE_MASK) != 0)
    3089             :     {
    3090           0 :       vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s", 
    3091           0 :         config_file, safe_strerror(errno), errno, VTY_NEWLINE);
    3092           0 :       goto finished;
    3093             :     }
    3094             : 
    3095           0 :   vty_out (vty, "Configuration saved to %s%s", config_file,
    3096           0 :            VTY_NEWLINE);
    3097           0 :   ret = CMD_SUCCESS;
    3098             : 
    3099             : finished:
    3100           0 :   unlink (config_file_tmp);
    3101           0 :   XFREE (MTYPE_TMP, config_file_tmp);
    3102           0 :   XFREE (MTYPE_TMP, config_file_sav);
    3103           0 :   return ret;
    3104             : }
    3105             : 
    3106             : ALIAS (config_write_file, 
    3107             :        config_write_cmd,
    3108             :        "write",  
    3109             :        "Write running configuration to memory, network, or terminal\n")
    3110             : 
    3111             : ALIAS (config_write_file, 
    3112             :        config_write_memory_cmd,
    3113             :        "write memory",  
    3114             :        "Write running configuration to memory, network, or terminal\n"
    3115             :        "Write configuration to the file (same as write file)\n")
    3116             : 
    3117             : ALIAS (config_write_file, 
    3118             :        copy_runningconfig_startupconfig_cmd,
    3119             :        "copy running-config startup-config",  
    3120             :        "Copy configuration\n"
    3121             :        "Copy running config to... \n"
    3122             :        "Copy running config to startup config (same as write file)\n")
    3123             : 
    3124             : /* Write current configuration into the terminal. */
    3125           0 : DEFUN (config_write_terminal,
    3126             :        config_write_terminal_cmd,
    3127             :        "write terminal",
    3128             :        "Write running configuration to memory, network, or terminal\n"
    3129             :        "Write to terminal\n")
    3130             : {
    3131             :   unsigned int i;
    3132             :   struct cmd_node *node;
    3133             : 
    3134           0 :   if (vty->type == VTY_SHELL_SERV)
    3135             :     {
    3136           0 :       for (i = 0; i < vector_active (cmdvec); i++)
    3137           0 :         if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
    3138             :           {
    3139           0 :             if ((*node->func) (vty))
    3140           0 :               vty_out (vty, "!%s", VTY_NEWLINE);
    3141             :           }
    3142             :     }
    3143             :   else
    3144             :     {
    3145           0 :       vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
    3146           0 :                VTY_NEWLINE);
    3147           0 :       vty_out (vty, "!%s", VTY_NEWLINE);
    3148             : 
    3149           0 :       for (i = 0; i < vector_active (cmdvec); i++)
    3150           0 :         if ((node = vector_slot (cmdvec, i)) && node->func)
    3151             :           {
    3152           0 :             if ((*node->func) (vty))
    3153           0 :               vty_out (vty, "!%s", VTY_NEWLINE);
    3154             :           }
    3155           0 :       vty_out (vty, "end%s",VTY_NEWLINE);
    3156             :     }
    3157           0 :   return CMD_SUCCESS;
    3158             : }
    3159             : 
    3160             : /* Write current configuration into the terminal. */
    3161             : ALIAS (config_write_terminal,
    3162             :        show_running_config_cmd,
    3163             :        "show running-config",
    3164             :        SHOW_STR
    3165             :        "running configuration\n")
    3166             : 
    3167             : /* Write startup configuration into the terminal. */
    3168           0 : DEFUN (show_startup_config,
    3169             :        show_startup_config_cmd,
    3170             :        "show startup-config",
    3171             :        SHOW_STR
    3172             :        "Contentes of startup configuration\n")
    3173             : {
    3174             :   char buf[BUFSIZ];
    3175             :   FILE *confp;
    3176             : 
    3177           0 :   confp = fopen (host.config, "r");
    3178           0 :   if (confp == NULL)
    3179             :     {
    3180           0 :       vty_out (vty, "Can't open configuration file [%s]%s",
    3181           0 :                host.config, VTY_NEWLINE);
    3182           0 :       return CMD_WARNING;
    3183             :     }
    3184             : 
    3185           0 :   while (fgets (buf, BUFSIZ, confp))
    3186             :     {
    3187           0 :       char *cp = buf;
    3188             : 
    3189           0 :       while (*cp != '\r' && *cp != '\n' && *cp != '\0')
    3190           0 :         cp++;
    3191           0 :       *cp = '\0';
    3192             : 
    3193           0 :       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
    3194             :     }
    3195             : 
    3196           0 :   fclose (confp);
    3197             : 
    3198           0 :   return CMD_SUCCESS;
    3199             : }
    3200             : 
    3201             : /* Hostname configuration */
    3202           0 : DEFUN (config_hostname, 
    3203             :        hostname_cmd,
    3204             :        "hostname WORD",
    3205             :        "Set system's network name\n"
    3206             :        "This system's network name\n")
    3207             : {
    3208           0 :   if (!isalpha((int) *argv[0]))
    3209             :     {
    3210           0 :       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
    3211           0 :       return CMD_WARNING;
    3212             :     }
    3213             : 
    3214           0 :   if (host.name)
    3215           0 :     XFREE (MTYPE_HOST, host.name);
    3216             :     
    3217           0 :   host.name = XSTRDUP (MTYPE_HOST, argv[0]);
    3218           0 :   return CMD_SUCCESS;
    3219             : }
    3220             : 
    3221           0 : DEFUN (config_no_hostname, 
    3222             :        no_hostname_cmd,
    3223             :        "no hostname [HOSTNAME]",
    3224             :        NO_STR
    3225             :        "Reset system's network name\n"
    3226             :        "Host name of this router\n")
    3227             : {
    3228           0 :   if (host.name)
    3229           0 :     XFREE (MTYPE_HOST, host.name);
    3230           0 :   host.name = NULL;
    3231           0 :   return CMD_SUCCESS;
    3232             : }
    3233             : 
    3234             : /* VTY interface password set. */
    3235           0 : DEFUN (config_password, password_cmd,
    3236             :        "password (8|) WORD",
    3237             :        "Assign the terminal connection password\n"
    3238             :        "Specifies a HIDDEN password will follow\n"
    3239             :        "dummy string \n"
    3240             :        "The HIDDEN line password string\n")
    3241             : {
    3242             :   /* Argument check. */
    3243           0 :   if (argc == 0)
    3244             :     {
    3245           0 :       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
    3246           0 :       return CMD_WARNING;
    3247             :     }
    3248             : 
    3249           0 :   if (argc == 2)
    3250             :     {
    3251           0 :       if (*argv[0] == '8')
    3252             :         {
    3253           0 :           if (host.password)
    3254           0 :             XFREE (MTYPE_HOST, host.password);
    3255           0 :           host.password = NULL;
    3256           0 :           if (host.password_encrypt)
    3257           0 :             XFREE (MTYPE_HOST, host.password_encrypt);
    3258           0 :           host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
    3259           0 :           return CMD_SUCCESS;
    3260             :         }
    3261             :       else
    3262             :         {
    3263           0 :           vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
    3264           0 :           return CMD_WARNING;
    3265             :         }
    3266             :     }
    3267             : 
    3268           0 :   if (!isalnum ((int) *argv[0]))
    3269             :     {
    3270           0 :       vty_out (vty, 
    3271           0 :                "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
    3272           0 :       return CMD_WARNING;
    3273             :     }
    3274             : 
    3275           0 :   if (host.password)
    3276           0 :     XFREE (MTYPE_HOST, host.password);
    3277           0 :   host.password = NULL;
    3278             : 
    3279           0 :   if (host.encrypt)
    3280             :     {
    3281           0 :       if (host.password_encrypt)
    3282           0 :         XFREE (MTYPE_HOST, host.password_encrypt);
    3283           0 :       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
    3284             :     }
    3285             :   else
    3286           0 :     host.password = XSTRDUP (MTYPE_HOST, argv[0]);
    3287             : 
    3288           0 :   return CMD_SUCCESS;
    3289             : }
    3290             : 
    3291             : ALIAS (config_password, password_text_cmd,
    3292             :        "password LINE",
    3293             :        "Assign the terminal connection password\n"
    3294             :        "The UNENCRYPTED (cleartext) line password\n")
    3295             : 
    3296             : /* VTY enable password set. */
    3297           0 : DEFUN (config_enable_password, enable_password_cmd,
    3298             :        "enable password (8|) WORD",
    3299             :        "Modify enable password parameters\n"
    3300             :        "Assign the privileged level password\n"
    3301             :        "Specifies a HIDDEN password will follow\n"
    3302             :        "dummy string \n"
    3303             :        "The HIDDEN 'enable' password string\n")
    3304             : {
    3305             :   /* Argument check. */
    3306           0 :   if (argc == 0)
    3307             :     {
    3308           0 :       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
    3309           0 :       return CMD_WARNING;
    3310             :     }
    3311             : 
    3312             :   /* Crypt type is specified. */
    3313           0 :   if (argc == 2)
    3314             :     {
    3315           0 :       if (*argv[0] == '8')
    3316             :         {
    3317           0 :           if (host.enable)
    3318           0 :             XFREE (MTYPE_HOST, host.enable);
    3319           0 :           host.enable = NULL;
    3320             : 
    3321           0 :           if (host.enable_encrypt)
    3322           0 :             XFREE (MTYPE_HOST, host.enable_encrypt);
    3323           0 :           host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
    3324             : 
    3325           0 :           return CMD_SUCCESS;
    3326             :         }
    3327             :       else
    3328             :         {
    3329           0 :           vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
    3330           0 :           return CMD_WARNING;
    3331             :         }
    3332             :     }
    3333             : 
    3334           0 :   if (!isalnum ((int) *argv[0]))
    3335             :     {
    3336           0 :       vty_out (vty, 
    3337           0 :                "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
    3338           0 :       return CMD_WARNING;
    3339             :     }
    3340             : 
    3341           0 :   if (host.enable)
    3342           0 :     XFREE (MTYPE_HOST, host.enable);
    3343           0 :   host.enable = NULL;
    3344             : 
    3345             :   /* Plain password input. */
    3346           0 :   if (host.encrypt)
    3347             :     {
    3348           0 :       if (host.enable_encrypt)
    3349           0 :         XFREE (MTYPE_HOST, host.enable_encrypt);
    3350           0 :       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
    3351             :     }
    3352             :   else
    3353           0 :     host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
    3354             : 
    3355           0 :   return CMD_SUCCESS;
    3356             : }
    3357             : 
    3358             : ALIAS (config_enable_password,
    3359             :        enable_password_text_cmd,
    3360             :        "enable password LINE",
    3361             :        "Modify enable password parameters\n"
    3362             :        "Assign the privileged level password\n"
    3363             :        "The UNENCRYPTED (cleartext) 'enable' password\n")
    3364             : 
    3365             : /* VTY enable password delete. */
    3366           0 : DEFUN (no_config_enable_password, no_enable_password_cmd,
    3367             :        "no enable password",
    3368             :        NO_STR
    3369             :        "Modify enable password parameters\n"
    3370             :        "Assign the privileged level password\n")
    3371             : {
    3372           0 :   if (host.enable)
    3373           0 :     XFREE (MTYPE_HOST, host.enable);
    3374           0 :   host.enable = NULL;
    3375             : 
    3376           0 :   if (host.enable_encrypt)
    3377           0 :     XFREE (MTYPE_HOST, host.enable_encrypt);
    3378           0 :   host.enable_encrypt = NULL;
    3379             : 
    3380           0 :   return CMD_SUCCESS;
    3381             : }
    3382             :         
    3383           0 : DEFUN (service_password_encrypt,
    3384             :        service_password_encrypt_cmd,
    3385             :        "service password-encryption",
    3386             :        "Set up miscellaneous service\n"
    3387             :        "Enable encrypted passwords\n")
    3388             : {
    3389           0 :   if (host.encrypt)
    3390           0 :     return CMD_SUCCESS;
    3391             : 
    3392           0 :   host.encrypt = 1;
    3393             : 
    3394           0 :   if (host.password)
    3395             :     {
    3396           0 :       if (host.password_encrypt)
    3397           0 :         XFREE (MTYPE_HOST, host.password_encrypt);
    3398           0 :       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
    3399             :     }
    3400           0 :   if (host.enable)
    3401             :     {
    3402           0 :       if (host.enable_encrypt)
    3403           0 :         XFREE (MTYPE_HOST, host.enable_encrypt);
    3404           0 :       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
    3405             :     }
    3406             : 
    3407           0 :   return CMD_SUCCESS;
    3408             : }
    3409             : 
    3410           0 : DEFUN (no_service_password_encrypt,
    3411             :        no_service_password_encrypt_cmd,
    3412             :        "no service password-encryption",
    3413             :        NO_STR
    3414             :        "Set up miscellaneous service\n"
    3415             :        "Enable encrypted passwords\n")
    3416             : {
    3417           0 :   if (! host.encrypt)
    3418           0 :     return CMD_SUCCESS;
    3419             : 
    3420           0 :   host.encrypt = 0;
    3421             : 
    3422           0 :   if (host.password_encrypt)
    3423           0 :     XFREE (MTYPE_HOST, host.password_encrypt);
    3424           0 :   host.password_encrypt = NULL;
    3425             : 
    3426           0 :   if (host.enable_encrypt)
    3427           0 :     XFREE (MTYPE_HOST, host.enable_encrypt);
    3428           0 :   host.enable_encrypt = NULL;
    3429             : 
    3430           0 :   return CMD_SUCCESS;
    3431             : }
    3432             : 
    3433           0 : DEFUN (config_terminal_length, config_terminal_length_cmd,
    3434             :        "terminal length <0-512>",
    3435             :        "Set terminal line parameters\n"
    3436             :        "Set number of lines on a screen\n"
    3437             :        "Number of lines on screen (0 for no pausing)\n")
    3438             : {
    3439             :   int lines;
    3440           0 :   char *endptr = NULL;
    3441             : 
    3442           0 :   lines = strtol (argv[0], &endptr, 10);
    3443           0 :   if (lines < 0 || lines > 512 || *endptr != '\0')
    3444             :     {
    3445           0 :       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
    3446           0 :       return CMD_WARNING;
    3447             :     }
    3448           0 :   vty->lines = lines;
    3449             : 
    3450           0 :   return CMD_SUCCESS;
    3451             : }
    3452             : 
    3453           0 : DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
    3454             :        "terminal no length",
    3455             :        "Set terminal line parameters\n"
    3456             :        NO_STR
    3457             :        "Set number of lines on a screen\n")
    3458             : {
    3459           0 :   vty->lines = -1;
    3460           0 :   return CMD_SUCCESS;
    3461             : }
    3462             : 
    3463           0 : DEFUN (service_terminal_length, service_terminal_length_cmd,
    3464             :        "service terminal-length <0-512>",
    3465             :        "Set up miscellaneous service\n"
    3466             :        "System wide terminal length configuration\n"
    3467             :        "Number of lines of VTY (0 means no line control)\n")
    3468             : {
    3469             :   int lines;
    3470           0 :   char *endptr = NULL;
    3471             : 
    3472           0 :   lines = strtol (argv[0], &endptr, 10);
    3473           0 :   if (lines < 0 || lines > 512 || *endptr != '\0')
    3474             :     {
    3475           0 :       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
    3476           0 :       return CMD_WARNING;
    3477             :     }
    3478           0 :   host.lines = lines;
    3479             : 
    3480           0 :   return CMD_SUCCESS;
    3481             : }
    3482             : 
    3483           0 : DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
    3484             :        "no service terminal-length [<0-512>]",
    3485             :        NO_STR
    3486             :        "Set up miscellaneous service\n"
    3487             :        "System wide terminal length configuration\n"
    3488             :        "Number of lines of VTY (0 means no line control)\n")
    3489             : {
    3490           0 :   host.lines = -1;
    3491           0 :   return CMD_SUCCESS;
    3492             : }
    3493             : 
    3494           0 : DEFUN_HIDDEN (do_echo,
    3495             :               echo_cmd,
    3496             :               "echo .MESSAGE",
    3497             :               "Echo a message back to the vty\n"
    3498             :               "The message to echo\n")
    3499             : {
    3500             :   char *message;
    3501             : 
    3502           0 :   vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
    3503           0 :            VTY_NEWLINE);
    3504           0 :   if (message)
    3505           0 :     XFREE(MTYPE_TMP, message);
    3506           0 :   return CMD_SUCCESS;
    3507             : }
    3508             : 
    3509           0 : DEFUN (config_logmsg,
    3510             :        config_logmsg_cmd,
    3511             :        "logmsg "LOG_LEVELS" .MESSAGE",
    3512             :        "Send a message to enabled logging destinations\n"
    3513             :        LOG_LEVEL_DESC
    3514             :        "The message to send\n")
    3515             : {
    3516             :   int level;
    3517             :   char *message;
    3518             : 
    3519           0 :   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
    3520           0 :     return CMD_ERR_NO_MATCH;
    3521             : 
    3522           0 :   zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
    3523           0 :   if (message)
    3524           0 :     XFREE(MTYPE_TMP, message);
    3525           0 :   return CMD_SUCCESS;
    3526             : }
    3527             : 
    3528           0 : DEFUN (show_logging,
    3529             :        show_logging_cmd,
    3530             :        "show logging",
    3531             :        SHOW_STR
    3532             :        "Show current logging configuration\n")
    3533             : {
    3534           0 :   struct zlog *zl = zlog_default;
    3535             : 
    3536           0 :   vty_out (vty, "Syslog logging: ");
    3537           0 :   if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
    3538           0 :     vty_out (vty, "disabled");
    3539             :   else
    3540           0 :     vty_out (vty, "level %s, facility %s, ident %s",
    3541           0 :              zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
    3542             :              facility_name(zl->facility), zl->ident);
    3543           0 :   vty_out (vty, "%s", VTY_NEWLINE);
    3544             : 
    3545           0 :   vty_out (vty, "Stdout logging: ");
    3546           0 :   if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
    3547           0 :     vty_out (vty, "disabled");
    3548             :   else
    3549           0 :     vty_out (vty, "level %s",
    3550           0 :              zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
    3551           0 :   vty_out (vty, "%s", VTY_NEWLINE);
    3552             : 
    3553           0 :   vty_out (vty, "Monitor logging: ");
    3554           0 :   if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
    3555           0 :     vty_out (vty, "disabled");
    3556             :   else
    3557           0 :     vty_out (vty, "level %s",
    3558           0 :              zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
    3559           0 :   vty_out (vty, "%s", VTY_NEWLINE);
    3560             : 
    3561           0 :   vty_out (vty, "File logging: ");
    3562           0 :   if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
    3563           0 :       !zl->fp)
    3564           0 :     vty_out (vty, "disabled");
    3565             :   else
    3566           0 :     vty_out (vty, "level %s, filename %s",
    3567           0 :              zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
    3568             :              zl->filename);
    3569           0 :   vty_out (vty, "%s", VTY_NEWLINE);
    3570             : 
    3571           0 :   vty_out (vty, "Protocol name: %s%s",
    3572           0 :            zlog_proto_names[zl->protocol], VTY_NEWLINE);
    3573           0 :   vty_out (vty, "Record priority: %s%s",
    3574           0 :            (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
    3575           0 :   vty_out (vty, "Timestamp precision: %d%s",
    3576           0 :            zl->timestamp_precision, VTY_NEWLINE);
    3577             : 
    3578           0 :   return CMD_SUCCESS;
    3579             : }
    3580             : 
    3581           0 : DEFUN (config_log_stdout,
    3582             :        config_log_stdout_cmd,
    3583             :        "log stdout",
    3584             :        "Logging control\n"
    3585             :        "Set stdout logging level\n")
    3586             : {
    3587           0 :   zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
    3588           0 :   return CMD_SUCCESS;
    3589             : }
    3590             : 
    3591           0 : DEFUN (config_log_stdout_level,
    3592             :        config_log_stdout_level_cmd,
    3593             :        "log stdout "LOG_LEVELS,
    3594             :        "Logging control\n"
    3595             :        "Set stdout logging level\n"
    3596             :        LOG_LEVEL_DESC)
    3597             : {
    3598             :   int level;
    3599             : 
    3600           0 :   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
    3601           0 :     return CMD_ERR_NO_MATCH;
    3602           0 :   zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
    3603           0 :   return CMD_SUCCESS;
    3604             : }
    3605             : 
    3606           0 : DEFUN (no_config_log_stdout,
    3607             :        no_config_log_stdout_cmd,
    3608             :        "no log stdout [LEVEL]",
    3609             :        NO_STR
    3610             :        "Logging control\n"
    3611             :        "Cancel logging to stdout\n"
    3612             :        "Logging level\n")
    3613             : {
    3614           0 :   zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
    3615           0 :   return CMD_SUCCESS;
    3616             : }
    3617             : 
    3618           0 : DEFUN (config_log_monitor,
    3619             :        config_log_monitor_cmd,
    3620             :        "log monitor",
    3621             :        "Logging control\n"
    3622             :        "Set terminal line (monitor) logging level\n")
    3623             : {
    3624           0 :   zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
    3625           0 :   return CMD_SUCCESS;
    3626             : }
    3627             : 
    3628           0 : DEFUN (config_log_monitor_level,
    3629             :        config_log_monitor_level_cmd,
    3630             :        "log monitor "LOG_LEVELS,
    3631             :        "Logging control\n"
    3632             :        "Set terminal line (monitor) logging level\n"
    3633             :        LOG_LEVEL_DESC)
    3634             : {
    3635             :   int level;
    3636             : 
    3637           0 :   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
    3638           0 :     return CMD_ERR_NO_MATCH;
    3639           0 :   zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
    3640           0 :   return CMD_SUCCESS;
    3641             : }
    3642             : 
    3643           0 : DEFUN (no_config_log_monitor,
    3644             :        no_config_log_monitor_cmd,
    3645             :        "no log monitor [LEVEL]",
    3646             :        NO_STR
    3647             :        "Logging control\n"
    3648             :        "Disable terminal line (monitor) logging\n"
    3649             :        "Logging level\n")
    3650             : {
    3651           0 :   zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
    3652           0 :   return CMD_SUCCESS;
    3653             : }
    3654             : 
    3655             : static int
    3656          45 : set_log_file(struct vty *vty, const char *fname, int loglevel)
    3657             : {
    3658             :   int ret;
    3659          45 :   char *p = NULL;
    3660             :   const char *fullpath;
    3661             :   
    3662             :   /* Path detection. */
    3663          45 :   if (! IS_DIRECTORY_SEP (*fname))
    3664             :     {
    3665             :       char cwd[MAXPATHLEN+1];
    3666           0 :       cwd[MAXPATHLEN] = '\0';
    3667             :       
    3668           0 :       if (getcwd (cwd, MAXPATHLEN) == NULL)
    3669             :         {
    3670           0 :           zlog_err ("config_log_file: Unable to alloc mem!");
    3671           0 :           return CMD_WARNING;
    3672             :         }
    3673             :       
    3674           0 :       if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
    3675             :           == NULL)
    3676             :         {
    3677           0 :           zlog_err ("config_log_file: Unable to alloc mem!");
    3678           0 :           return CMD_WARNING;
    3679             :         }
    3680           0 :       sprintf (p, "%s/%s", cwd, fname);
    3681           0 :       fullpath = p;
    3682             :     }
    3683             :   else
    3684          45 :     fullpath = fname;
    3685             : 
    3686          45 :   ret = zlog_set_file (NULL, fullpath, loglevel);
    3687             : 
    3688          45 :   if (p)
    3689           0 :     XFREE (MTYPE_TMP, p);
    3690             : 
    3691          45 :   if (!ret)
    3692             :     {
    3693           0 :       vty_out (vty, "can't open logfile %s\n", fname);
    3694           0 :       return CMD_WARNING;
    3695             :     }
    3696             : 
    3697          45 :   if (host.logfile)
    3698           0 :     XFREE (MTYPE_HOST, host.logfile);
    3699             : 
    3700          45 :   host.logfile = XSTRDUP (MTYPE_HOST, fname);
    3701             : 
    3702          45 :   return CMD_SUCCESS;
    3703             : }
    3704             : 
    3705          45 : DEFUN (config_log_file,
    3706             :        config_log_file_cmd,
    3707             :        "log file FILENAME",
    3708             :        "Logging control\n"
    3709             :        "Logging to file\n"
    3710             :        "Logging filename\n")
    3711             : {
    3712          45 :   return set_log_file(vty, argv[0], zlog_default->default_lvl);
    3713             : }
    3714             : 
    3715           0 : DEFUN (config_log_file_level,
    3716             :        config_log_file_level_cmd,
    3717             :        "log file FILENAME "LOG_LEVELS,
    3718             :        "Logging control\n"
    3719             :        "Logging to file\n"
    3720             :        "Logging filename\n"
    3721             :        LOG_LEVEL_DESC)
    3722             : {
    3723             :   int level;
    3724             : 
    3725           0 :   if ((level = level_match(argv[1])) == ZLOG_DISABLED)
    3726           0 :     return CMD_ERR_NO_MATCH;
    3727           0 :   return set_log_file(vty, argv[0], level);
    3728             : }
    3729             : 
    3730           0 : DEFUN (no_config_log_file,
    3731             :        no_config_log_file_cmd,
    3732             :        "no log file [FILENAME]",
    3733             :        NO_STR
    3734             :        "Logging control\n"
    3735             :        "Cancel logging to file\n"
    3736             :        "Logging file name\n")
    3737             : {
    3738           0 :   zlog_reset_file (NULL);
    3739             : 
    3740           0 :   if (host.logfile)
    3741           0 :     XFREE (MTYPE_HOST, host.logfile);
    3742             : 
    3743           0 :   host.logfile = NULL;
    3744             : 
    3745           0 :   return CMD_SUCCESS;
    3746             : }
    3747             : 
    3748             : ALIAS (no_config_log_file,
    3749             :        no_config_log_file_level_cmd,
    3750             :        "no log file FILENAME LEVEL",
    3751             :        NO_STR
    3752             :        "Logging control\n"
    3753             :        "Cancel logging to file\n"
    3754             :        "Logging file name\n"
    3755             :        "Logging level\n")
    3756             : 
    3757           0 : DEFUN (config_log_syslog,
    3758             :        config_log_syslog_cmd,
    3759             :        "log syslog",
    3760             :        "Logging control\n"
    3761             :        "Set syslog logging level\n")
    3762             : {
    3763           0 :   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
    3764           0 :   return CMD_SUCCESS;
    3765             : }
    3766             : 
    3767           0 : DEFUN (config_log_syslog_level,
    3768             :        config_log_syslog_level_cmd,
    3769             :        "log syslog "LOG_LEVELS,
    3770             :        "Logging control\n"
    3771             :        "Set syslog logging level\n"
    3772             :        LOG_LEVEL_DESC)
    3773             : {
    3774             :   int level;
    3775             : 
    3776           0 :   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
    3777           0 :     return CMD_ERR_NO_MATCH;
    3778           0 :   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
    3779           0 :   return CMD_SUCCESS;
    3780             : }
    3781             : 
    3782           0 : DEFUN_DEPRECATED (config_log_syslog_facility,
    3783             :                   config_log_syslog_facility_cmd,
    3784             :                   "log syslog facility "LOG_FACILITIES,
    3785             :                   "Logging control\n"
    3786             :                   "Logging goes to syslog\n"
    3787             :                   "(Deprecated) Facility parameter for syslog messages\n"
    3788             :                   LOG_FACILITY_DESC)
    3789             : {
    3790             :   int facility;
    3791             : 
    3792           0 :   if ((facility = facility_match(argv[0])) < 0)
    3793           0 :     return CMD_ERR_NO_MATCH;
    3794             : 
    3795           0 :   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
    3796           0 :   zlog_default->facility = facility;
    3797           0 :   return CMD_SUCCESS;
    3798             : }
    3799             : 
    3800           0 : DEFUN (no_config_log_syslog,
    3801             :        no_config_log_syslog_cmd,
    3802             :        "no log syslog [LEVEL]",
    3803             :        NO_STR
    3804             :        "Logging control\n"
    3805             :        "Cancel logging to syslog\n"
    3806             :        "Logging level\n")
    3807             : {
    3808           0 :   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
    3809           0 :   return CMD_SUCCESS;
    3810             : }
    3811             : 
    3812             : ALIAS (no_config_log_syslog,
    3813             :        no_config_log_syslog_facility_cmd,
    3814             :        "no log syslog facility "LOG_FACILITIES,
    3815             :        NO_STR
    3816             :        "Logging control\n"
    3817             :        "Logging goes to syslog\n"
    3818             :        "Facility parameter for syslog messages\n"
    3819             :        LOG_FACILITY_DESC)
    3820             : 
    3821           0 : DEFUN (config_log_facility,
    3822             :        config_log_facility_cmd,
    3823             :        "log facility "LOG_FACILITIES,
    3824             :        "Logging control\n"
    3825             :        "Facility parameter for syslog messages\n"
    3826             :        LOG_FACILITY_DESC)
    3827             : {
    3828             :   int facility;
    3829             : 
    3830           0 :   if ((facility = facility_match(argv[0])) < 0)
    3831           0 :     return CMD_ERR_NO_MATCH;
    3832           0 :   zlog_default->facility = facility;
    3833           0 :   return CMD_SUCCESS;
    3834             : }
    3835             : 
    3836           0 : DEFUN (no_config_log_facility,
    3837             :        no_config_log_facility_cmd,
    3838             :        "no log facility [FACILITY]",
    3839             :        NO_STR
    3840             :        "Logging control\n"
    3841             :        "Reset syslog facility to default (daemon)\n"
    3842             :        "Syslog facility\n")
    3843             : {
    3844           0 :   zlog_default->facility = LOG_DAEMON;
    3845           0 :   return CMD_SUCCESS;
    3846             : }
    3847             : 
    3848           0 : DEFUN_DEPRECATED (config_log_trap,
    3849             :                   config_log_trap_cmd,
    3850             :                   "log trap "LOG_LEVELS,
    3851             :                   "Logging control\n"
    3852             :                   "(Deprecated) Set logging level and default for all destinations\n"
    3853             :                   LOG_LEVEL_DESC)
    3854             : {
    3855             :   int new_level ;
    3856             :   int i;
    3857             :   
    3858           0 :   if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
    3859           0 :     return CMD_ERR_NO_MATCH;
    3860             : 
    3861           0 :   zlog_default->default_lvl = new_level;
    3862           0 :   for (i = 0; i < ZLOG_NUM_DESTS; i++)
    3863           0 :     if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
    3864           0 :       zlog_default->maxlvl[i] = new_level;
    3865           0 :   return CMD_SUCCESS;
    3866             : }
    3867             : 
    3868           0 : DEFUN_DEPRECATED (no_config_log_trap,
    3869             :                   no_config_log_trap_cmd,
    3870             :                   "no log trap [LEVEL]",
    3871             :                   NO_STR
    3872             :                   "Logging control\n"
    3873             :                   "Permit all logging information\n"
    3874             :                   "Logging level\n")
    3875             : {
    3876           0 :   zlog_default->default_lvl = LOG_DEBUG;
    3877           0 :   return CMD_SUCCESS;
    3878             : }
    3879             : 
    3880           0 : DEFUN (config_log_record_priority,
    3881             :        config_log_record_priority_cmd,
    3882             :        "log record-priority",
    3883             :        "Logging control\n"
    3884             :        "Log the priority of the message within the message\n")
    3885             : {
    3886           0 :   zlog_default->record_priority = 1 ;
    3887           0 :   return CMD_SUCCESS;
    3888             : }
    3889             : 
    3890           0 : DEFUN (no_config_log_record_priority,
    3891             :        no_config_log_record_priority_cmd,
    3892             :        "no log record-priority",
    3893             :        NO_STR
    3894             :        "Logging control\n"
    3895             :        "Do not log the priority of the message within the message\n")
    3896             : {
    3897           0 :   zlog_default->record_priority = 0 ;
    3898           0 :   return CMD_SUCCESS;
    3899             : }
    3900             : 
    3901           0 : DEFUN (config_log_timestamp_precision,
    3902             :        config_log_timestamp_precision_cmd,
    3903             :        "log timestamp precision <0-6>",
    3904             :        "Logging control\n"
    3905             :        "Timestamp configuration\n"
    3906             :        "Set the timestamp precision\n"
    3907             :        "Number of subsecond digits\n")
    3908             : {
    3909           0 :   if (argc != 1)
    3910             :     {
    3911           0 :       vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
    3912           0 :       return CMD_WARNING;
    3913             :     }
    3914             : 
    3915           0 :   VTY_GET_INTEGER_RANGE("Timestamp Precision",
    3916             :                         zlog_default->timestamp_precision, argv[0], 0, 6);
    3917           0 :   return CMD_SUCCESS;
    3918             : }
    3919             : 
    3920           0 : DEFUN (no_config_log_timestamp_precision,
    3921             :        no_config_log_timestamp_precision_cmd,
    3922             :        "no log timestamp precision",
    3923             :        NO_STR
    3924             :        "Logging control\n"
    3925             :        "Timestamp configuration\n"
    3926             :        "Reset the timestamp precision to the default value of 0\n")
    3927             : {
    3928           0 :   zlog_default->timestamp_precision = 0 ;
    3929           0 :   return CMD_SUCCESS;
    3930             : }
    3931             : 
    3932           0 : DEFUN (banner_motd_file,
    3933             :        banner_motd_file_cmd,
    3934             :        "banner motd file [FILE]",
    3935             :        "Set banner\n"
    3936             :        "Banner for motd\n"
    3937             :        "Banner from a file\n"
    3938             :        "Filename\n")
    3939             : {
    3940           0 :   if (host.motdfile)
    3941           0 :     XFREE (MTYPE_HOST, host.motdfile);
    3942           0 :   host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
    3943             : 
    3944           0 :   return CMD_SUCCESS;
    3945             : }
    3946             : 
    3947           0 : DEFUN (banner_motd_default,
    3948             :        banner_motd_default_cmd,
    3949             :        "banner motd default",
    3950             :        "Set banner string\n"
    3951             :        "Strings for motd\n"
    3952             :        "Default string\n")
    3953             : {
    3954           0 :   host.motd = default_motd;
    3955           0 :   return CMD_SUCCESS;
    3956             : }
    3957             : 
    3958           0 : DEFUN (no_banner_motd,
    3959             :        no_banner_motd_cmd,
    3960             :        "no banner motd",
    3961             :        NO_STR
    3962             :        "Set banner string\n"
    3963             :        "Strings for motd\n")
    3964             : {
    3965           0 :   host.motd = NULL;
    3966           0 :   if (host.motdfile) 
    3967           0 :     XFREE (MTYPE_HOST, host.motdfile);
    3968           0 :   host.motdfile = NULL;
    3969           0 :   return CMD_SUCCESS;
    3970             : }
    3971             : 
    3972             : /* Set config filename.  Called from vty.c */
    3973             : void
    3974          45 : host_config_set (char *filename)
    3975             : {
    3976          45 :   if (host.config)
    3977           0 :     XFREE (MTYPE_HOST, host.config);
    3978          45 :   host.config = XSTRDUP (MTYPE_HOST, filename);
    3979          45 : }
    3980             : 
    3981             : void
    3982         225 : install_default (enum node_type node)
    3983             : {
    3984         225 :   install_element (node, &config_exit_cmd);
    3985         225 :   install_element (node, &config_quit_cmd);
    3986         225 :   install_element (node, &config_end_cmd);
    3987         225 :   install_element (node, &config_help_cmd);
    3988         225 :   install_element (node, &config_list_cmd);
    3989             : 
    3990         225 :   install_element (node, &config_write_terminal_cmd);
    3991         225 :   install_element (node, &config_write_file_cmd);
    3992         225 :   install_element (node, &config_write_memory_cmd);
    3993         225 :   install_element (node, &config_write_cmd);
    3994         225 :   install_element (node, &show_running_config_cmd);
    3995         225 : }
    3996             : 
    3997             : /* Initialize command interface. Install basic nodes and commands. */
    3998             : void
    3999          45 : cmd_init (int terminal)
    4000             : {
    4001          45 :   command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
    4002          45 :   token_cr.type = TOKEN_TERMINAL;
    4003          45 :   token_cr.cmd = command_cr;
    4004          45 :   token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
    4005             : 
    4006             :   /* Allocate initial top vector of commands. */
    4007          45 :   cmdvec = vector_init (VECTOR_MIN_SIZE);
    4008             : 
    4009             :   /* Default host value settings. */
    4010          45 :   host.name = NULL;
    4011          45 :   host.password = NULL;
    4012          45 :   host.enable = NULL;
    4013          45 :   host.logfile = NULL;
    4014          45 :   host.config = NULL;
    4015          45 :   host.lines = -1;
    4016          45 :   host.motd = default_motd;
    4017          45 :   host.motdfile = NULL;
    4018             : 
    4019             :   /* Install top nodes. */
    4020          45 :   install_node (&view_node, NULL);
    4021          45 :   install_node (&enable_node, NULL);
    4022          45 :   install_node (&auth_node, NULL);
    4023          45 :   install_node (&auth_enable_node, NULL);
    4024          45 :   install_node (&restricted_node, NULL);
    4025          45 :   install_node (&config_node, config_write_host);
    4026             : 
    4027             :   /* Each node's basic commands. */
    4028          45 :   install_element (VIEW_NODE, &show_version_cmd);
    4029          45 :   if (terminal)
    4030             :     {
    4031          45 :       install_element (VIEW_NODE, &config_list_cmd);
    4032          45 :       install_element (VIEW_NODE, &config_exit_cmd);
    4033          45 :       install_element (VIEW_NODE, &config_quit_cmd);
    4034          45 :       install_element (VIEW_NODE, &config_help_cmd);
    4035          45 :       install_element (VIEW_NODE, &config_enable_cmd);
    4036          45 :       install_element (VIEW_NODE, &config_terminal_length_cmd);
    4037          45 :       install_element (VIEW_NODE, &config_terminal_no_length_cmd);
    4038          45 :       install_element (VIEW_NODE, &show_logging_cmd);
    4039          45 :       install_element (VIEW_NODE, &echo_cmd);
    4040             : 
    4041          45 :       install_element (RESTRICTED_NODE, &config_list_cmd);
    4042          45 :       install_element (RESTRICTED_NODE, &config_exit_cmd);
    4043          45 :       install_element (RESTRICTED_NODE, &config_quit_cmd);
    4044          45 :       install_element (RESTRICTED_NODE, &config_help_cmd);
    4045          45 :       install_element (RESTRICTED_NODE, &config_enable_cmd);
    4046          45 :       install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
    4047          45 :       install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
    4048          45 :       install_element (RESTRICTED_NODE, &echo_cmd);
    4049             :     }
    4050             : 
    4051          45 :   if (terminal)
    4052             :     {
    4053          45 :       install_default (ENABLE_NODE);
    4054          45 :       install_element (ENABLE_NODE, &config_disable_cmd);
    4055          45 :       install_element (ENABLE_NODE, &config_terminal_cmd);
    4056          45 :       install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
    4057             :     }
    4058          45 :   install_element (ENABLE_NODE, &show_startup_config_cmd);
    4059          45 :   install_element (ENABLE_NODE, &show_version_cmd);
    4060             : 
    4061          45 :   if (terminal)
    4062             :     {
    4063          45 :       install_element (ENABLE_NODE, &config_terminal_length_cmd);
    4064          45 :       install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
    4065          45 :       install_element (ENABLE_NODE, &show_logging_cmd);
    4066          45 :       install_element (ENABLE_NODE, &echo_cmd);
    4067          45 :       install_element (ENABLE_NODE, &config_logmsg_cmd);
    4068             : 
    4069          45 :       install_default (CONFIG_NODE);
    4070             :     }
    4071             :   
    4072          45 :   install_element (CONFIG_NODE, &hostname_cmd);
    4073          45 :   install_element (CONFIG_NODE, &no_hostname_cmd);
    4074             : 
    4075          45 :   if (terminal)
    4076             :     {
    4077          45 :       install_element (CONFIG_NODE, &password_cmd);
    4078          45 :       install_element (CONFIG_NODE, &password_text_cmd);
    4079          45 :       install_element (CONFIG_NODE, &enable_password_cmd);
    4080          45 :       install_element (CONFIG_NODE, &enable_password_text_cmd);
    4081          45 :       install_element (CONFIG_NODE, &no_enable_password_cmd);
    4082             : 
    4083          45 :       install_element (CONFIG_NODE, &config_log_stdout_cmd);
    4084          45 :       install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
    4085          45 :       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
    4086          45 :       install_element (CONFIG_NODE, &config_log_monitor_cmd);
    4087          45 :       install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
    4088          45 :       install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
    4089          45 :       install_element (CONFIG_NODE, &config_log_file_cmd);
    4090          45 :       install_element (CONFIG_NODE, &config_log_file_level_cmd);
    4091          45 :       install_element (CONFIG_NODE, &no_config_log_file_cmd);
    4092          45 :       install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
    4093          45 :       install_element (CONFIG_NODE, &config_log_syslog_cmd);
    4094          45 :       install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
    4095          45 :       install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
    4096          45 :       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
    4097          45 :       install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
    4098          45 :       install_element (CONFIG_NODE, &config_log_facility_cmd);
    4099          45 :       install_element (CONFIG_NODE, &no_config_log_facility_cmd);
    4100          45 :       install_element (CONFIG_NODE, &config_log_trap_cmd);
    4101          45 :       install_element (CONFIG_NODE, &no_config_log_trap_cmd);
    4102          45 :       install_element (CONFIG_NODE, &config_log_record_priority_cmd);
    4103          45 :       install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
    4104          45 :       install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
    4105          45 :       install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
    4106          45 :       install_element (CONFIG_NODE, &service_password_encrypt_cmd);
    4107          45 :       install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
    4108          45 :       install_element (CONFIG_NODE, &banner_motd_default_cmd);
    4109          45 :       install_element (CONFIG_NODE, &banner_motd_file_cmd);
    4110          45 :       install_element (CONFIG_NODE, &no_banner_motd_cmd);
    4111          45 :       install_element (CONFIG_NODE, &service_terminal_length_cmd);
    4112          45 :       install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
    4113             : 
    4114          45 :       install_element (VIEW_NODE, &show_thread_cpu_cmd);
    4115          45 :       install_element (ENABLE_NODE, &show_thread_cpu_cmd);
    4116          45 :       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
    4117             :       
    4118          45 :       install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
    4119          45 :       install_element (VIEW_NODE, &show_work_queues_cmd);
    4120          45 :       install_element (ENABLE_NODE, &show_work_queues_cmd);
    4121             :     }
    4122          45 :   srand(time(NULL));
    4123          45 : }
    4124             : 
    4125             : static void
    4126           0 : cmd_terminate_token(struct cmd_token *token)
    4127             : {
    4128             :   unsigned int i, j;
    4129             :   vector keyword_vect;
    4130             : 
    4131           0 :   if (token->multiple)
    4132             :     {
    4133           0 :       for (i = 0; i < vector_active(token->multiple); i++)
    4134           0 :         cmd_terminate_token(vector_slot(token->multiple, i));
    4135           0 :       vector_free(token->multiple);
    4136           0 :       token->multiple = NULL;
    4137             :     }
    4138             : 
    4139           0 :   if (token->keyword)
    4140             :     {
    4141           0 :       for (i = 0; i < vector_active(token->keyword); i++)
    4142             :         {
    4143           0 :           keyword_vect = vector_slot(token->keyword, i);
    4144           0 :           for (j = 0; j < vector_active(keyword_vect); j++)
    4145           0 :             cmd_terminate_token(vector_slot(keyword_vect, j));
    4146           0 :           vector_free(keyword_vect);
    4147             :         }
    4148           0 :       vector_free(token->keyword);
    4149           0 :       token->keyword = NULL;
    4150             :     }
    4151             : 
    4152           0 :   XFREE(MTYPE_CMD_TOKENS, token->cmd);
    4153           0 :   XFREE(MTYPE_CMD_TOKENS, token->desc);
    4154             : 
    4155           0 :   XFREE(MTYPE_CMD_TOKENS, token);
    4156           0 : }
    4157             : 
    4158             : static void
    4159           0 : cmd_terminate_element(struct cmd_element *cmd)
    4160             : {
    4161             :   unsigned int i;
    4162             : 
    4163           0 :   if (cmd->tokens == NULL)
    4164           0 :     return;
    4165             : 
    4166           0 :   for (i = 0; i < vector_active(cmd->tokens); i++)
    4167           0 :     cmd_terminate_token(vector_slot(cmd->tokens, i));
    4168             : 
    4169           0 :   vector_free(cmd->tokens);
    4170           0 :   cmd->tokens = NULL;
    4171             : }
    4172             : 
    4173             : void
    4174           0 : cmd_terminate ()
    4175             : {
    4176             :   unsigned int i, j;
    4177             :   struct cmd_node *cmd_node;
    4178             :   struct cmd_element *cmd_element;
    4179             :   vector cmd_node_v;
    4180             : 
    4181           0 :   if (cmdvec)
    4182             :     {
    4183           0 :       for (i = 0; i < vector_active (cmdvec); i++) 
    4184           0 :         if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
    4185             :           {
    4186           0 :             cmd_node_v = cmd_node->cmd_vector;
    4187             : 
    4188           0 :             for (j = 0; j < vector_active (cmd_node_v); j++)
    4189           0 :               if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
    4190           0 :                 cmd_terminate_element(cmd_element);
    4191             : 
    4192           0 :             vector_free (cmd_node_v);
    4193             :           }
    4194             : 
    4195           0 :       vector_free (cmdvec);
    4196           0 :       cmdvec = NULL;
    4197             :     }
    4198             : 
    4199           0 :   if (command_cr)
    4200           0 :     XFREE(MTYPE_CMD_TOKENS, command_cr);
    4201           0 :   if (token_cr.desc)
    4202           0 :     XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
    4203           0 :   if (host.name)
    4204           0 :     XFREE (MTYPE_HOST, host.name);
    4205           0 :   if (host.password)
    4206           0 :     XFREE (MTYPE_HOST, host.password);
    4207           0 :   if (host.password_encrypt)
    4208           0 :     XFREE (MTYPE_HOST, host.password_encrypt);
    4209           0 :   if (host.enable)
    4210           0 :     XFREE (MTYPE_HOST, host.enable);
    4211           0 :   if (host.enable_encrypt)
    4212           0 :     XFREE (MTYPE_HOST, host.enable_encrypt);
    4213           0 :   if (host.logfile)
    4214           0 :     XFREE (MTYPE_HOST, host.logfile);
    4215           0 :   if (host.motdfile)
    4216           0 :     XFREE (MTYPE_HOST, host.motdfile);
    4217           0 :   if (host.config)
    4218           0 :     XFREE (MTYPE_HOST, host.config);
    4219           0 : }

Generated by: LCOV version 1.10