Annotation of embedaddon/quagga/lib/command.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:    Command interpreter routine for virtual terminal [aka TeletYpe]
                      3:    Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
1.1.1.4 ! misho       4:    Copyright (C) 2013 by Open Source Routing.
        !             5:    Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       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: 
1.1.1.4 ! misho      40: struct cmd_token token_cr;
1.1       misho      41: char *command_cr = NULL;
                     42: 
1.1.1.4 ! misho      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: 
1.1       misho      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\
1.1.1.3   misho     112: " GIT_INFO "\r\n";
1.1       misho     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);
1.1.1.4 ! misho     184:   printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
1.1       misho     185: }
                    186: 
1.1.1.4 ! misho     187: 
1.1       misho     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: 
1.1.1.4 ! misho     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: 
1.1       misho     326: static char *
1.1.1.4 ! misho     327: format_parser_desc_str(struct format_parser_state *state)
1.1       misho     328: {
                    329:   const char *cp, *start;
                    330:   char *token;
                    331:   int strlen;
1.1.1.4 ! misho     332: 
        !           333:   cp = state->dp;
1.1       misho     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;
1.1.1.4 ! misho     352:   token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
1.1       misho     353:   memcpy (token, start, strlen);
                    354:   *(token + strlen) = '\0';
                    355: 
1.1.1.4 ! misho     356:   state->dp = cp;
1.1       misho     357: 
                    358:   return token;
                    359: }
                    360: 
1.1.1.4 ! misho     361: static void
        !           362: format_parser_begin_keyword(struct format_parser_state *state)
1.1       misho     363: {
1.1.1.4 ! misho     364:   struct cmd_token *token;
        !           365:   vector keyword_vect;
1.1       misho     366: 
1.1.1.4 ! misho     367:   if (state->in_keyword
        !           368:       || state->in_multiple)
        !           369:     format_parser_error(state, "Unexpected '{'");
1.1       misho     370: 
1.1.1.4 ! misho     371:   state->cp++;
        !           372:   state->in_keyword = 1;
1.1       misho     373: 
1.1.1.4 ! misho     374:   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
        !           375:   token->type = TOKEN_KEYWORD;
        !           376:   token->keyword = vector_init(VECTOR_MIN_SIZE);
1.1       misho     377: 
1.1.1.4 ! misho     378:   keyword_vect = vector_init(VECTOR_MIN_SIZE);
        !           379:   vector_set(token->keyword, keyword_vect);
1.1       misho     380: 
1.1.1.4 ! misho     381:   vector_set(state->curvect, token);
        !           382:   state->curvect = keyword_vect;
        !           383: }
1.1       misho     384: 
1.1.1.4 ! misho     385: static void
        !           386: format_parser_begin_multiple(struct format_parser_state *state)
        !           387: {
        !           388:   struct cmd_token *token;
1.1       misho     389: 
1.1.1.4 ! misho     390:   if (state->in_keyword == 1)
        !           391:     format_parser_error(state, "Keyword starting with '('");
1.1       misho     392: 
1.1.1.4 ! misho     393:   if (state->in_multiple)
        !           394:     format_parser_error(state, "Nested group");
1.1       misho     395: 
1.1.1.4 ! misho     396:   state->cp++;
        !           397:   state->in_multiple = 1;
        !           398:   state->just_read_word = 0;
1.1       misho     399: 
1.1.1.4 ! misho     400:   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
        !           401:   token->type = TOKEN_MULTIPLE;
        !           402:   token->multiple = vector_init(VECTOR_MIN_SIZE);
1.1       misho     403: 
1.1.1.4 ! misho     404:   vector_set(state->curvect, token);
        !           405:   if (state->curvect != state->topvect)
        !           406:     state->intvect = state->curvect;
        !           407:   state->curvect = token->multiple;
        !           408: }
1.1       misho     409: 
1.1.1.4 ! misho     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: }
1.1       misho     424: 
1.1.1.4 ! misho     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);
1.1       misho     448:     }
1.1.1.4 ! misho     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;
1.1       misho     457: }
                    458: 
