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

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

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