File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / command.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>