1.1.1.4 ! misho     459: static void
        !           460: format_parser_handle_pipe(struct format_parser_state *state)
1.1       misho     461: {
1.1.1.4 ! misho     462:   struct cmd_token *keyword_token;
        !           463:   vector keyword_vect;
1.1       misho     464: 
1.1.1.4 ! misho     465:   if (state->in_multiple)
1.1       misho     466:     {
1.1.1.4 ! misho     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:         }
1.1       misho     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);
1.1.1.4 ! misho     623:   if (cmd->tokens == NULL)
        !           624:     cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
1.1       misho     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: 
1.1.1.3   misho     988:   return no_match;
1.1       misho     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) == '.')
1.1.1.3   misho    1074:                {
                   1075:                  if (colons || double_colon)
                   1076:                    state = STATE_DOT;
                   1077:                  else
                   1078:                    return no_match;
                   1079:                }
1.1       misho    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
1.1.1.4 ! misho    1177: cmd_word_match(struct cmd_token *token,
        !          1178:                enum filter_type filter,
        !          1179:                const char *word)
1.1       misho    1180: {
                   1181:   const char *str;
                   1182:   enum match_type match_type;
                   1183: 
1.1.1.4 ! misho    1184:   str = token->cmd;
1.1       misho    1185: 
1.1.1.4 ! misho    1186:   if (filter == FILTER_RELAXED)
        !          1187:     if (!word || !strlen(word))
        !          1188:       return partly_match;
1.1       misho    1189: 
1.1.1.4 ! misho    1190:   if (!word)
        !          1191:     return no_match;
1.1       misho    1192: 
1.1.1.4 ! misho    1193:   switch (token->terminal)
        !          1194:     {
        !          1195:       case TERMINAL_VARARG:
        !          1196:         return vararg_match;
1.1       misho    1197: 
1.1.1.4 ! misho    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;
1.1       misho    1234: 
1.1.1.4 ! misho    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;
1.1       misho    1245: 
1.1.1.4 ! misho    1246:       default:
        !          1247:         assert (0);
        !          1248:     }
1.1       misho    1249: 
1.1.1.4 ! misho    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++;
1.1       misho    1362:       }
1.1.1.4 ! misho    1363: 
        !          1364:   return MATCHER_OK;
1.1       misho    1365: }
                   1366: 
1.1.1.4 ! misho    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)
1.1       misho    1737: {
                   1738:   unsigned int i;
                   1739:   struct cmd_element *cmd_element;
1.1.1.4 ! misho    1740:   enum match_type best_match;
        !          1741:   enum match_type element_match;
        !          1742:   enum matcher_rv matcher_rv;
1.1       misho    1743: 
1.1.1.4 ! misho    1744:   best_match = no_match;
        !          1745:   *matches = vector_init(VECTOR_MIN_SIZE);
1.1       misho    1746: 
1.1.1.4 ! misho    1747:   for (i = 0; i < vector_active (commands); i++)
        !          1748:     if ((cmd_element = vector_slot (commands, i)) != NULL)
1.1       misho    1749:       {
1.1.1.4 ! misho    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: }
1.1       misho    1772: 
1.1.1.4 ! misho    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;
1.1       misho    1787: 
1.1.1.4 ! misho    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;
1.1       misho    1821: 
1.1.1.4 ! misho    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:     }
1.1       misho    1834: }
                   1835: 
                   1836: /* Check ambiguous match */
                   1837: static int
1.1.1.4 ! misho    1838: is_cmd_ambiguous (vector cmd_vector,
        !          1839:                   const char *command,
        !          1840:                   vector matches,
        !          1841:                   enum match_type type)
1.1       misho    1842: {
                   1843:   unsigned int i;
                   1844:   unsigned int j;
                   1845:   const char *str = NULL;
                   1846:   const char *matched = NULL;
1.1.1.4 ! misho    1847:   vector match_vector;
        !          1848:   struct cmd_token *cmd_token;
1.1       misho    1849: 
1.1.1.4 ! misho    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)
1.1       misho    1855:       {
                   1856:        int match = 0;
                   1857: 
1.1.1.4 ! misho    1858:        for (j = 0; j < vector_active (match_vector); j++)
        !          1859:          if ((cmd_token = vector_slot (match_vector, j)) != NULL)
1.1       misho    1860:            {
                   1861:              enum match_type ret;
1.1.1.4 ! misho    1862: 
        !          1863:              assert(cmd_token->type == TOKEN_TERMINAL);
        !          1864:              if (cmd_token->type != TOKEN_TERMINAL)
        !          1865:                continue;
        !          1866: 
        !          1867:              str = cmd_token->cmd;
1.1       misho    1868: 
                   1869:              switch (type)
                   1870:                {
                   1871:                case exact_match:
1.1.1.4 ! misho    1872:                  if (!TERMINAL_RECORD (cmd_token->terminal)
1.1       misho    1873:                      && strcmp (command, str) == 0)
                   1874:                    match++;
                   1875:                  break;
                   1876:                case partly_match:
1.1.1.4 ! misho    1877:                  if (!TERMINAL_RECORD (cmd_token->terminal)
1.1       misho    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:
1.1.1.4 ! misho    1899:                  if (cmd_token->terminal == TERMINAL_IPV6)
1.1       misho    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:
1.1.1.4 ! misho    1913:                  if (cmd_token->terminal == TERMINAL_IPV4)
1.1       misho    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:
1.1.1.4 ! misho    1926:                  if (TERMINAL_RECORD (cmd_token->terminal))
1.1       misho    1927:                    match++;
                   1928:                  break;
                   1929:                case no_match:
                   1930:                default:
                   1931:                  break;
                   1932:                }
                   1933:            }
                   1934:        if (!match)
1.1.1.4 ! misho    1935:          vector_slot (cmd_vector, i) = NULL;
1.1       misho    1936:       }
                   1937:   return 0;
                   1938: }
                   1939: 
                   1940: /* If src matches dst return dst string, otherwise return NULL */
                   1941: static const char *
1.1.1.4 ! misho    1942: cmd_entry_function (const char *src, struct cmd_token *token)
1.1       misho    1943: {
1.1.1.4 ! misho    1944:   const char *dst = token->cmd;
        !          1945: 
1.1       misho    1946:   /* Skip variable arguments. */
1.1.1.4 ! misho    1947:   if (TERMINAL_RECORD (token->terminal))
1.1       misho    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 *
1.1.1.4 ! misho    1965: cmd_entry_function_desc (const char *src, struct cmd_token *token)
1.1       misho    1966: {
1.1.1.4 ! misho    1967:   const char *dst = token->cmd;
1.1       misho    1968: 
1.1.1.4 ! misho    1969:   switch (token->terminal)
1.1       misho    1970:     {
1.1.1.4 ! misho    1971:       case TERMINAL_VARARG:
        !          1972:         return dst;
1.1       misho    1973: 
1.1.1.4 ! misho    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:  */
1.1       misho    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: 
1.1.1.4 ! misho    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:  */
1.1       misho    2052: static int
                   2053: desc_unique_string (vector v, const char *str)
                   2054: {
                   2055:   unsigned int i;
1.1.1.4 ! misho    2056:   struct cmd_token *token;
1.1       misho    2057: 
                   2058:   for (i = 0; i < vector_active (v); i++)
1.1.1.4 ! misho    2059:     if ((token = vector_slot (v, i)) != NULL)
        !          2060:       if (strcmp (token->cmd, str) == 0)
        !          2061:        return 0;
        !          2062:   return 1;
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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;
1.1.1.4 ! misho    2120:   vector matches = NULL;
        !          2121:   vector match_vector;
        !          2122:   uint32_t command_found = 0;
        !          2123:   const char *last_word;
1.1       misho    2124: 
                   2125:   /* Set index. */
                   2126:   if (vector_active (vline) == 0)
                   2127:     {
                   2128:       *status = CMD_ERR_NO_MATCH;
                   2129:       return NULL;
                   2130:     }
1.1.1.4 ! misho    2131: 
        !          2132:   index = vector_active (vline) - 1;
        !          2133: 
1.1       misho    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: 
1.1.1.4 ! misho    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);
1.1       misho    2144: 
1.1.1.4 ! misho    2145:       if (matches)
        !          2146:        cmd_matches_free(&matches);
1.1       misho    2147: 
1.1.1.4 ! misho    2148:       ret = cmd_vector_filter(cmd_vector,
        !          2149:                              FILTER_RELAXED,
        !          2150:                              vline, i,
        !          2151:                              &match,
        !          2152:                              &matches);
1.1       misho    2153: 
1.1.1.4 ! misho    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;
1.1       misho    2166: 
1.1.1.4 ! misho    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:     }
1.1       misho    2207: 
                   2208:   /* Make description vector. */
1.1.1.4 ! misho    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;
1.1       misho    2215: 
1.1.1.4 ! misho    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);
1.1       misho    2222: 
1.1.1.4 ! misho    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);
1.1       misho    2257: 
                   2258:   vector_free (cmd_vector);
1.1.1.4 ! misho    2259:   cmd_matches_free(&matches);
1.1       misho    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;
1.1.1.4 ! misho    2269:   cmd_describe_sort(matchvec);
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    2365: /* Command line completion support. */
                   2366: static char **
1.1.1.4 ! misho    2367: cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
1.1       misho    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;
1.1.1.4 ! misho    2375:   struct cmd_token *token;
1.1       misho    2376:   char *command;
                   2377:   int lcd;
1.1.1.4 ! misho    2378:   vector matches = NULL;
        !          2379:   vector match_vector;
1.1       misho    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: 
1.1.1.4 ! misho    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);
1.1       misho    2406: 
1.1.1.4 ! misho    2407:       if (ret != CMD_SUCCESS)
        !          2408:        {
        !          2409:          vector_free(cmd_vector);
        !          2410:          cmd_matches_free(&matches);
        !          2411:          *status = ret;
        !          2412:          return NULL;
        !          2413:        }
1.1       misho    2414: 
1.1.1.4 ! misho    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:       /*
1.1       misho    2430:           else if (ret == 2)
                   2431:           {
                   2432:           vector_free (cmd_vector);
1.1.1.4 ! misho    2433:           cmd_matches_free(&matches);
1.1       misho    2434:           *status = CMD_ERR_NO_MATCH;
                   2435:           return NULL;
                   2436:           }
                   2437:         */
1.1.1.4 ! misho    2438:     }
1.1       misho    2439:   
                   2440:   /* Prepare match vector. */
                   2441:   matchvec = vector_init (INIT_MATCHVEC_SIZE);
                   2442: 
1.1.1.4 ! misho    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)))
1.1       misho    2446:       {
                   2447:        const char *string;
1.1.1.4 ! misho    2448:        unsigned int j;
1.1       misho    2449: 
1.1.1.4 ! misho    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:             }
1.1       misho    2459:       }
                   2460: 
                   2461:   /* We don't need cmd_vector any more. */
                   2462:   vector_free (cmd_vector);
1.1.1.4 ! misho    2463:   cmd_matches_free(&matches);
1.1       misho    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: 
1.1.1.4 ! misho    2503:              lcdstr = (islib != 0 ?
        !          2504:                         XMALLOC (MTYPE_TMP, lcd + 1) :
        !          2505:                         malloc(lcd + 1));
1.1       misho    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++)
1.1.1.4 ! misho    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:                 }
1.1       misho    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;
1.1.1.4 ! misho    2537:   cmd_complete_sort(matchvec);
1.1       misho    2538:   vector_only_wrapper_free (matchvec);
                   2539:   *status = CMD_COMPLETE_LIST_MATCH;
                   2540:   return match_str;
                   2541: }
                   2542: 
                   2543: char **
1.1.1.4 ! misho    2544: cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
1.1       misho    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: 
1.1.1.4 ! misho    2565:       ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
1.1       misho    2566: 
                   2567:       vector_free(shifted_vline);
                   2568:       vty->node = onode;
                   2569:       return ret;
                   2570:   }
                   2571: 
1.1.1.4 ! misho    2572:   return cmd_complete_command_real (vline, vty, status, islib);
        !          2573: }
1.1       misho    2574: 
1.1.1.4 ! misho    2575: char **
        !          2576: cmd_complete_command (vector vline, struct vty *vty, int *status)
        !          2577: {
        !          2578:   return cmd_complete_command_lib (vline, vty, status, 0);
1.1       misho    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:
1.1.1.4 ! misho    2593:     case BGP_VPNV6_NODE:
        !          2594:     case BGP_ENCAP_NODE:
        !          2595:     case BGP_ENCAPV6_NODE:
1.1       misho    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
1.1.1.4 ! misho    2614: cmd_execute_command_real (vector vline,
        !          2615:                          enum filter_type filter,
        !          2616:                          struct vty *vty,
1.1       misho    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;
1.1.1.4 ! misho    2629:   int ret;
        !          2630:   vector matches;
1.1       misho    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++)
1.1.1.4 ! misho    2636:     {
        !          2637:       command = vector_slot (vline, index);
        !          2638:       ret = cmd_vector_filter(cmd_vector,
        !          2639:                              filter,
        !          2640:                              vline, index,
        !          2641:                              &match,
        !          2642:                              &matches);
1.1       misho    2643: 
1.1.1.4 ! misho    2644:       if (ret != CMD_SUCCESS)
        !          2645:        {
        !          2646:          cmd_matches_free(&matches);
        !          2647:          return ret;
        !          2648:        }
1.1       misho    2649: 
1.1.1.4 ! misho    2650:       if (match == vararg_match)
        !          2651:        {
        !          2652:          cmd_matches_free(&matches);
1.1       misho    2653:          break;
1.1.1.4 ! misho    2654:        }
1.1       misho    2655: 
1.1.1.4 ! misho    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:     }
1.1       misho    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:       {
1.1.1.4 ! misho    2679:        if (cmd_is_complete(cmd_element, vline))
1.1       misho    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: 
1.1.1.4 ! misho    2705:   ret = cmd_parse(matched_element, vline, &argc, argv);
        !          2706:   if (ret != CMD_SUCCESS)
        !          2707:     return ret;
1.1       misho    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: 
1.1.1.4 ! misho    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:  */
1.1       misho    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: 
1.1.1.4 ! misho    2758:       ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
1.1       misho    2759: 
                   2760:       vector_free(shifted_vline);
                   2761:       vty->node = onode;
                   2762:       return ret;
                   2763:   }
                   2764: 
                   2765: 
1.1.1.4 ! misho    2766:   saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
1.1       misho    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;
1.1.1.4 ! misho    2777:       ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
1.1       misho    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: 
1.1.1.4 ! misho    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:  */
1.1       misho    2805: int
                   2806: cmd_execute_command_strict (vector vline, struct vty *vty,
                   2807:                            struct cmd_element **cmd)
                   2808: {
1.1.1.4 ! misho    2809:   return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
        !          2810: }
1.1       misho    2811: 
1.1.1.4 ! misho    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;
1.1       misho    2830: 
1.1.1.4 ! misho    2831:   vline = cmd_make_strvec (vty->buf);
1.1       misho    2832: 
1.1.1.4 ! misho    2833:   /* In case of comment line */
        !          2834:   if (vline == NULL)
        !          2835:     return CMD_SUCCESS;
1.1       misho    2836: 
1.1.1.4 ! misho    2837:   /* Execute configuration command : this is strict match */
        !          2838:   ret = cmd_execute_command_strict (vline, vty, cmd);
1.1       misho    2839: 
1.1.1.4 ! misho    2840:   saved_node = vty->node;
1.1       misho    2841: 
1.1.1.4 ! misho    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:   }
1.1       misho    2848: 
1.1.1.4 ! misho    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)
1.1       misho    2854:     {
1.1.1.4 ! misho    2855:       vty->node = saved_node;
1.1       misho    2856:     }
                   2857: 
1.1.1.4 ! misho    2858:   cmd_free_strvec (vline);
1.1       misho    2859: 
1.1.1.4 ! misho    2860:   return ret;
1.1       misho    2861: }
                   2862: 
                   2863: /* Configration make from file. */
                   2864: int
1.1.1.4 ! misho    2865: config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
1.1       misho    2866: {
                   2867:   int ret;
1.1.1.4 ! misho    2868:   *line_num = 0;
1.1       misho    2869: 
                   2870:   while (fgets (vty->buf, VTY_BUFSIZ, fp))
                   2871:     {
1.1.1.4 ! misho    2872:       ++(*line_num);
1.1       misho    2873: 
1.1.1.4 ! misho    2874:       ret = command_config_read_one_line (vty, NULL, 0);
1.1       misho    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:
1.1.1.2   misho    2952:     case BABEL_NODE:
1.1       misho    2953:     case OSPF_NODE:
                   2954:     case OSPF6_NODE:
                   2955:     case ISIS_NODE:
                   2956:     case KEYCHAIN_NODE:
                   2957:     case MASC_NODE:
                   2958:     case RMAP_NODE:
1.1.1.4 ! misho    2959:     case PIM_NODE:
1.1       misho    2960:     case VTY_NODE:
                   2961:       vty->node = CONFIG_NODE;
                   2962:       break;
                   2963:     case BGP_IPV4_NODE:
                   2964:     case BGP_IPV4M_NODE:
1.1.1.4 ! misho    2965:     case BGP_VPNV4_NODE:
        !          2966:     case BGP_VPNV6_NODE:
        !          2967:     case BGP_ENCAP_NODE:
        !          2968:     case BGP_ENCAPV6_NODE:
1.1       misho    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:
1.1.1.2   misho    3006:     case BABEL_NODE:
1.1       misho    3007:     case BGP_NODE:
1.1.1.4 ! misho    3008:     case BGP_ENCAP_NODE:
        !          3009:     case BGP_ENCAPV6_NODE:
1.1       misho    3010:     case BGP_VPNV4_NODE:
1.1.1.4 ! misho    3011:     case BGP_VPNV6_NODE:
1.1       misho    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:
1.1.1.4 ! misho    3023:     case PIM_NODE:
1.1       misho    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);
1.1.1.3   misho    3043:   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
1.1.1.4 ! misho    3044:   vty_out (vty, "configured with:%s    %s%s", VTY_NEWLINE,
        !          3045:            QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
1.1       misho    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 ();
1.1.1.4 ! misho    3140:   file_vty->wfd = fd;
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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: {
1.1.1.4 ! misho    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, "");
1.1       misho    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);
1.1.1.4 ! misho    4167:       install_element (VIEW_NODE, &show_commandtree_cmd);
1.1       misho    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);
1.1.1.4 ! misho    4177:       install_element (RESTRICTED_NODE, &show_commandtree_cmd);
1.1       misho    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);
1.1.1.4 ! misho    4190:   install_element (ENABLE_NODE, &show_commandtree_cmd);
1.1       misho    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:     }
1.1.1.4 ! misho    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;
1.1       misho    4303: }
                   4304: 
                   4305: void
                   4306: cmd_terminate ()
                   4307: {
1.1.1.4 ! misho    4308:   unsigned int i, j;
1.1       misho    4309:   struct cmd_node *cmd_node;
                   4310:   struct cmd_element *cmd_element;
1.1.1.4 ! misho    4311:   vector cmd_node_v;
1.1       misho    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++)
1.1.1.4 ! misho    4321:               if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
        !          4322:                 cmd_terminate_element(cmd_element);
1.1       misho    4323: 
                   4324:             vector_free (cmd_node_v);
                   4325:           }
                   4326: 
                   4327:       vector_free (cmdvec);
                   4328:       cmdvec = NULL;
                   4329:     }
                   4330: 
                   4331:   if (command_cr)
1.1.1.4 ! misho    4332:     XFREE(MTYPE_CMD_TOKENS, command_cr);
        !          4333:   if (token_cr.desc)
        !          4334:     XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
1.1       misho    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>