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

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\
1.1.1.3 ! misho      87: " GIT_INFO "\r\n";
1.1       misho      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: 
1.1.1.3 ! misho     871:   return no_match;
1.1       misho     872: }
                    873: 
                    874: static enum match_type
                    875: cmd_ipv6_prefix_match (const char *str)
                    876: {
                    877:   int state = STATE_START;
                    878:   int colons = 0, nums = 0, double_colon = 0;
                    879:   int mask;
                    880:   const char *sp = NULL;
                    881:   char *endptr = NULL;
                    882: 
                    883:   if (str == NULL)
                    884:     return partly_match;
                    885: 
                    886:   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
                    887:     return no_match;
                    888: 
                    889:   while (*str != '\0' && state != STATE_MASK)
                    890:     {
                    891:       switch (state)
                    892:        {
                    893:        case STATE_START:
                    894:          if (*str == ':')
                    895:            {
                    896:              if (*(str + 1) != ':' && *(str + 1) != '\0')
                    897:                return no_match;
                    898:              colons--;
                    899:              state = STATE_COLON;
                    900:            }
                    901:          else
                    902:            {
                    903:              sp = str;
                    904:              state = STATE_ADDR;
                    905:            }
                    906: 
                    907:          continue;
                    908:        case STATE_COLON:
                    909:          colons++;
                    910:          if (*(str + 1) == '/')
                    911:            return no_match;
                    912:          else if (*(str + 1) == ':')
                    913:            state = STATE_DOUBLE;
                    914:          else
                    915:            {
                    916:              sp = str + 1;
                    917:              state = STATE_ADDR;
                    918:            }
                    919:          break;
                    920:        case STATE_DOUBLE:
                    921:          if (double_colon)
                    922:            return no_match;
                    923: 
                    924:          if (*(str + 1) == ':')
                    925:            return no_match;
                    926:          else
                    927:            {
                    928:              if (*(str + 1) != '\0' && *(str + 1) != '/')
                    929:                colons++;
                    930:              sp = str + 1;
                    931: 
                    932:              if (*(str + 1) == '/')
                    933:                state = STATE_SLASH;
                    934:              else
                    935:                state = STATE_ADDR;
                    936:            }
                    937: 
                    938:          double_colon++;
                    939:          nums += 1;
                    940:          break;
                    941:        case STATE_ADDR:
                    942:          if (*(str + 1) == ':' || *(str + 1) == '.'
                    943:              || *(str + 1) == '\0' || *(str + 1) == '/')
                    944:            {
                    945:              if (str - sp > 3)
                    946:                return no_match;
                    947: 
                    948:              for (; sp <= str; sp++)
                    949:                if (*sp == '/')
                    950:                  return no_match;
                    951: 
                    952:              nums++;
                    953: 
                    954:              if (*(str + 1) == ':')
                    955:                state = STATE_COLON;
                    956:              else if (*(str + 1) == '.')
1.1.1.3 ! misho     957:                {
        !           958:                  if (colons || double_colon)
        !           959:                    state = STATE_DOT;
        !           960:                  else
        !           961:                    return no_match;
        !           962:                }
1.1       misho     963:              else if (*(str + 1) == '/')
                    964:                state = STATE_SLASH;
                    965:            }
                    966:          break;
                    967:        case STATE_DOT:
                    968:          state = STATE_ADDR;
                    969:          break;
                    970:        case STATE_SLASH:
                    971:          if (*(str + 1) == '\0')
                    972:            return partly_match;
                    973: 
                    974:          state = STATE_MASK;
                    975:          break;
                    976:        default:
                    977:          break;
                    978:        }
                    979: 
                    980:       if (nums > 11)
                    981:        return no_match;
                    982: 
                    983:       if (colons > 7)
                    984:        return no_match;
                    985: 
                    986:       str++;
                    987:     }
                    988: 
                    989:   if (state < STATE_MASK)
                    990:     return partly_match;
                    991: 
                    992:   mask = strtol (str, &endptr, 10);
                    993:   if (*endptr != '\0')
                    994:     return no_match;
                    995: 
                    996:   if (mask < 0 || mask > 128)
                    997:     return no_match;
                    998:   
                    999: /* I don't know why mask < 13 makes command match partly.
                   1000:    Forgive me to make this comments. I Want to set static default route
                   1001:    because of lack of function to originate default in ospf6d; sorry
                   1002:        yasu
                   1003:   if (mask < 13)
                   1004:     return partly_match;
                   1005: */
                   1006: 
                   1007:   return exact_match;
                   1008: }
                   1009: 
                   1010: #endif /* HAVE_IPV6  */
                   1011: 
                   1012: #define DECIMAL_STRLEN_MAX 10
                   1013: 
                   1014: static int
                   1015: cmd_range_match (const char *range, const char *str)
                   1016: {
                   1017:   char *p;
                   1018:   char buf[DECIMAL_STRLEN_MAX + 1];
                   1019:   char *endptr = NULL;
                   1020:   unsigned long min, max, val;
                   1021: 
                   1022:   if (str == NULL)
                   1023:     return 1;
                   1024: 
                   1025:   val = strtoul (str, &endptr, 10);
                   1026:   if (*endptr != '\0')
                   1027:     return 0;
                   1028: 
                   1029:   range++;
                   1030:   p = strchr (range, '-');
                   1031:   if (p == NULL)
                   1032:     return 0;
                   1033:   if (p - range > DECIMAL_STRLEN_MAX)
                   1034:     return 0;
                   1035:   strncpy (buf, range, p - range);
                   1036:   buf[p - range] = '\0';
                   1037:   min = strtoul (buf, &endptr, 10);
                   1038:   if (*endptr != '\0')
                   1039:     return 0;
                   1040: 
                   1041:   range = p + 1;
                   1042:   p = strchr (range, '>');
                   1043:   if (p == NULL)
                   1044:     return 0;
                   1045:   if (p - range > DECIMAL_STRLEN_MAX)
                   1046:     return 0;
                   1047:   strncpy (buf, range, p - range);
                   1048:   buf[p - range] = '\0';
                   1049:   max = strtoul (buf, &endptr, 10);
                   1050:   if (*endptr != '\0')
                   1051:     return 0;
                   1052: 
                   1053:   if (val < min || val > max)
                   1054:     return 0;
                   1055: 
                   1056:   return 1;
                   1057: }
                   1058: 
                   1059: /* Make completion match and return match type flag. */
                   1060: static enum match_type
                   1061: cmd_filter_by_completion (char *command, vector v, unsigned int index)
                   1062: {
                   1063:   unsigned int i;
                   1064:   const char *str;
                   1065:   struct cmd_element *cmd_element;
                   1066:   enum match_type match_type;
                   1067:   vector descvec;
                   1068:   struct desc *desc;
                   1069: 
                   1070:   match_type = no_match;
                   1071: 
                   1072:   /* If command and cmd_element string does not match set NULL to vector */
                   1073:   for (i = 0; i < vector_active (v); i++)
                   1074:     if ((cmd_element = vector_slot (v, i)) != NULL)
                   1075:       {
                   1076:        if (index >= vector_active (cmd_element->strvec))
                   1077:          vector_slot (v, i) = NULL;
                   1078:        else
                   1079:          {
                   1080:            unsigned int j;
                   1081:            int matched = 0;
                   1082: 
                   1083:            descvec = vector_slot (cmd_element->strvec, index);
                   1084: 
                   1085:            for (j = 0; j < vector_active (descvec); j++)
                   1086:              if ((desc = vector_slot (descvec, j)))
                   1087:                {
                   1088:                  str = desc->cmd;
                   1089:                  
                   1090:                  if (CMD_VARARG (str))
                   1091:                    {
                   1092:                      if (match_type < vararg_match)
                   1093:                        match_type = vararg_match;
                   1094:                      matched++;
                   1095:                    }
                   1096:                  else if (CMD_RANGE (str))
                   1097:                    {
                   1098:                      if (cmd_range_match (str, command))
                   1099:                        {
                   1100:                          if (match_type < range_match)
                   1101:                            match_type = range_match;
                   1102: 
                   1103:                          matched++;
                   1104:                        }
                   1105:                    }
                   1106: #ifdef HAVE_IPV6
                   1107:                  else if (CMD_IPV6 (str))
                   1108:                    {
                   1109:                      if (cmd_ipv6_match (command))
                   1110:                        {
                   1111:                          if (match_type < ipv6_match)
                   1112:                            match_type = ipv6_match;
                   1113: 
                   1114:                          matched++;
                   1115:                        }
                   1116:                    }
                   1117:                  else if (CMD_IPV6_PREFIX (str))
                   1118:                    {
                   1119:                      if (cmd_ipv6_prefix_match (command))
                   1120:                        {
                   1121:                          if (match_type < ipv6_prefix_match)
                   1122:                            match_type = ipv6_prefix_match;
                   1123: 
                   1124:                          matched++;
                   1125:                        }
                   1126:                    }
                   1127: #endif /* HAVE_IPV6  */
                   1128:                  else if (CMD_IPV4 (str))
                   1129:                    {
                   1130:                      if (cmd_ipv4_match (command))
                   1131:                        {
                   1132:                          if (match_type < ipv4_match)
                   1133:                            match_type = ipv4_match;
                   1134: 
                   1135:                          matched++;
                   1136:                        }
                   1137:                    }
                   1138:                  else if (CMD_IPV4_PREFIX (str))
                   1139:                    {
                   1140:                      if (cmd_ipv4_prefix_match (command))
                   1141:                        {
                   1142:                          if (match_type < ipv4_prefix_match)
                   1143:                            match_type = ipv4_prefix_match;
                   1144:                          matched++;
                   1145:                        }
                   1146:                    }
                   1147:                  else
                   1148:                    /* Check is this point's argument optional ? */
                   1149:                  if (CMD_OPTION (str) || CMD_VARIABLE (str))
                   1150:                    {
                   1151:                      if (match_type < extend_match)
                   1152:                        match_type = extend_match;
                   1153:                      matched++;
                   1154:                    }
                   1155:                  else if (strncmp (command, str, strlen (command)) == 0)
                   1156:                    {
                   1157:                      if (strcmp (command, str) == 0)
                   1158:                        match_type = exact_match;
                   1159:                      else
                   1160:                        {
                   1161:                          if (match_type < partly_match)
                   1162:                            match_type = partly_match;
                   1163:                        }
                   1164:                      matched++;
                   1165:                    }
                   1166:                }
                   1167:            if (!matched)
                   1168:              vector_slot (v, i) = NULL;
                   1169:          }
                   1170:       }
                   1171:   return match_type;
                   1172: }
                   1173: 
                   1174: /* Filter vector by command character with index. */
                   1175: static enum match_type
                   1176: cmd_filter_by_string (char *command, vector v, unsigned int index)
                   1177: {
                   1178:   unsigned int i;
                   1179:   const char *str;
                   1180:   struct cmd_element *cmd_element;
                   1181:   enum match_type match_type;
                   1182:   vector descvec;
                   1183:   struct desc *desc;
                   1184: 
                   1185:   match_type = no_match;
                   1186: 
                   1187:   /* If command and cmd_element string does not match set NULL to vector */
                   1188:   for (i = 0; i < vector_active (v); i++)
                   1189:     if ((cmd_element = vector_slot (v, i)) != NULL)
                   1190:       {
                   1191:        /* If given index is bigger than max string vector of command,
                   1192:           set NULL */
                   1193:        if (index >= vector_active (cmd_element->strvec))
                   1194:          vector_slot (v, i) = NULL;
                   1195:        else
                   1196:          {
                   1197:            unsigned int j;
                   1198:            int matched = 0;
                   1199: 
                   1200:            descvec = vector_slot (cmd_element->strvec, index);
                   1201: 
                   1202:            for (j = 0; j < vector_active (descvec); j++)
                   1203:              if ((desc = vector_slot (descvec, j)))
                   1204:                {
                   1205:                  str = desc->cmd;
                   1206: 
                   1207:                  if (CMD_VARARG (str))
                   1208:                    {
                   1209:                      if (match_type < vararg_match)
                   1210:                        match_type = vararg_match;
                   1211:                      matched++;
                   1212:                    }
                   1213:                  else if (CMD_RANGE (str))
                   1214:                    {
                   1215:                      if (cmd_range_match (str, command))
                   1216:                        {
                   1217:                          if (match_type < range_match)
                   1218:                            match_type = range_match;
                   1219:                          matched++;
                   1220:                        }
                   1221:                    }
                   1222: #ifdef HAVE_IPV6
                   1223:                  else if (CMD_IPV6 (str))
                   1224:                    {
                   1225:                      if (cmd_ipv6_match (command) == exact_match)
                   1226:                        {
                   1227:                          if (match_type < ipv6_match)
                   1228:                            match_type = ipv6_match;
                   1229:                          matched++;
                   1230:                        }
                   1231:                    }
                   1232:                  else if (CMD_IPV6_PREFIX (str))
                   1233:                    {
                   1234:                      if (cmd_ipv6_prefix_match (command) == exact_match)
                   1235:                        {
                   1236:                          if (match_type < ipv6_prefix_match)
                   1237:                            match_type = ipv6_prefix_match;
                   1238:                          matched++;
                   1239:                        }
                   1240:                    }
                   1241: #endif /* HAVE_IPV6  */
                   1242:                  else if (CMD_IPV4 (str))
                   1243:                    {
                   1244:                      if (cmd_ipv4_match (command) == exact_match)
                   1245:                        {
                   1246:                          if (match_type < ipv4_match)
                   1247:                            match_type = ipv4_match;
                   1248:                          matched++;
                   1249:                        }
                   1250:                    }
                   1251:                  else if (CMD_IPV4_PREFIX (str))
                   1252:                    {
                   1253:                      if (cmd_ipv4_prefix_match (command) == exact_match)
                   1254:                        {
                   1255:                          if (match_type < ipv4_prefix_match)
                   1256:                            match_type = ipv4_prefix_match;
                   1257:                          matched++;
                   1258:                        }
                   1259:                    }
                   1260:                  else if (CMD_OPTION (str) || CMD_VARIABLE (str))
                   1261:                    {
                   1262:                      if (match_type < extend_match)
                   1263:                        match_type = extend_match;
                   1264:                      matched++;
                   1265:                    }
                   1266:                  else
                   1267:                    {
                   1268:                      if (strcmp (command, str) == 0)
                   1269:                        {
                   1270:                          match_type = exact_match;
                   1271:                          matched++;
                   1272:                        }
                   1273:                    }
                   1274:                }
                   1275:            if (!matched)
                   1276:              vector_slot (v, i) = NULL;
                   1277:          }
                   1278:       }
                   1279:   return match_type;
                   1280: }
                   1281: 
                   1282: /* Check ambiguous match */
                   1283: static int
                   1284: is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
                   1285: {
                   1286:   unsigned int i;
                   1287:   unsigned int j;
                   1288:   const char *str = NULL;
                   1289:   struct cmd_element *cmd_element;
                   1290:   const char *matched = NULL;
                   1291:   vector descvec;
                   1292:   struct desc *desc;
                   1293: 
                   1294:   for (i = 0; i < vector_active (v); i++)
                   1295:     if ((cmd_element = vector_slot (v, i)) != NULL)
                   1296:       {
                   1297:        int match = 0;
                   1298: 
                   1299:        descvec = vector_slot (cmd_element->strvec, index);
                   1300: 
                   1301:        for (j = 0; j < vector_active (descvec); j++)
                   1302:          if ((desc = vector_slot (descvec, j)))
                   1303:            {
                   1304:              enum match_type ret;
                   1305:              
                   1306:              str = desc->cmd;
                   1307: 
                   1308:              switch (type)
                   1309:                {
                   1310:                case exact_match:
                   1311:                  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
                   1312:                      && strcmp (command, str) == 0)
                   1313:                    match++;
                   1314:                  break;
                   1315:                case partly_match:
                   1316:                  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
                   1317:                      && strncmp (command, str, strlen (command)) == 0)
                   1318:                    {
                   1319:                      if (matched && strcmp (matched, str) != 0)
                   1320:                        return 1;       /* There is ambiguous match. */
                   1321:                      else
                   1322:                        matched = str;
                   1323:                      match++;
                   1324:                    }
                   1325:                  break;
                   1326:                case range_match:
                   1327:                  if (cmd_range_match (str, command))
                   1328:                    {
                   1329:                      if (matched && strcmp (matched, str) != 0)
                   1330:                        return 1;
                   1331:                      else
                   1332:                        matched = str;
                   1333:                      match++;
                   1334:                    }
                   1335:                  break;
                   1336: #ifdef HAVE_IPV6
                   1337:                case ipv6_match:
                   1338:                  if (CMD_IPV6 (str))
                   1339:                    match++;
                   1340:                  break;
                   1341:                case ipv6_prefix_match:
                   1342:                  if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
                   1343:                    {
                   1344:                      if (ret == partly_match)
                   1345:                        return 2;       /* There is incomplete match. */
                   1346: 
                   1347:                      match++;
                   1348:                    }
                   1349:                  break;
                   1350: #endif /* HAVE_IPV6 */
                   1351:                case ipv4_match:
                   1352:                  if (CMD_IPV4 (str))
                   1353:                    match++;
                   1354:                  break;
                   1355:                case ipv4_prefix_match:
                   1356:                  if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
                   1357:                    {
                   1358:                      if (ret == partly_match)
                   1359:                        return 2;       /* There is incomplete match. */
                   1360: 
                   1361:                      match++;
                   1362:                    }
                   1363:                  break;
                   1364:                case extend_match:
                   1365:                  if (CMD_OPTION (str) || CMD_VARIABLE (str))
                   1366:                    match++;
                   1367:                  break;
                   1368:                case no_match:
                   1369:                default:
                   1370:                  break;
                   1371:                }
                   1372:            }
                   1373:        if (!match)
                   1374:          vector_slot (v, i) = NULL;
                   1375:       }
                   1376:   return 0;
                   1377: }
                   1378: 
                   1379: /* If src matches dst return dst string, otherwise return NULL */
                   1380: static const char *
                   1381: cmd_entry_function (const char *src, const char *dst)
                   1382: {
                   1383:   /* Skip variable arguments. */
                   1384:   if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
                   1385:       CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
                   1386:     return NULL;
                   1387: 
                   1388:   /* In case of 'command \t', given src is NULL string. */
                   1389:   if (src == NULL)
                   1390:     return dst;
                   1391: 
                   1392:   /* Matched with input string. */
                   1393:   if (strncmp (src, dst, strlen (src)) == 0)
                   1394:     return dst;
                   1395: 
                   1396:   return NULL;
                   1397: }
                   1398: 
                   1399: /* If src matches dst return dst string, otherwise return NULL */
                   1400: /* This version will return the dst string always if it is
                   1401:    CMD_VARIABLE for '?' key processing */
                   1402: static const char *
                   1403: cmd_entry_function_desc (const char *src, const char *dst)
                   1404: {
                   1405:   if (CMD_VARARG (dst))
                   1406:     return dst;
                   1407: 
                   1408:   if (CMD_RANGE (dst))
                   1409:     {
                   1410:       if (cmd_range_match (dst, src))
                   1411:        return dst;
                   1412:       else
                   1413:        return NULL;
                   1414:     }
                   1415: 
                   1416: #ifdef HAVE_IPV6
                   1417:   if (CMD_IPV6 (dst))
                   1418:     {
                   1419:       if (cmd_ipv6_match (src))
                   1420:        return dst;
                   1421:       else
                   1422:        return NULL;
                   1423:     }
                   1424: 
                   1425:   if (CMD_IPV6_PREFIX (dst))
                   1426:     {
                   1427:       if (cmd_ipv6_prefix_match (src))
                   1428:        return dst;
                   1429:       else
                   1430:        return NULL;
                   1431:     }
                   1432: #endif /* HAVE_IPV6 */
                   1433: 
                   1434:   if (CMD_IPV4 (dst))
                   1435:     {
                   1436:       if (cmd_ipv4_match (src))
                   1437:        return dst;
                   1438:       else
                   1439:        return NULL;
                   1440:     }
                   1441: 
                   1442:   if (CMD_IPV4_PREFIX (dst))
                   1443:     {
                   1444:       if (cmd_ipv4_prefix_match (src))
                   1445:        return dst;
                   1446:       else
                   1447:        return NULL;
                   1448:     }
                   1449: 
                   1450:   /* Optional or variable commands always match on '?' */
                   1451:   if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
                   1452:     return dst;
                   1453: 
                   1454:   /* In case of 'command \t', given src is NULL string. */
                   1455:   if (src == NULL)
                   1456:     return dst;
                   1457: 
                   1458:   if (strncmp (src, dst, strlen (src)) == 0)
                   1459:     return dst;
                   1460:   else
                   1461:     return NULL;
                   1462: }
                   1463: 
                   1464: /* Check same string element existence.  If it isn't there return
                   1465:     1. */
                   1466: static int
                   1467: cmd_unique_string (vector v, const char *str)
                   1468: {
                   1469:   unsigned int i;
                   1470:   char *match;
                   1471: 
                   1472:   for (i = 0; i < vector_active (v); i++)
                   1473:     if ((match = vector_slot (v, i)) != NULL)
                   1474:       if (strcmp (match, str) == 0)
                   1475:        return 0;
                   1476:   return 1;
                   1477: }
                   1478: 
                   1479: /* Compare string to description vector.  If there is same string
                   1480:    return 1 else return 0. */
                   1481: static int
                   1482: desc_unique_string (vector v, const char *str)
                   1483: {
                   1484:   unsigned int i;
                   1485:   struct desc *desc;
                   1486: 
                   1487:   for (i = 0; i < vector_active (v); i++)
                   1488:     if ((desc = vector_slot (v, i)) != NULL)
                   1489:       if (strcmp (desc->cmd, str) == 0)
                   1490:        return 1;
                   1491:   return 0;
                   1492: }
                   1493: 
                   1494: static int 
                   1495: cmd_try_do_shortcut (enum node_type node, char* first_word) {
                   1496:   if ( first_word != NULL &&
                   1497:        node != AUTH_NODE &&
                   1498:        node != VIEW_NODE &&
                   1499:        node != AUTH_ENABLE_NODE &&
                   1500:        node != ENABLE_NODE &&
                   1501:        node != RESTRICTED_NODE &&
                   1502:        0 == strcmp( "do", first_word ) )
                   1503:     return 1;
                   1504:   return 0;
                   1505: }
                   1506: 
                   1507: /* '?' describe command support. */
                   1508: static vector
                   1509: cmd_describe_command_real (vector vline, struct vty *vty, int *status)
                   1510: {
                   1511:   unsigned int i;
                   1512:   vector cmd_vector;
                   1513: #define INIT_MATCHVEC_SIZE 10
                   1514:   vector matchvec;
                   1515:   struct cmd_element *cmd_element;
                   1516:   unsigned int index;
                   1517:   int ret;
                   1518:   enum match_type match;
                   1519:   char *command;
                   1520: 
                   1521:   /* Set index. */
                   1522:   if (vector_active (vline) == 0)
                   1523:     {
                   1524:       *status = CMD_ERR_NO_MATCH;
                   1525:       return NULL;
                   1526:     }
                   1527:   else
                   1528:     index = vector_active (vline) - 1;
                   1529:   
                   1530:   /* Make copy vector of current node's command vector. */
                   1531:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
                   1532: 
                   1533:   /* Prepare match vector */
                   1534:   matchvec = vector_init (INIT_MATCHVEC_SIZE);
                   1535: 
                   1536:   /* Filter commands. */
                   1537:   /* Only words precedes current word will be checked in this loop. */
                   1538:   for (i = 0; i < index; i++)
                   1539:     if ((command = vector_slot (vline, i)))
                   1540:       {
                   1541:        match = cmd_filter_by_completion (command, cmd_vector, i);
                   1542:        
                   1543:        if (match == vararg_match)
                   1544:          {
                   1545:            struct cmd_element *cmd_element;
                   1546:            vector descvec;
                   1547:            unsigned int j, k;
                   1548: 
                   1549:            for (j = 0; j < vector_active (cmd_vector); j++)
                   1550:              if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
                   1551:                  && (vector_active (cmd_element->strvec)))
                   1552:                {
                   1553:                  descvec = vector_slot (cmd_element->strvec,
                   1554:                                         vector_active (cmd_element->strvec) - 1);
                   1555:                  for (k = 0; k < vector_active (descvec); k++)
                   1556:                    {
                   1557:                      struct desc *desc = vector_slot (descvec, k);
                   1558:                      vector_set (matchvec, desc);
                   1559:                    }
                   1560:                }
                   1561:             
                   1562:            vector_set (matchvec, &desc_cr);
                   1563:            vector_free (cmd_vector);
                   1564: 
                   1565:            return matchvec;
                   1566:          }
                   1567: 
                   1568:        if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
                   1569:          {
                   1570:            vector_free (cmd_vector);
                   1571:            vector_free (matchvec);
                   1572:            *status = CMD_ERR_AMBIGUOUS;
                   1573:            return NULL;
                   1574:          }
                   1575:        else if (ret == 2)
                   1576:          {
                   1577:            vector_free (cmd_vector);
                   1578:            vector_free (matchvec);
                   1579:            *status = CMD_ERR_NO_MATCH;
                   1580:            return NULL;
                   1581:          }
                   1582:       }
                   1583: 
                   1584:   /* Prepare match vector */
                   1585:   /*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
                   1586: 
                   1587:   /* Make sure that cmd_vector is filtered based on current word */
                   1588:   command = vector_slot (vline, index);
                   1589:   if (command)
                   1590:     match = cmd_filter_by_completion (command, cmd_vector, index);
                   1591: 
                   1592:   /* Make description vector. */
                   1593:   for (i = 0; i < vector_active (cmd_vector); i++)
                   1594:     if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
                   1595:       {
                   1596:        vector strvec = cmd_element->strvec;
                   1597: 
                   1598:        /* if command is NULL, index may be equal to vector_active */
                   1599:        if (command && index >= vector_active (strvec))
                   1600:          vector_slot (cmd_vector, i) = NULL;
                   1601:        else
                   1602:          {
                   1603:            /* Check if command is completed. */
                   1604:            if (command == NULL && index == vector_active (strvec))
                   1605:              {
                   1606:                if (!desc_unique_string (matchvec, command_cr))
                   1607:                  vector_set (matchvec, &desc_cr);
                   1608:              }
                   1609:            else
                   1610:              {
                   1611:                unsigned int j;
                   1612:                vector descvec = vector_slot (strvec, index);
                   1613:                struct desc *desc;
                   1614: 
                   1615:                for (j = 0; j < vector_active (descvec); j++)
                   1616:                  if ((desc = vector_slot (descvec, j)))
                   1617:                    {
                   1618:                      const char *string;
                   1619: 
                   1620:                      string = cmd_entry_function_desc (command, desc->cmd);
                   1621:                      if (string)
                   1622:                        {
                   1623:                          /* Uniqueness check */
                   1624:                          if (!desc_unique_string (matchvec, string))
                   1625:                            vector_set (matchvec, desc);
                   1626:                        }
                   1627:                    }
                   1628:              }
                   1629:          }
                   1630:       }
                   1631:   vector_free (cmd_vector);
                   1632: 
                   1633:   if (vector_slot (matchvec, 0) == NULL)
                   1634:     {
                   1635:       vector_free (matchvec);
                   1636:       *status = CMD_ERR_NO_MATCH;
                   1637:       return NULL;
                   1638:     }
                   1639: 
                   1640:   *status = CMD_SUCCESS;
                   1641:   return matchvec;
                   1642: }
                   1643: 
                   1644: vector
                   1645: cmd_describe_command (vector vline, struct vty *vty, int *status)
                   1646: {
                   1647:   vector ret;
                   1648: 
                   1649:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
                   1650:     {
                   1651:       enum node_type onode;
                   1652:       vector shifted_vline;
                   1653:       unsigned int index;
                   1654: 
                   1655:       onode = vty->node;
                   1656:       vty->node = ENABLE_NODE;
                   1657:       /* We can try it on enable node, cos' the vty is authenticated */
                   1658: 
                   1659:       shifted_vline = vector_init (vector_count(vline));
                   1660:       /* use memcpy? */
                   1661:       for (index = 1; index < vector_active (vline); index++) 
                   1662:        {
                   1663:          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
                   1664:        }
                   1665: 
                   1666:       ret = cmd_describe_command_real (shifted_vline, vty, status);
                   1667: 
                   1668:       vector_free(shifted_vline);
                   1669:       vty->node = onode;
                   1670:       return ret;
                   1671:   }
                   1672: 
                   1673: 
                   1674:   return cmd_describe_command_real (vline, vty, status);
                   1675: }
                   1676: 
                   1677: 
                   1678: /* Check LCD of matched command. */
                   1679: static int
                   1680: cmd_lcd (char **matched)
                   1681: {
                   1682:   int i;
                   1683:   int j;
                   1684:   int lcd = -1;
                   1685:   char *s1, *s2;
                   1686:   char c1, c2;
                   1687: 
                   1688:   if (matched[0] == NULL || matched[1] == NULL)
                   1689:     return 0;
                   1690: 
                   1691:   for (i = 1; matched[i] != NULL; i++)
                   1692:     {
                   1693:       s1 = matched[i - 1];
                   1694:       s2 = matched[i];
                   1695: 
                   1696:       for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
                   1697:        if (c1 != c2)
                   1698:          break;
                   1699: 
                   1700:       if (lcd < 0)
                   1701:        lcd = j;
                   1702:       else
                   1703:        {
                   1704:          if (lcd > j)
                   1705:            lcd = j;
                   1706:        }
                   1707:     }
                   1708:   return lcd;
                   1709: }
                   1710: 
                   1711: /* Command line completion support. */
                   1712: static char **
                   1713: cmd_complete_command_real (vector vline, struct vty *vty, int *status)
                   1714: {
                   1715:   unsigned int i;
                   1716:   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
                   1717: #define INIT_MATCHVEC_SIZE 10
                   1718:   vector matchvec;
                   1719:   struct cmd_element *cmd_element;
                   1720:   unsigned int index;
                   1721:   char **match_str;
                   1722:   struct desc *desc;
                   1723:   vector descvec;
                   1724:   char *command;
                   1725:   int lcd;
                   1726: 
                   1727:   if (vector_active (vline) == 0)
                   1728:     {
                   1729:       vector_free (cmd_vector);
                   1730:       *status = CMD_ERR_NO_MATCH;
                   1731:       return NULL;
                   1732:     }
                   1733:   else
                   1734:     index = vector_active (vline) - 1;
                   1735: 
                   1736:   /* First, filter by preceeding command string */
                   1737:   for (i = 0; i < index; i++)
                   1738:     if ((command = vector_slot (vline, i)))
                   1739:       {
                   1740:        enum match_type match;
                   1741:        int ret;
                   1742: 
                   1743:        /* First try completion match, if there is exactly match return 1 */
                   1744:        match = cmd_filter_by_completion (command, cmd_vector, i);
                   1745: 
                   1746:        /* If there is exact match then filter ambiguous match else check
                   1747:           ambiguousness. */
                   1748:        if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
                   1749:          {
                   1750:            vector_free (cmd_vector);
                   1751:            *status = CMD_ERR_AMBIGUOUS;
                   1752:            return NULL;
                   1753:          }
                   1754:        /*
                   1755:           else if (ret == 2)
                   1756:           {
                   1757:           vector_free (cmd_vector);
                   1758:           *status = CMD_ERR_NO_MATCH;
                   1759:           return NULL;
                   1760:           }
                   1761:         */
                   1762:       }
                   1763:   
                   1764:   /* Prepare match vector. */
                   1765:   matchvec = vector_init (INIT_MATCHVEC_SIZE);
                   1766: 
                   1767:   /* Now we got into completion */
                   1768:   for (i = 0; i < vector_active (cmd_vector); i++)
                   1769:     if ((cmd_element = vector_slot (cmd_vector, i)))
                   1770:       {
                   1771:        const char *string;
                   1772:        vector strvec = cmd_element->strvec;
                   1773: 
                   1774:        /* Check field length */
                   1775:        if (index >= vector_active (strvec))
                   1776:          vector_slot (cmd_vector, i) = NULL;
                   1777:        else
                   1778:          {
                   1779:            unsigned int j;
                   1780: 
                   1781:            descvec = vector_slot (strvec, index);
                   1782:            for (j = 0; j < vector_active (descvec); j++)
                   1783:              if ((desc = vector_slot (descvec, j)))
                   1784:                {
                   1785:                  if ((string = 
                   1786:                       cmd_entry_function (vector_slot (vline, index),
                   1787:                                           desc->cmd)))
                   1788:                    if (cmd_unique_string (matchvec, string))
                   1789:                      vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
                   1790:                }
                   1791:          }
                   1792:       }
                   1793: 
                   1794:   /* We don't need cmd_vector any more. */
                   1795:   vector_free (cmd_vector);
                   1796: 
                   1797:   /* No matched command */
                   1798:   if (vector_slot (matchvec, 0) == NULL)
                   1799:     {
                   1800:       vector_free (matchvec);
                   1801: 
                   1802:       /* In case of 'command \t' pattern.  Do you need '?' command at
                   1803:          the end of the line. */
                   1804:       if (vector_slot (vline, index) == '\0')
                   1805:        *status = CMD_ERR_NOTHING_TODO;
                   1806:       else
                   1807:        *status = CMD_ERR_NO_MATCH;
                   1808:       return NULL;
                   1809:     }
                   1810: 
                   1811:   /* Only one matched */
                   1812:   if (vector_slot (matchvec, 1) == NULL)
                   1813:     {
                   1814:       match_str = (char **) matchvec->index;
                   1815:       vector_only_wrapper_free (matchvec);
                   1816:       *status = CMD_COMPLETE_FULL_MATCH;
                   1817:       return match_str;
                   1818:     }
                   1819:   /* Make it sure last element is NULL. */
                   1820:   vector_set (matchvec, NULL);
                   1821: 
                   1822:   /* Check LCD of matched strings. */
                   1823:   if (vector_slot (vline, index) != NULL)
                   1824:     {
                   1825:       lcd = cmd_lcd ((char **) matchvec->index);
                   1826: 
                   1827:       if (lcd)
                   1828:        {
                   1829:          int len = strlen (vector_slot (vline, index));
                   1830: 
                   1831:          if (len < lcd)
                   1832:            {
                   1833:              char *lcdstr;
                   1834: 
                   1835:              lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
                   1836:              memcpy (lcdstr, matchvec->index[0], lcd);
                   1837:              lcdstr[lcd] = '\0';
                   1838: 
                   1839:              /* match_str = (char **) &lcdstr; */
                   1840: 
                   1841:              /* Free matchvec. */
                   1842:              for (i = 0; i < vector_active (matchvec); i++)
                   1843:                {
                   1844:                  if (vector_slot (matchvec, i))
                   1845:                    XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
                   1846:                }
                   1847:              vector_free (matchvec);
                   1848: 
                   1849:              /* Make new matchvec. */
                   1850:              matchvec = vector_init (INIT_MATCHVEC_SIZE);
                   1851:              vector_set (matchvec, lcdstr);
                   1852:              match_str = (char **) matchvec->index;
                   1853:              vector_only_wrapper_free (matchvec);
                   1854: 
                   1855:              *status = CMD_COMPLETE_MATCH;
                   1856:              return match_str;
                   1857:            }
                   1858:        }
                   1859:     }
                   1860: 
                   1861:   match_str = (char **) matchvec->index;
                   1862:   vector_only_wrapper_free (matchvec);
                   1863:   *status = CMD_COMPLETE_LIST_MATCH;
                   1864:   return match_str;
                   1865: }
                   1866: 
                   1867: char **
                   1868: cmd_complete_command (vector vline, struct vty *vty, int *status)
                   1869: {
                   1870:   char **ret;
                   1871: 
                   1872:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
                   1873:     {
                   1874:       enum node_type onode;
                   1875:       vector shifted_vline;
                   1876:       unsigned int index;
                   1877: 
                   1878:       onode = vty->node;
                   1879:       vty->node = ENABLE_NODE;
                   1880:       /* We can try it on enable node, cos' the vty is authenticated */
                   1881: 
                   1882:       shifted_vline = vector_init (vector_count(vline));
                   1883:       /* use memcpy? */
                   1884:       for (index = 1; index < vector_active (vline); index++) 
                   1885:        {
                   1886:          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
                   1887:        }
                   1888: 
                   1889:       ret = cmd_complete_command_real (shifted_vline, vty, status);
                   1890: 
                   1891:       vector_free(shifted_vline);
                   1892:       vty->node = onode;
                   1893:       return ret;
                   1894:   }
                   1895: 
                   1896: 
                   1897:   return cmd_complete_command_real (vline, vty, status);
                   1898: }
                   1899: 
                   1900: /* return parent node */
                   1901: /* MUST eventually converge on CONFIG_NODE */
                   1902: enum node_type
                   1903: node_parent ( enum node_type node )
                   1904: {
                   1905:   enum node_type ret;
                   1906: 
                   1907:   assert (node > CONFIG_NODE);
                   1908: 
                   1909:   switch (node)
                   1910:     {
                   1911:     case BGP_VPNV4_NODE:
                   1912:     case BGP_IPV4_NODE:
                   1913:     case BGP_IPV4M_NODE:
                   1914:     case BGP_IPV6_NODE:
                   1915:     case BGP_IPV6M_NODE:
                   1916:       ret = BGP_NODE;
                   1917:       break;
                   1918:     case KEYCHAIN_KEY_NODE:
                   1919:       ret = KEYCHAIN_NODE;
                   1920:       break;
                   1921:     default:
                   1922:       ret = CONFIG_NODE;
                   1923:     }
                   1924: 
                   1925:   return ret;
                   1926: }
                   1927: 
                   1928: /* Execute command by argument vline vector. */
                   1929: static int
                   1930: cmd_execute_command_real (vector vline, struct vty *vty,
                   1931:                          struct cmd_element **cmd)
                   1932: {
                   1933:   unsigned int i;
                   1934:   unsigned int index;
                   1935:   vector cmd_vector;
                   1936:   struct cmd_element *cmd_element;
                   1937:   struct cmd_element *matched_element;
                   1938:   unsigned int matched_count, incomplete_count;
                   1939:   int argc;
                   1940:   const char *argv[CMD_ARGC_MAX];
                   1941:   enum match_type match = 0;
                   1942:   int varflag;
                   1943:   char *command;
                   1944: 
                   1945:   /* Make copy of command elements. */
                   1946:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
                   1947: 
                   1948:   for (index = 0; index < vector_active (vline); index++)
                   1949:     if ((command = vector_slot (vline, index)))
                   1950:       {
                   1951:        int ret;
                   1952: 
                   1953:        match = cmd_filter_by_completion (command, cmd_vector, index);
                   1954: 
                   1955:        if (match == vararg_match)
                   1956:          break;
                   1957:         
                   1958:        ret = is_cmd_ambiguous (command, cmd_vector, index, match);
                   1959: 
                   1960:        if (ret == 1)
                   1961:          {
                   1962:            vector_free (cmd_vector);
                   1963:            return CMD_ERR_AMBIGUOUS;
                   1964:          }
                   1965:        else if (ret == 2)
                   1966:          {
                   1967:            vector_free (cmd_vector);
                   1968:            return CMD_ERR_NO_MATCH;
                   1969:          }
                   1970:       }
                   1971: 
                   1972:   /* Check matched count. */
                   1973:   matched_element = NULL;
                   1974:   matched_count = 0;
                   1975:   incomplete_count = 0;
                   1976: 
                   1977:   for (i = 0; i < vector_active (cmd_vector); i++)
                   1978:     if ((cmd_element = vector_slot (cmd_vector, i)))
                   1979:       {
                   1980:        if (match == vararg_match || index >= cmd_element->cmdsize)
                   1981:          {
                   1982:            matched_element = cmd_element;
                   1983: #if 0
                   1984:            printf ("DEBUG: %s\n", cmd_element->string);
                   1985: #endif
                   1986:            matched_count++;
                   1987:          }
                   1988:        else
                   1989:          {
                   1990:            incomplete_count++;
                   1991:          }
                   1992:       }
                   1993: 
                   1994:   /* Finish of using cmd_vector. */
                   1995:   vector_free (cmd_vector);
                   1996: 
                   1997:   /* To execute command, matched_count must be 1. */
                   1998:   if (matched_count == 0)
                   1999:     {
                   2000:       if (incomplete_count)
                   2001:        return CMD_ERR_INCOMPLETE;
                   2002:       else
                   2003:        return CMD_ERR_NO_MATCH;
                   2004:     }
                   2005: 
                   2006:   if (matched_count > 1)
                   2007:     return CMD_ERR_AMBIGUOUS;
                   2008: 
                   2009:   /* Argument treatment */
                   2010:   varflag = 0;
                   2011:   argc = 0;
                   2012: 
                   2013:   for (i = 0; i < vector_active (vline); i++)
                   2014:     {
                   2015:       if (varflag)
                   2016:        argv[argc++] = vector_slot (vline, i);
                   2017:       else
                   2018:        {
                   2019:          vector descvec = vector_slot (matched_element->strvec, i);
                   2020: 
                   2021:          if (vector_active (descvec) == 1)
                   2022:            {
                   2023:              struct desc *desc = vector_slot (descvec, 0);
                   2024: 
                   2025:              if (CMD_VARARG (desc->cmd))
                   2026:                varflag = 1;
                   2027: 
                   2028:              if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
                   2029:                argv[argc++] = vector_slot (vline, i);
                   2030:            }
                   2031:          else
                   2032:            argv[argc++] = vector_slot (vline, i);
                   2033:        }
                   2034: 
                   2035:       if (argc >= CMD_ARGC_MAX)
                   2036:        return CMD_ERR_EXEED_ARGC_MAX;
                   2037:     }
                   2038: 
                   2039:   /* For vtysh execution. */
                   2040:   if (cmd)
                   2041:     *cmd = matched_element;
                   2042: 
                   2043:   if (matched_element->daemon)
                   2044:     return CMD_SUCCESS_DAEMON;
                   2045: 
                   2046:   /* Execute matched command. */
                   2047:   return (*matched_element->func) (matched_element, vty, argc, argv);
                   2048: }
                   2049: 
                   2050: int
                   2051: cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
                   2052:                     int vtysh) {
                   2053:   int ret, saved_ret, tried = 0;
                   2054:   enum node_type onode, try_node;
                   2055: 
                   2056:   onode = try_node = vty->node;
                   2057: 
                   2058:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
                   2059:     {
                   2060:       vector shifted_vline;
                   2061:       unsigned int index;
                   2062: 
                   2063:       vty->node = ENABLE_NODE;
                   2064:       /* We can try it on enable node, cos' the vty is authenticated */
                   2065: 
                   2066:       shifted_vline = vector_init (vector_count(vline));
                   2067:       /* use memcpy? */
                   2068:       for (index = 1; index < vector_active (vline); index++) 
                   2069:        {
                   2070:          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
                   2071:        }
                   2072: 
                   2073:       ret = cmd_execute_command_real (shifted_vline, vty, cmd);
                   2074: 
                   2075:       vector_free(shifted_vline);
                   2076:       vty->node = onode;
                   2077:       return ret;
                   2078:   }
                   2079: 
                   2080: 
                   2081:   saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
                   2082: 
                   2083:   if (vtysh)
                   2084:     return saved_ret;
                   2085: 
                   2086:   /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
                   2087:   while ( ret != CMD_SUCCESS && ret != CMD_WARNING 
                   2088:          && vty->node > CONFIG_NODE )
                   2089:     {
                   2090:       try_node = node_parent(try_node);
                   2091:       vty->node = try_node;
                   2092:       ret = cmd_execute_command_real (vline, vty, cmd);
                   2093:       tried = 1;
                   2094:       if (ret == CMD_SUCCESS || ret == CMD_WARNING)
                   2095:        {
                   2096:          /* succesfull command, leave the node as is */
                   2097:          return ret;
                   2098:        }
                   2099:     }
                   2100:   /* no command succeeded, reset the vty to the original node and
                   2101:      return the error for this node */
                   2102:   if ( tried )
                   2103:     vty->node = onode;
                   2104:   return saved_ret;
                   2105: }
                   2106: 
                   2107: /* Execute command by argument readline. */
                   2108: int
                   2109: cmd_execute_command_strict (vector vline, struct vty *vty,
                   2110:                            struct cmd_element **cmd)
                   2111: {
                   2112:   unsigned int i;
                   2113:   unsigned int index;
                   2114:   vector cmd_vector;
                   2115:   struct cmd_element *cmd_element;
                   2116:   struct cmd_element *matched_element;
                   2117:   unsigned int matched_count, incomplete_count;
                   2118:   int argc;
                   2119:   const char *argv[CMD_ARGC_MAX];
                   2120:   int varflag;
                   2121:   enum match_type match = 0;
                   2122:   char *command;
                   2123: 
                   2124:   /* Make copy of command element */
                   2125:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
                   2126: 
                   2127:   for (index = 0; index < vector_active (vline); index++)
                   2128:     if ((command = vector_slot (vline, index)))
                   2129:       {
                   2130:        int ret;
                   2131:        
                   2132:        match = cmd_filter_by_string (vector_slot (vline, index),
                   2133:                                      cmd_vector, index);
                   2134: 
                   2135:        /* If command meets '.VARARG' then finish matching. */
                   2136:        if (match == vararg_match)
                   2137:          break;
                   2138:         
                   2139:        ret = is_cmd_ambiguous (command, cmd_vector, index, match);
                   2140:        if (ret == 1)
                   2141:          {
                   2142:            vector_free (cmd_vector);
                   2143:            return CMD_ERR_AMBIGUOUS;
                   2144:          }
                   2145:        if (ret == 2)
                   2146:          {
                   2147:            vector_free (cmd_vector);
                   2148:            return CMD_ERR_NO_MATCH;
                   2149:          }
                   2150:       }
                   2151: 
                   2152:   /* Check matched count. */
                   2153:   matched_element = NULL;
                   2154:   matched_count = 0;
                   2155:   incomplete_count = 0;
                   2156:   for (i = 0; i < vector_active (cmd_vector); i++)
                   2157:     if (vector_slot (cmd_vector, i) != NULL)
                   2158:       {
                   2159:        cmd_element = vector_slot (cmd_vector, i);
                   2160: 
                   2161:        if (match == vararg_match || index >= cmd_element->cmdsize)
                   2162:          {
                   2163:            matched_element = cmd_element;
                   2164:            matched_count++;
                   2165:          }
                   2166:        else
                   2167:          incomplete_count++;
                   2168:       }
                   2169: 
                   2170:   /* Finish of using cmd_vector. */
                   2171:   vector_free (cmd_vector);
                   2172: 
                   2173:   /* To execute command, matched_count must be 1. */
                   2174:   if (matched_count == 0)
                   2175:     {
                   2176:       if (incomplete_count)
                   2177:        return CMD_ERR_INCOMPLETE;
                   2178:       else
                   2179:        return CMD_ERR_NO_MATCH;
                   2180:     }
                   2181: 
                   2182:   if (matched_count > 1)
                   2183:     return CMD_ERR_AMBIGUOUS;
                   2184: 
                   2185:   /* Argument treatment */
                   2186:   varflag = 0;
                   2187:   argc = 0;
                   2188: 
                   2189:   for (i = 0; i < vector_active (vline); i++)
                   2190:     {
                   2191:       if (varflag)
                   2192:        argv[argc++] = vector_slot (vline, i);
                   2193:       else
                   2194:        {
                   2195:          vector descvec = vector_slot (matched_element->strvec, i);
                   2196: 
                   2197:          if (vector_active (descvec) == 1)
                   2198:            {
                   2199:              struct desc *desc = vector_slot (descvec, 0);
                   2200: 
                   2201:              if (CMD_VARARG (desc->cmd))
                   2202:                varflag = 1;
                   2203: 
                   2204:              if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
                   2205:                argv[argc++] = vector_slot (vline, i);
                   2206:            }
                   2207:          else
                   2208:            argv[argc++] = vector_slot (vline, i);
                   2209:        }
                   2210: 
                   2211:       if (argc >= CMD_ARGC_MAX)
                   2212:        return CMD_ERR_EXEED_ARGC_MAX;
                   2213:     }
                   2214: 
                   2215:   /* For vtysh execution. */
                   2216:   if (cmd)
                   2217:     *cmd = matched_element;
                   2218: 
                   2219:   if (matched_element->daemon)
                   2220:     return CMD_SUCCESS_DAEMON;
                   2221: 
                   2222:   /* Now execute matched command */
                   2223:   return (*matched_element->func) (matched_element, vty, argc, argv);
                   2224: }
                   2225: 
                   2226: /* Configration make from file. */
                   2227: int
                   2228: config_from_file (struct vty *vty, FILE *fp)
                   2229: {
                   2230:   int ret;
                   2231:   vector vline;
                   2232: 
                   2233:   while (fgets (vty->buf, VTY_BUFSIZ, fp))
                   2234:     {
                   2235:       vline = cmd_make_strvec (vty->buf);
                   2236: 
                   2237:       /* In case of comment line */
                   2238:       if (vline == NULL)
                   2239:        continue;
                   2240:       /* Execute configuration command : this is strict match */
                   2241:       ret = cmd_execute_command_strict (vline, vty, NULL);
                   2242: 
                   2243:       /* Try again with setting node to CONFIG_NODE */
                   2244:       while (ret != CMD_SUCCESS && ret != CMD_WARNING
                   2245:             && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
                   2246:        {
                   2247:          vty->node = node_parent(vty->node);
                   2248:          ret = cmd_execute_command_strict (vline, vty, NULL);
                   2249:        }
                   2250: 
                   2251:       cmd_free_strvec (vline);
                   2252: 
                   2253:       if (ret != CMD_SUCCESS && ret != CMD_WARNING
                   2254:          && ret != CMD_ERR_NOTHING_TODO)
                   2255:        return ret;
                   2256:     }
                   2257:   return CMD_SUCCESS;
                   2258: }
                   2259: 
                   2260: /* Configration from terminal */
                   2261: DEFUN (config_terminal,
                   2262:        config_terminal_cmd,
                   2263:        "configure terminal",
                   2264:        "Configuration from vty interface\n"
                   2265:        "Configuration terminal\n")
                   2266: {
                   2267:   if (vty_config_lock (vty))
                   2268:     vty->node = CONFIG_NODE;
                   2269:   else
                   2270:     {
                   2271:       vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
                   2272:       return CMD_WARNING;
                   2273:     }
                   2274:   return CMD_SUCCESS;
                   2275: }
                   2276: 
                   2277: /* Enable command */
                   2278: DEFUN (enable, 
                   2279:        config_enable_cmd,
                   2280:        "enable",
                   2281:        "Turn on privileged mode command\n")
                   2282: {
                   2283:   /* If enable password is NULL, change to ENABLE_NODE */
                   2284:   if ((host.enable == NULL && host.enable_encrypt == NULL) ||
                   2285:       vty->type == VTY_SHELL_SERV)
                   2286:     vty->node = ENABLE_NODE;
                   2287:   else
                   2288:     vty->node = AUTH_ENABLE_NODE;
                   2289: 
                   2290:   return CMD_SUCCESS;
                   2291: }
                   2292: 
                   2293: /* Disable command */
                   2294: DEFUN (disable, 
                   2295:        config_disable_cmd,
                   2296:        "disable",
                   2297:        "Turn off privileged mode command\n")
                   2298: {
                   2299:   if (vty->node == ENABLE_NODE)
                   2300:     vty->node = VIEW_NODE;
                   2301:   return CMD_SUCCESS;
                   2302: }
                   2303: 
                   2304: /* Down vty node level. */
                   2305: DEFUN (config_exit,
                   2306:        config_exit_cmd,
                   2307:        "exit",
                   2308:        "Exit current mode and down to previous mode\n")
                   2309: {
                   2310:   switch (vty->node)
                   2311:     {
                   2312:     case VIEW_NODE:
                   2313:     case ENABLE_NODE:
                   2314:     case RESTRICTED_NODE:
                   2315:       if (vty_shell (vty))
                   2316:        exit (0);
                   2317:       else
                   2318:        vty->status = VTY_CLOSE;
                   2319:       break;
                   2320:     case CONFIG_NODE:
                   2321:       vty->node = ENABLE_NODE;
                   2322:       vty_config_unlock (vty);
                   2323:       break;
                   2324:     case INTERFACE_NODE:
                   2325:     case ZEBRA_NODE:
                   2326:     case BGP_NODE:
                   2327:     case RIP_NODE:
                   2328:     case RIPNG_NODE:
1.1.1.2   misho    2329:     case BABEL_NODE:
1.1       misho    2330:     case OSPF_NODE:
                   2331:     case OSPF6_NODE:
                   2332:     case ISIS_NODE:
                   2333:     case KEYCHAIN_NODE:
                   2334:     case MASC_NODE:
                   2335:     case RMAP_NODE:
                   2336:     case VTY_NODE:
                   2337:       vty->node = CONFIG_NODE;
                   2338:       break;
                   2339:     case BGP_VPNV4_NODE:
                   2340:     case BGP_IPV4_NODE:
                   2341:     case BGP_IPV4M_NODE:
                   2342:     case BGP_IPV6_NODE:
                   2343:     case BGP_IPV6M_NODE:
                   2344:       vty->node = BGP_NODE;
                   2345:       break;
                   2346:     case KEYCHAIN_KEY_NODE:
                   2347:       vty->node = KEYCHAIN_NODE;
                   2348:       break;
                   2349:     default:
                   2350:       break;
                   2351:     }
                   2352:   return CMD_SUCCESS;
                   2353: }
                   2354: 
                   2355: /* quit is alias of exit. */
                   2356: ALIAS (config_exit,
                   2357:        config_quit_cmd,
                   2358:        "quit",
                   2359:        "Exit current mode and down to previous mode\n")
                   2360:        
                   2361: /* End of configuration. */
                   2362: DEFUN (config_end,
                   2363:        config_end_cmd,
                   2364:        "end",
                   2365:        "End current mode and change to enable mode.")
                   2366: {
                   2367:   switch (vty->node)
                   2368:     {
                   2369:     case VIEW_NODE:
                   2370:     case ENABLE_NODE:
                   2371:     case RESTRICTED_NODE:
                   2372:       /* Nothing to do. */
                   2373:       break;
                   2374:     case CONFIG_NODE:
                   2375:     case INTERFACE_NODE:
                   2376:     case ZEBRA_NODE:
                   2377:     case RIP_NODE:
                   2378:     case RIPNG_NODE:
1.1.1.2   misho    2379:     case BABEL_NODE:
1.1       misho    2380:     case BGP_NODE:
                   2381:     case BGP_VPNV4_NODE:
                   2382:     case BGP_IPV4_NODE:
                   2383:     case BGP_IPV4M_NODE:
                   2384:     case BGP_IPV6_NODE:
                   2385:     case BGP_IPV6M_NODE:
                   2386:     case RMAP_NODE:
                   2387:     case OSPF_NODE:
                   2388:     case OSPF6_NODE:
                   2389:     case ISIS_NODE:
                   2390:     case KEYCHAIN_NODE:
                   2391:     case KEYCHAIN_KEY_NODE:
                   2392:     case MASC_NODE:
                   2393:     case VTY_NODE:
                   2394:       vty_config_unlock (vty);
                   2395:       vty->node = ENABLE_NODE;
                   2396:       break;
                   2397:     default:
                   2398:       break;
                   2399:     }
                   2400:   return CMD_SUCCESS;
                   2401: }
                   2402: 
                   2403: /* Show version. */
                   2404: DEFUN (show_version,
                   2405:        show_version_cmd,
                   2406:        "show version",
                   2407:        SHOW_STR
                   2408:        "Displays zebra version\n")
                   2409: {
                   2410:   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
                   2411:           VTY_NEWLINE);
1.1.1.3 ! misho    2412:   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
1.1       misho    2413: 
                   2414:   return CMD_SUCCESS;
                   2415: }
                   2416: 
                   2417: /* Help display function for all node. */
                   2418: DEFUN (config_help,
                   2419:        config_help_cmd,
                   2420:        "help",
                   2421:        "Description of the interactive help system\n")
                   2422: {
                   2423:   vty_out (vty, 
                   2424:           "Quagga VTY provides advanced help feature.  When you need help,%s\
                   2425: anytime at the command line please press '?'.%s\
                   2426: %s\
                   2427: If nothing matches, the help list will be empty and you must backup%s\
                   2428:  until entering a '?' shows the available options.%s\
                   2429: Two styles of help are provided:%s\
                   2430: 1. Full help is available when you are ready to enter a%s\
                   2431: command argument (e.g. 'show ?') and describes each possible%s\
                   2432: argument.%s\
                   2433: 2. Partial help is provided when an abbreviated argument is entered%s\
                   2434:    and you want to know what arguments match the input%s\
                   2435:    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
                   2436:           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
                   2437:           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
                   2438:   return CMD_SUCCESS;
                   2439: }
                   2440: 
                   2441: /* Help display function for all node. */
                   2442: DEFUN (config_list,
                   2443:        config_list_cmd,
                   2444:        "list",
                   2445:        "Print command list\n")
                   2446: {
                   2447:   unsigned int i;
                   2448:   struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
                   2449:   struct cmd_element *cmd;
                   2450: 
                   2451:   for (i = 0; i < vector_active (cnode->cmd_vector); i++)
                   2452:     if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
                   2453:         && !(cmd->attr == CMD_ATTR_DEPRECATED
                   2454:              || cmd->attr == CMD_ATTR_HIDDEN))
                   2455:       vty_out (vty, "  %s%s", cmd->string,
                   2456:               VTY_NEWLINE);
                   2457:   return CMD_SUCCESS;
                   2458: }
                   2459: 
                   2460: /* Write current configuration into file. */
                   2461: DEFUN (config_write_file, 
                   2462:        config_write_file_cmd,
                   2463:        "write file",  
                   2464:        "Write running configuration to memory, network, or terminal\n"
                   2465:        "Write to configuration file\n")
                   2466: {
                   2467:   unsigned int i;
                   2468:   int fd;
                   2469:   struct cmd_node *node;
                   2470:   char *config_file;
                   2471:   char *config_file_tmp = NULL;
                   2472:   char *config_file_sav = NULL;
                   2473:   int ret = CMD_WARNING;
                   2474:   struct vty *file_vty;
                   2475: 
                   2476:   /* Check and see if we are operating under vtysh configuration */
                   2477:   if (host.config == NULL)
                   2478:     {
                   2479:       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
                   2480:               VTY_NEWLINE);
                   2481:       return CMD_WARNING;
                   2482:     }
                   2483: 
                   2484:   /* Get filename. */
                   2485:   config_file = host.config;
                   2486:   
                   2487:   config_file_sav =
                   2488:     XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
                   2489:   strcpy (config_file_sav, config_file);
                   2490:   strcat (config_file_sav, CONF_BACKUP_EXT);
                   2491: 
                   2492: 
                   2493:   config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
                   2494:   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
                   2495:   
                   2496:   /* Open file to configuration write. */
                   2497:   fd = mkstemp (config_file_tmp);
                   2498:   if (fd < 0)
                   2499:     {
                   2500:       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
                   2501:               VTY_NEWLINE);
                   2502:       goto finished;
                   2503:     }
                   2504:   
                   2505:   /* Make vty for configuration file. */
                   2506:   file_vty = vty_new ();
                   2507:   file_vty->fd = fd;
                   2508:   file_vty->type = VTY_FILE;
                   2509: 
                   2510:   /* Config file header print. */
                   2511:   vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
                   2512:   vty_time_print (file_vty, 1);
                   2513:   vty_out (file_vty, "!\n");
                   2514: 
                   2515:   for (i = 0; i < vector_active (cmdvec); i++)
                   2516:     if ((node = vector_slot (cmdvec, i)) && node->func)
                   2517:       {
                   2518:        if ((*node->func) (file_vty))
                   2519:          vty_out (file_vty, "!\n");
                   2520:       }
                   2521:   vty_close (file_vty);
                   2522: 
                   2523:   if (unlink (config_file_sav) != 0)
                   2524:     if (errno != ENOENT)
                   2525:       {
                   2526:        vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
                   2527:                 VTY_NEWLINE);
                   2528:         goto finished;
                   2529:       }
                   2530:   if (link (config_file, config_file_sav) != 0)
                   2531:     {
                   2532:       vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
                   2533:                VTY_NEWLINE);
                   2534:       goto finished;
                   2535:     }
                   2536:   sync ();
                   2537:   if (unlink (config_file) != 0)
                   2538:     {
                   2539:       vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
                   2540:                VTY_NEWLINE);
                   2541:       goto finished;
                   2542:     }
                   2543:   if (link (config_file_tmp, config_file) != 0)
                   2544:     {
                   2545:       vty_out (vty, "Can't save configuration file %s.%s", config_file,
                   2546:               VTY_NEWLINE);
                   2547:       goto finished;
                   2548:     }
                   2549:   sync ();
                   2550:   
                   2551:   if (chmod (config_file, CONFIGFILE_MASK) != 0)
                   2552:     {
                   2553:       vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s", 
                   2554:        config_file, safe_strerror(errno), errno, VTY_NEWLINE);
                   2555:       goto finished;
                   2556:     }
                   2557: 
                   2558:   vty_out (vty, "Configuration saved to %s%s", config_file,
                   2559:           VTY_NEWLINE);
                   2560:   ret = CMD_SUCCESS;
                   2561: 
                   2562: finished:
                   2563:   unlink (config_file_tmp);
                   2564:   XFREE (MTYPE_TMP, config_file_tmp);
                   2565:   XFREE (MTYPE_TMP, config_file_sav);
                   2566:   return ret;
                   2567: }
                   2568: 
                   2569: ALIAS (config_write_file, 
                   2570:        config_write_cmd,
                   2571:        "write",  
                   2572:        "Write running configuration to memory, network, or terminal\n")
                   2573: 
                   2574: ALIAS (config_write_file, 
                   2575:        config_write_memory_cmd,
                   2576:        "write memory",  
                   2577:        "Write running configuration to memory, network, or terminal\n"
                   2578:        "Write configuration to the file (same as write file)\n")
                   2579: 
                   2580: ALIAS (config_write_file, 
                   2581:        copy_runningconfig_startupconfig_cmd,
                   2582:        "copy running-config startup-config",  
                   2583:        "Copy configuration\n"
                   2584:        "Copy running config to... \n"
                   2585:        "Copy running config to startup config (same as write file)\n")
                   2586: 
                   2587: /* Write current configuration into the terminal. */
                   2588: DEFUN (config_write_terminal,
                   2589:        config_write_terminal_cmd,
                   2590:        "write terminal",
                   2591:        "Write running configuration to memory, network, or terminal\n"
                   2592:        "Write to terminal\n")
                   2593: {
                   2594:   unsigned int i;
                   2595:   struct cmd_node *node;
                   2596: 
                   2597:   if (vty->type == VTY_SHELL_SERV)
                   2598:     {
                   2599:       for (i = 0; i < vector_active (cmdvec); i++)
                   2600:        if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
                   2601:          {
                   2602:            if ((*node->func) (vty))
                   2603:              vty_out (vty, "!%s", VTY_NEWLINE);
                   2604:          }
                   2605:     }
                   2606:   else
                   2607:     {
                   2608:       vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
                   2609:               VTY_NEWLINE);
                   2610:       vty_out (vty, "!%s", VTY_NEWLINE);
                   2611: 
                   2612:       for (i = 0; i < vector_active (cmdvec); i++)
                   2613:        if ((node = vector_slot (cmdvec, i)) && node->func)
                   2614:          {
                   2615:            if ((*node->func) (vty))
                   2616:              vty_out (vty, "!%s", VTY_NEWLINE);
                   2617:          }
                   2618:       vty_out (vty, "end%s",VTY_NEWLINE);
                   2619:     }
                   2620:   return CMD_SUCCESS;
                   2621: }
                   2622: 
                   2623: /* Write current configuration into the terminal. */
                   2624: ALIAS (config_write_terminal,
                   2625:        show_running_config_cmd,
                   2626:        "show running-config",
                   2627:        SHOW_STR
                   2628:        "running configuration\n")
                   2629: 
                   2630: /* Write startup configuration into the terminal. */
                   2631: DEFUN (show_startup_config,
                   2632:        show_startup_config_cmd,
                   2633:        "show startup-config",
                   2634:        SHOW_STR
                   2635:        "Contentes of startup configuration\n")
                   2636: {
                   2637:   char buf[BUFSIZ];
                   2638:   FILE *confp;
                   2639: 
                   2640:   confp = fopen (host.config, "r");
                   2641:   if (confp == NULL)
                   2642:     {
                   2643:       vty_out (vty, "Can't open configuration file [%s]%s",
                   2644:               host.config, VTY_NEWLINE);
                   2645:       return CMD_WARNING;
                   2646:     }
                   2647: 
                   2648:   while (fgets (buf, BUFSIZ, confp))
                   2649:     {
                   2650:       char *cp = buf;
                   2651: 
                   2652:       while (*cp != '\r' && *cp != '\n' && *cp != '\0')
                   2653:        cp++;
                   2654:       *cp = '\0';
                   2655: 
                   2656:       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
                   2657:     }
                   2658: 
                   2659:   fclose (confp);
                   2660: 
                   2661:   return CMD_SUCCESS;
                   2662: }
                   2663: 
                   2664: /* Hostname configuration */
                   2665: DEFUN (config_hostname, 
                   2666:        hostname_cmd,
                   2667:        "hostname WORD",
                   2668:        "Set system's network name\n"
                   2669:        "This system's network name\n")
                   2670: {
                   2671:   if (!isalpha((int) *argv[0]))
                   2672:     {
                   2673:       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
                   2674:       return CMD_WARNING;
                   2675:     }
                   2676: 
                   2677:   if (host.name)
                   2678:     XFREE (MTYPE_HOST, host.name);
                   2679:     
                   2680:   host.name = XSTRDUP (MTYPE_HOST, argv[0]);
                   2681:   return CMD_SUCCESS;
                   2682: }
                   2683: 
                   2684: DEFUN (config_no_hostname, 
                   2685:        no_hostname_cmd,
                   2686:        "no hostname [HOSTNAME]",
                   2687:        NO_STR
                   2688:        "Reset system's network name\n"
                   2689:        "Host name of this router\n")
                   2690: {
                   2691:   if (host.name)
                   2692:     XFREE (MTYPE_HOST, host.name);
                   2693:   host.name = NULL;
                   2694:   return CMD_SUCCESS;
                   2695: }
                   2696: 
                   2697: /* VTY interface password set. */
                   2698: DEFUN (config_password, password_cmd,
                   2699:        "password (8|) WORD",
                   2700:        "Assign the terminal connection password\n"
                   2701:        "Specifies a HIDDEN password will follow\n"
                   2702:        "dummy string \n"
                   2703:        "The HIDDEN line password string\n")
                   2704: {
                   2705:   /* Argument check. */
                   2706:   if (argc == 0)
                   2707:     {
                   2708:       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
                   2709:       return CMD_WARNING;
                   2710:     }
                   2711: 
                   2712:   if (argc == 2)
                   2713:     {
                   2714:       if (*argv[0] == '8')
                   2715:        {
                   2716:          if (host.password)
                   2717:            XFREE (MTYPE_HOST, host.password);
                   2718:          host.password = NULL;
                   2719:          if (host.password_encrypt)
                   2720:            XFREE (MTYPE_HOST, host.password_encrypt);
                   2721:          host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
                   2722:          return CMD_SUCCESS;
                   2723:        }
                   2724:       else
                   2725:        {
                   2726:          vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
                   2727:          return CMD_WARNING;
                   2728:        }
                   2729:     }
                   2730: 
                   2731:   if (!isalnum ((int) *argv[0]))
                   2732:     {
                   2733:       vty_out (vty, 
                   2734:               "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
                   2735:       return CMD_WARNING;
                   2736:     }
                   2737: 
                   2738:   if (host.password)
                   2739:     XFREE (MTYPE_HOST, host.password);
                   2740:   host.password = NULL;
                   2741: 
                   2742:   if (host.encrypt)
                   2743:     {
                   2744:       if (host.password_encrypt)
                   2745:        XFREE (MTYPE_HOST, host.password_encrypt);
                   2746:       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
                   2747:     }
                   2748:   else
                   2749:     host.password = XSTRDUP (MTYPE_HOST, argv[0]);
                   2750: 
                   2751:   return CMD_SUCCESS;
                   2752: }
                   2753: 
                   2754: ALIAS (config_password, password_text_cmd,
                   2755:        "password LINE",
                   2756:        "Assign the terminal connection password\n"
                   2757:        "The UNENCRYPTED (cleartext) line password\n")
                   2758: 
                   2759: /* VTY enable password set. */
                   2760: DEFUN (config_enable_password, enable_password_cmd,
                   2761:        "enable password (8|) WORD",
                   2762:        "Modify enable password parameters\n"
                   2763:        "Assign the privileged level password\n"
                   2764:        "Specifies a HIDDEN password will follow\n"
                   2765:        "dummy string \n"
                   2766:        "The HIDDEN 'enable' password string\n")
                   2767: {
                   2768:   /* Argument check. */
                   2769:   if (argc == 0)
                   2770:     {
                   2771:       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
                   2772:       return CMD_WARNING;
                   2773:     }
                   2774: 
                   2775:   /* Crypt type is specified. */
                   2776:   if (argc == 2)
                   2777:     {
                   2778:       if (*argv[0] == '8')
                   2779:        {
                   2780:          if (host.enable)
                   2781:            XFREE (MTYPE_HOST, host.enable);
                   2782:          host.enable = NULL;
                   2783: 
                   2784:          if (host.enable_encrypt)
                   2785:            XFREE (MTYPE_HOST, host.enable_encrypt);
                   2786:          host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
                   2787: 
                   2788:          return CMD_SUCCESS;
                   2789:        }
                   2790:       else
                   2791:        {
                   2792:          vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
                   2793:          return CMD_WARNING;
                   2794:        }
                   2795:     }
                   2796: 
                   2797:   if (!isalnum ((int) *argv[0]))
                   2798:     {
                   2799:       vty_out (vty, 
                   2800:               "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
                   2801:       return CMD_WARNING;
                   2802:     }
                   2803: 
                   2804:   if (host.enable)
                   2805:     XFREE (MTYPE_HOST, host.enable);
                   2806:   host.enable = NULL;
                   2807: 
                   2808:   /* Plain password input. */
                   2809:   if (host.encrypt)
                   2810:     {
                   2811:       if (host.enable_encrypt)
                   2812:        XFREE (MTYPE_HOST, host.enable_encrypt);
                   2813:       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
                   2814:     }
                   2815:   else
                   2816:     host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
                   2817: 
                   2818:   return CMD_SUCCESS;
                   2819: }
                   2820: 
                   2821: ALIAS (config_enable_password,
                   2822:        enable_password_text_cmd,
                   2823:        "enable password LINE",
                   2824:        "Modify enable password parameters\n"
                   2825:        "Assign the privileged level password\n"
                   2826:        "The UNENCRYPTED (cleartext) 'enable' password\n")
                   2827: 
                   2828: /* VTY enable password delete. */
                   2829: DEFUN (no_config_enable_password, no_enable_password_cmd,
                   2830:        "no enable password",
                   2831:        NO_STR
                   2832:        "Modify enable password parameters\n"
                   2833:        "Assign the privileged level password\n")
                   2834: {
                   2835:   if (host.enable)
                   2836:     XFREE (MTYPE_HOST, host.enable);
                   2837:   host.enable = NULL;
                   2838: 
                   2839:   if (host.enable_encrypt)
                   2840:     XFREE (MTYPE_HOST, host.enable_encrypt);
                   2841:   host.enable_encrypt = NULL;
                   2842: 
                   2843:   return CMD_SUCCESS;
                   2844: }
                   2845:        
                   2846: DEFUN (service_password_encrypt,
                   2847:        service_password_encrypt_cmd,
                   2848:        "service password-encryption",
                   2849:        "Set up miscellaneous service\n"
                   2850:        "Enable encrypted passwords\n")
                   2851: {
                   2852:   if (host.encrypt)
                   2853:     return CMD_SUCCESS;
                   2854: 
                   2855:   host.encrypt = 1;
                   2856: 
                   2857:   if (host.password)
                   2858:     {
                   2859:       if (host.password_encrypt)
                   2860:        XFREE (MTYPE_HOST, host.password_encrypt);
                   2861:       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
                   2862:     }
                   2863:   if (host.enable)
                   2864:     {
                   2865:       if (host.enable_encrypt)
                   2866:        XFREE (MTYPE_HOST, host.enable_encrypt);
                   2867:       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
                   2868:     }
                   2869: 
                   2870:   return CMD_SUCCESS;
                   2871: }
                   2872: 
                   2873: DEFUN (no_service_password_encrypt,
                   2874:        no_service_password_encrypt_cmd,
                   2875:        "no service password-encryption",
                   2876:        NO_STR
                   2877:        "Set up miscellaneous service\n"
                   2878:        "Enable encrypted passwords\n")
                   2879: {
                   2880:   if (! host.encrypt)
                   2881:     return CMD_SUCCESS;
                   2882: 
                   2883:   host.encrypt = 0;
                   2884: 
                   2885:   if (host.password_encrypt)
                   2886:     XFREE (MTYPE_HOST, host.password_encrypt);
                   2887:   host.password_encrypt = NULL;
                   2888: 
                   2889:   if (host.enable_encrypt)
                   2890:     XFREE (MTYPE_HOST, host.enable_encrypt);
                   2891:   host.enable_encrypt = NULL;
                   2892: 
                   2893:   return CMD_SUCCESS;
                   2894: }
                   2895: 
                   2896: DEFUN (config_terminal_length, config_terminal_length_cmd,
                   2897:        "terminal length <0-512>",
                   2898:        "Set terminal line parameters\n"
                   2899:        "Set number of lines on a screen\n"
                   2900:        "Number of lines on screen (0 for no pausing)\n")
                   2901: {
                   2902:   int lines;
                   2903:   char *endptr = NULL;
                   2904: 
                   2905:   lines = strtol (argv[0], &endptr, 10);
                   2906:   if (lines < 0 || lines > 512 || *endptr != '\0')
                   2907:     {
                   2908:       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
                   2909:       return CMD_WARNING;
                   2910:     }
                   2911:   vty->lines = lines;
                   2912: 
                   2913:   return CMD_SUCCESS;
                   2914: }
                   2915: 
                   2916: DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
                   2917:        "terminal no length",
                   2918:        "Set terminal line parameters\n"
                   2919:        NO_STR
                   2920:        "Set number of lines on a screen\n")
                   2921: {
                   2922:   vty->lines = -1;
                   2923:   return CMD_SUCCESS;
                   2924: }
                   2925: 
                   2926: DEFUN (service_terminal_length, service_terminal_length_cmd,
                   2927:        "service terminal-length <0-512>",
                   2928:        "Set up miscellaneous service\n"
                   2929:        "System wide terminal length configuration\n"
                   2930:        "Number of lines of VTY (0 means no line control)\n")
                   2931: {
                   2932:   int lines;
                   2933:   char *endptr = NULL;
                   2934: 
                   2935:   lines = strtol (argv[0], &endptr, 10);
                   2936:   if (lines < 0 || lines > 512 || *endptr != '\0')
                   2937:     {
                   2938:       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
                   2939:       return CMD_WARNING;
                   2940:     }
                   2941:   host.lines = lines;
                   2942: 
                   2943:   return CMD_SUCCESS;
                   2944: }
                   2945: 
                   2946: DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
                   2947:        "no service terminal-length [<0-512>]",
                   2948:        NO_STR
                   2949:        "Set up miscellaneous service\n"
                   2950:        "System wide terminal length configuration\n"
                   2951:        "Number of lines of VTY (0 means no line control)\n")
                   2952: {
                   2953:   host.lines = -1;
                   2954:   return CMD_SUCCESS;
                   2955: }
                   2956: 
                   2957: DEFUN_HIDDEN (do_echo,
                   2958:              echo_cmd,
                   2959:              "echo .MESSAGE",
                   2960:              "Echo a message back to the vty\n"
                   2961:              "The message to echo\n")
                   2962: {
                   2963:   char *message;
                   2964: 
                   2965:   vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
                   2966:           VTY_NEWLINE);
                   2967:   if (message)
                   2968:     XFREE(MTYPE_TMP, message);
                   2969:   return CMD_SUCCESS;
                   2970: }
                   2971: 
                   2972: DEFUN (config_logmsg,
                   2973:        config_logmsg_cmd,
                   2974:        "logmsg "LOG_LEVELS" .MESSAGE",
                   2975:        "Send a message to enabled logging destinations\n"
                   2976:        LOG_LEVEL_DESC
                   2977:        "The message to send\n")
                   2978: {
                   2979:   int level;
                   2980:   char *message;
                   2981: 
                   2982:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
                   2983:     return CMD_ERR_NO_MATCH;
                   2984: 
                   2985:   zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
                   2986:   if (message)
                   2987:     XFREE(MTYPE_TMP, message);
                   2988:   return CMD_SUCCESS;
                   2989: }
                   2990: 
                   2991: DEFUN (show_logging,
                   2992:        show_logging_cmd,
                   2993:        "show logging",
                   2994:        SHOW_STR
                   2995:        "Show current logging configuration\n")
                   2996: {
                   2997:   struct zlog *zl = zlog_default;
                   2998: 
                   2999:   vty_out (vty, "Syslog logging: ");
                   3000:   if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
                   3001:     vty_out (vty, "disabled");
                   3002:   else
                   3003:     vty_out (vty, "level %s, facility %s, ident %s",
                   3004:             zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
                   3005:             facility_name(zl->facility), zl->ident);
                   3006:   vty_out (vty, "%s", VTY_NEWLINE);
                   3007: 
                   3008:   vty_out (vty, "Stdout logging: ");
                   3009:   if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
                   3010:     vty_out (vty, "disabled");
                   3011:   else
                   3012:     vty_out (vty, "level %s",
                   3013:             zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
                   3014:   vty_out (vty, "%s", VTY_NEWLINE);
                   3015: 
                   3016:   vty_out (vty, "Monitor logging: ");
                   3017:   if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
                   3018:     vty_out (vty, "disabled");
                   3019:   else
                   3020:     vty_out (vty, "level %s",
                   3021:             zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
                   3022:   vty_out (vty, "%s", VTY_NEWLINE);
                   3023: 
                   3024:   vty_out (vty, "File logging: ");
                   3025:   if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
                   3026:       !zl->fp)
                   3027:     vty_out (vty, "disabled");
                   3028:   else
                   3029:     vty_out (vty, "level %s, filename %s",
                   3030:             zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
                   3031:             zl->filename);
                   3032:   vty_out (vty, "%s", VTY_NEWLINE);
                   3033: 
                   3034:   vty_out (vty, "Protocol name: %s%s",
                   3035:           zlog_proto_names[zl->protocol], VTY_NEWLINE);
                   3036:   vty_out (vty, "Record priority: %s%s",
                   3037:           (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
                   3038:   vty_out (vty, "Timestamp precision: %d%s",
                   3039:           zl->timestamp_precision, VTY_NEWLINE);
                   3040: 
                   3041:   return CMD_SUCCESS;
                   3042: }
                   3043: 
                   3044: DEFUN (config_log_stdout,
                   3045:        config_log_stdout_cmd,
                   3046:        "log stdout",
                   3047:        "Logging control\n"
                   3048:        "Set stdout logging level\n")
                   3049: {
                   3050:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
                   3051:   return CMD_SUCCESS;
                   3052: }
                   3053: 
                   3054: DEFUN (config_log_stdout_level,
                   3055:        config_log_stdout_level_cmd,
                   3056:        "log stdout "LOG_LEVELS,
                   3057:        "Logging control\n"
                   3058:        "Set stdout logging level\n"
                   3059:        LOG_LEVEL_DESC)
                   3060: {
                   3061:   int level;
                   3062: 
                   3063:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
                   3064:     return CMD_ERR_NO_MATCH;
                   3065:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
                   3066:   return CMD_SUCCESS;
                   3067: }
                   3068: 
                   3069: DEFUN (no_config_log_stdout,
                   3070:        no_config_log_stdout_cmd,
                   3071:        "no log stdout [LEVEL]",
                   3072:        NO_STR
                   3073:        "Logging control\n"
                   3074:        "Cancel logging to stdout\n"
                   3075:        "Logging level\n")
                   3076: {
                   3077:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
                   3078:   return CMD_SUCCESS;
                   3079: }
                   3080: 
                   3081: DEFUN (config_log_monitor,
                   3082:        config_log_monitor_cmd,
                   3083:        "log monitor",
                   3084:        "Logging control\n"
                   3085:        "Set terminal line (monitor) logging level\n")
                   3086: {
                   3087:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
                   3088:   return CMD_SUCCESS;
                   3089: }
                   3090: 
                   3091: DEFUN (config_log_monitor_level,
                   3092:        config_log_monitor_level_cmd,
                   3093:        "log monitor "LOG_LEVELS,
                   3094:        "Logging control\n"
                   3095:        "Set terminal line (monitor) logging level\n"
                   3096:        LOG_LEVEL_DESC)
                   3097: {
                   3098:   int level;
                   3099: 
                   3100:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
                   3101:     return CMD_ERR_NO_MATCH;
                   3102:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
                   3103:   return CMD_SUCCESS;
                   3104: }
                   3105: 
                   3106: DEFUN (no_config_log_monitor,
                   3107:        no_config_log_monitor_cmd,
                   3108:        "no log monitor [LEVEL]",
                   3109:        NO_STR
                   3110:        "Logging control\n"
                   3111:        "Disable terminal line (monitor) logging\n"
                   3112:        "Logging level\n")
                   3113: {
                   3114:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
                   3115:   return CMD_SUCCESS;
                   3116: }
                   3117: 
                   3118: static int
                   3119: set_log_file(struct vty *vty, const char *fname, int loglevel)
                   3120: {
                   3121:   int ret;
                   3122:   char *p = NULL;
                   3123:   const char *fullpath;
                   3124:   
                   3125:   /* Path detection. */
                   3126:   if (! IS_DIRECTORY_SEP (*fname))
                   3127:     {
                   3128:       char cwd[MAXPATHLEN+1];
                   3129:       cwd[MAXPATHLEN] = '\0';
                   3130:       
                   3131:       if (getcwd (cwd, MAXPATHLEN) == NULL)
                   3132:         {
                   3133:           zlog_err ("config_log_file: Unable to alloc mem!");
                   3134:           return CMD_WARNING;
                   3135:         }
                   3136:       
                   3137:       if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
                   3138:           == NULL)
                   3139:         {
                   3140:           zlog_err ("config_log_file: Unable to alloc mem!");
                   3141:           return CMD_WARNING;
                   3142:         }
                   3143:       sprintf (p, "%s/%s", cwd, fname);
                   3144:       fullpath = p;
                   3145:     }
                   3146:   else
                   3147:     fullpath = fname;
                   3148: 
                   3149:   ret = zlog_set_file (NULL, fullpath, loglevel);
                   3150: 
                   3151:   if (p)
                   3152:     XFREE (MTYPE_TMP, p);
                   3153: 
                   3154:   if (!ret)
                   3155:     {
                   3156:       vty_out (vty, "can't open logfile %s\n", fname);
                   3157:       return CMD_WARNING;
                   3158:     }
                   3159: 
                   3160:   if (host.logfile)
                   3161:     XFREE (MTYPE_HOST, host.logfile);
                   3162: 
                   3163:   host.logfile = XSTRDUP (MTYPE_HOST, fname);
                   3164: 
                   3165:   return CMD_SUCCESS;
                   3166: }
                   3167: 
                   3168: DEFUN (config_log_file,
                   3169:        config_log_file_cmd,
                   3170:        "log file FILENAME",
                   3171:        "Logging control\n"
                   3172:        "Logging to file\n"
                   3173:        "Logging filename\n")
                   3174: {
                   3175:   return set_log_file(vty, argv[0], zlog_default->default_lvl);
                   3176: }
                   3177: 
                   3178: DEFUN (config_log_file_level,
                   3179:        config_log_file_level_cmd,
                   3180:        "log file FILENAME "LOG_LEVELS,
                   3181:        "Logging control\n"
                   3182:        "Logging to file\n"
                   3183:        "Logging filename\n"
                   3184:        LOG_LEVEL_DESC)
                   3185: {
                   3186:   int level;
                   3187: 
                   3188:   if ((level = level_match(argv[1])) == ZLOG_DISABLED)
                   3189:     return CMD_ERR_NO_MATCH;
                   3190:   return set_log_file(vty, argv[0], level);
                   3191: }
                   3192: 
                   3193: DEFUN (no_config_log_file,
                   3194:        no_config_log_file_cmd,
                   3195:        "no log file [FILENAME]",
                   3196:        NO_STR
                   3197:        "Logging control\n"
                   3198:        "Cancel logging to file\n"
                   3199:        "Logging file name\n")
                   3200: {
                   3201:   zlog_reset_file (NULL);
                   3202: 
                   3203:   if (host.logfile)
                   3204:     XFREE (MTYPE_HOST, host.logfile);
                   3205: 
                   3206:   host.logfile = NULL;
                   3207: 
                   3208:   return CMD_SUCCESS;
                   3209: }
                   3210: 
                   3211: ALIAS (no_config_log_file,
                   3212:        no_config_log_file_level_cmd,
                   3213:        "no log file FILENAME LEVEL",
                   3214:        NO_STR
                   3215:        "Logging control\n"
                   3216:        "Cancel logging to file\n"
                   3217:        "Logging file name\n"
                   3218:        "Logging level\n")
                   3219: 
                   3220: DEFUN (config_log_syslog,
                   3221:        config_log_syslog_cmd,
                   3222:        "log syslog",
                   3223:        "Logging control\n"
                   3224:        "Set syslog logging level\n")
                   3225: {
                   3226:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
                   3227:   return CMD_SUCCESS;
                   3228: }
                   3229: 
                   3230: DEFUN (config_log_syslog_level,
                   3231:        config_log_syslog_level_cmd,
                   3232:        "log syslog "LOG_LEVELS,
                   3233:        "Logging control\n"
                   3234:        "Set syslog logging level\n"
                   3235:        LOG_LEVEL_DESC)
                   3236: {
                   3237:   int level;
                   3238: 
                   3239:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
                   3240:     return CMD_ERR_NO_MATCH;
                   3241:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
                   3242:   return CMD_SUCCESS;
                   3243: }
                   3244: 
                   3245: DEFUN_DEPRECATED (config_log_syslog_facility,
                   3246:                  config_log_syslog_facility_cmd,
                   3247:                  "log syslog facility "LOG_FACILITIES,
                   3248:                  "Logging control\n"
                   3249:                  "Logging goes to syslog\n"
                   3250:                  "(Deprecated) Facility parameter for syslog messages\n"
                   3251:                  LOG_FACILITY_DESC)
                   3252: {
                   3253:   int facility;
                   3254: 
                   3255:   if ((facility = facility_match(argv[0])) < 0)
                   3256:     return CMD_ERR_NO_MATCH;
                   3257: 
                   3258:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
                   3259:   zlog_default->facility = facility;
                   3260:   return CMD_SUCCESS;
                   3261: }
                   3262: 
                   3263: DEFUN (no_config_log_syslog,
                   3264:        no_config_log_syslog_cmd,
                   3265:        "no log syslog [LEVEL]",
                   3266:        NO_STR
                   3267:        "Logging control\n"
                   3268:        "Cancel logging to syslog\n"
                   3269:        "Logging level\n")
                   3270: {
                   3271:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
                   3272:   return CMD_SUCCESS;
                   3273: }
                   3274: 
                   3275: ALIAS (no_config_log_syslog,
                   3276:        no_config_log_syslog_facility_cmd,
                   3277:        "no log syslog facility "LOG_FACILITIES,
                   3278:        NO_STR
                   3279:        "Logging control\n"
                   3280:        "Logging goes to syslog\n"
                   3281:        "Facility parameter for syslog messages\n"
                   3282:        LOG_FACILITY_DESC)
                   3283: 
                   3284: DEFUN (config_log_facility,
                   3285:        config_log_facility_cmd,
                   3286:        "log facility "LOG_FACILITIES,
                   3287:        "Logging control\n"
                   3288:        "Facility parameter for syslog messages\n"
                   3289:        LOG_FACILITY_DESC)
                   3290: {
                   3291:   int facility;
                   3292: 
                   3293:   if ((facility = facility_match(argv[0])) < 0)
                   3294:     return CMD_ERR_NO_MATCH;
                   3295:   zlog_default->facility = facility;
                   3296:   return CMD_SUCCESS;
                   3297: }
                   3298: 
                   3299: DEFUN (no_config_log_facility,
                   3300:        no_config_log_facility_cmd,
                   3301:        "no log facility [FACILITY]",
                   3302:        NO_STR
                   3303:        "Logging control\n"
                   3304:        "Reset syslog facility to default (daemon)\n"
                   3305:        "Syslog facility\n")
                   3306: {
                   3307:   zlog_default->facility = LOG_DAEMON;
                   3308:   return CMD_SUCCESS;
                   3309: }
                   3310: 
                   3311: DEFUN_DEPRECATED (config_log_trap,
                   3312:                  config_log_trap_cmd,
                   3313:                  "log trap "LOG_LEVELS,
                   3314:                  "Logging control\n"
                   3315:                  "(Deprecated) Set logging level and default for all destinations\n"
                   3316:                  LOG_LEVEL_DESC)
                   3317: {
                   3318:   int new_level ;
                   3319:   int i;
                   3320:   
                   3321:   if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
                   3322:     return CMD_ERR_NO_MATCH;
                   3323: 
                   3324:   zlog_default->default_lvl = new_level;
                   3325:   for (i = 0; i < ZLOG_NUM_DESTS; i++)
                   3326:     if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
                   3327:       zlog_default->maxlvl[i] = new_level;
                   3328:   return CMD_SUCCESS;
                   3329: }
                   3330: 
                   3331: DEFUN_DEPRECATED (no_config_log_trap,
                   3332:                  no_config_log_trap_cmd,
                   3333:                  "no log trap [LEVEL]",
                   3334:                  NO_STR
                   3335:                  "Logging control\n"
                   3336:                  "Permit all logging information\n"
                   3337:                  "Logging level\n")
                   3338: {
                   3339:   zlog_default->default_lvl = LOG_DEBUG;
                   3340:   return CMD_SUCCESS;
                   3341: }
                   3342: 
                   3343: DEFUN (config_log_record_priority,
                   3344:        config_log_record_priority_cmd,
                   3345:        "log record-priority",
                   3346:        "Logging control\n"
                   3347:        "Log the priority of the message within the message\n")
                   3348: {
                   3349:   zlog_default->record_priority = 1 ;
                   3350:   return CMD_SUCCESS;
                   3351: }
                   3352: 
                   3353: DEFUN (no_config_log_record_priority,
                   3354:        no_config_log_record_priority_cmd,
                   3355:        "no log record-priority",
                   3356:        NO_STR
                   3357:        "Logging control\n"
                   3358:        "Do not log the priority of the message within the message\n")
                   3359: {
                   3360:   zlog_default->record_priority = 0 ;
                   3361:   return CMD_SUCCESS;
                   3362: }
                   3363: 
                   3364: DEFUN (config_log_timestamp_precision,
                   3365:        config_log_timestamp_precision_cmd,
                   3366:        "log timestamp precision <0-6>",
                   3367:        "Logging control\n"
                   3368:        "Timestamp configuration\n"
                   3369:        "Set the timestamp precision\n"
                   3370:        "Number of subsecond digits\n")
                   3371: {
                   3372:   if (argc != 1)
                   3373:     {
                   3374:       vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
                   3375:       return CMD_WARNING;
                   3376:     }
                   3377: 
                   3378:   VTY_GET_INTEGER_RANGE("Timestamp Precision",
                   3379:                        zlog_default->timestamp_precision, argv[0], 0, 6);
                   3380:   return CMD_SUCCESS;
                   3381: }
                   3382: 
                   3383: DEFUN (no_config_log_timestamp_precision,
                   3384:        no_config_log_timestamp_precision_cmd,
                   3385:        "no log timestamp precision",
                   3386:        NO_STR
                   3387:        "Logging control\n"
                   3388:        "Timestamp configuration\n"
                   3389:        "Reset the timestamp precision to the default value of 0\n")
                   3390: {
                   3391:   zlog_default->timestamp_precision = 0 ;
                   3392:   return CMD_SUCCESS;
                   3393: }
                   3394: 
                   3395: DEFUN (banner_motd_file,
                   3396:        banner_motd_file_cmd,
                   3397:        "banner motd file [FILE]",
                   3398:        "Set banner\n"
                   3399:        "Banner for motd\n"
                   3400:        "Banner from a file\n"
                   3401:        "Filename\n")
                   3402: {
                   3403:   if (host.motdfile)
                   3404:     XFREE (MTYPE_HOST, host.motdfile);
                   3405:   host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
                   3406: 
                   3407:   return CMD_SUCCESS;
                   3408: }
                   3409: 
                   3410: DEFUN (banner_motd_default,
                   3411:        banner_motd_default_cmd,
                   3412:        "banner motd default",
                   3413:        "Set banner string\n"
                   3414:        "Strings for motd\n"
                   3415:        "Default string\n")
                   3416: {
                   3417:   host.motd = default_motd;
                   3418:   return CMD_SUCCESS;
                   3419: }
                   3420: 
                   3421: DEFUN (no_banner_motd,
                   3422:        no_banner_motd_cmd,
                   3423:        "no banner motd",
                   3424:        NO_STR
                   3425:        "Set banner string\n"
                   3426:        "Strings for motd\n")
                   3427: {
                   3428:   host.motd = NULL;
                   3429:   if (host.motdfile) 
                   3430:     XFREE (MTYPE_HOST, host.motdfile);
                   3431:   host.motdfile = NULL;
                   3432:   return CMD_SUCCESS;
                   3433: }
                   3434: 
                   3435: /* Set config filename.  Called from vty.c */
                   3436: void
                   3437: host_config_set (char *filename)
                   3438: {
                   3439:   if (host.config)
                   3440:     XFREE (MTYPE_HOST, host.config);
                   3441:   host.config = XSTRDUP (MTYPE_HOST, filename);
                   3442: }
                   3443: 
                   3444: void
                   3445: install_default (enum node_type node)
                   3446: {
                   3447:   install_element (node, &config_exit_cmd);
                   3448:   install_element (node, &config_quit_cmd);
                   3449:   install_element (node, &config_end_cmd);
                   3450:   install_element (node, &config_help_cmd);
                   3451:   install_element (node, &config_list_cmd);
                   3452: 
                   3453:   install_element (node, &config_write_terminal_cmd);
                   3454:   install_element (node, &config_write_file_cmd);
                   3455:   install_element (node, &config_write_memory_cmd);
                   3456:   install_element (node, &config_write_cmd);
                   3457:   install_element (node, &show_running_config_cmd);
                   3458: }
                   3459: 
                   3460: /* Initialize command interface. Install basic nodes and commands. */
                   3461: void
                   3462: cmd_init (int terminal)
                   3463: {
                   3464:   command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
                   3465:   desc_cr.cmd = command_cr;
                   3466:   desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
                   3467: 
                   3468:   /* Allocate initial top vector of commands. */
                   3469:   cmdvec = vector_init (VECTOR_MIN_SIZE);
                   3470: 
                   3471:   /* Default host value settings. */
                   3472:   host.name = NULL;
                   3473:   host.password = NULL;
                   3474:   host.enable = NULL;
                   3475:   host.logfile = NULL;
                   3476:   host.config = NULL;
                   3477:   host.lines = -1;
                   3478:   host.motd = default_motd;
                   3479:   host.motdfile = NULL;
                   3480: 
                   3481:   /* Install top nodes. */
                   3482:   install_node (&view_node, NULL);
                   3483:   install_node (&enable_node, NULL);
                   3484:   install_node (&auth_node, NULL);
                   3485:   install_node (&auth_enable_node, NULL);
                   3486:   install_node (&restricted_node, NULL);
                   3487:   install_node (&config_node, config_write_host);
                   3488: 
                   3489:   /* Each node's basic commands. */
                   3490:   install_element (VIEW_NODE, &show_version_cmd);
                   3491:   if (terminal)
                   3492:     {
                   3493:       install_element (VIEW_NODE, &config_list_cmd);
                   3494:       install_element (VIEW_NODE, &config_exit_cmd);
                   3495:       install_element (VIEW_NODE, &config_quit_cmd);
                   3496:       install_element (VIEW_NODE, &config_help_cmd);
                   3497:       install_element (VIEW_NODE, &config_enable_cmd);
                   3498:       install_element (VIEW_NODE, &config_terminal_length_cmd);
                   3499:       install_element (VIEW_NODE, &config_terminal_no_length_cmd);
                   3500:       install_element (VIEW_NODE, &show_logging_cmd);
                   3501:       install_element (VIEW_NODE, &echo_cmd);
                   3502: 
                   3503:       install_element (RESTRICTED_NODE, &config_list_cmd);
                   3504:       install_element (RESTRICTED_NODE, &config_exit_cmd);
                   3505:       install_element (RESTRICTED_NODE, &config_quit_cmd);
                   3506:       install_element (RESTRICTED_NODE, &config_help_cmd);
                   3507:       install_element (RESTRICTED_NODE, &config_enable_cmd);
                   3508:       install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
                   3509:       install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
                   3510:       install_element (RESTRICTED_NODE, &echo_cmd);
                   3511:     }
                   3512: 
                   3513:   if (terminal)
                   3514:     {
                   3515:       install_default (ENABLE_NODE);
                   3516:       install_element (ENABLE_NODE, &config_disable_cmd);
                   3517:       install_element (ENABLE_NODE, &config_terminal_cmd);
                   3518:       install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
                   3519:     }
                   3520:   install_element (ENABLE_NODE, &show_startup_config_cmd);
                   3521:   install_element (ENABLE_NODE, &show_version_cmd);
                   3522: 
                   3523:   if (terminal)
                   3524:     {
                   3525:       install_element (ENABLE_NODE, &config_terminal_length_cmd);
                   3526:       install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
                   3527:       install_element (ENABLE_NODE, &show_logging_cmd);
                   3528:       install_element (ENABLE_NODE, &echo_cmd);
                   3529:       install_element (ENABLE_NODE, &config_logmsg_cmd);
                   3530: 
                   3531:       install_default (CONFIG_NODE);
                   3532:     }
                   3533:   
                   3534:   install_element (CONFIG_NODE, &hostname_cmd);
                   3535:   install_element (CONFIG_NODE, &no_hostname_cmd);
                   3536: 
                   3537:   if (terminal)
                   3538:     {
                   3539:       install_element (CONFIG_NODE, &password_cmd);
                   3540:       install_element (CONFIG_NODE, &password_text_cmd);
                   3541:       install_element (CONFIG_NODE, &enable_password_cmd);
                   3542:       install_element (CONFIG_NODE, &enable_password_text_cmd);
                   3543:       install_element (CONFIG_NODE, &no_enable_password_cmd);
                   3544: 
                   3545:       install_element (CONFIG_NODE, &config_log_stdout_cmd);
                   3546:       install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
                   3547:       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
                   3548:       install_element (CONFIG_NODE, &config_log_monitor_cmd);
                   3549:       install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
                   3550:       install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
                   3551:       install_element (CONFIG_NODE, &config_log_file_cmd);
                   3552:       install_element (CONFIG_NODE, &config_log_file_level_cmd);
                   3553:       install_element (CONFIG_NODE, &no_config_log_file_cmd);
                   3554:       install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
                   3555:       install_element (CONFIG_NODE, &config_log_syslog_cmd);
                   3556:       install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
                   3557:       install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
                   3558:       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
                   3559:       install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
                   3560:       install_element (CONFIG_NODE, &config_log_facility_cmd);
                   3561:       install_element (CONFIG_NODE, &no_config_log_facility_cmd);
                   3562:       install_element (CONFIG_NODE, &config_log_trap_cmd);
                   3563:       install_element (CONFIG_NODE, &no_config_log_trap_cmd);
                   3564:       install_element (CONFIG_NODE, &config_log_record_priority_cmd);
                   3565:       install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
                   3566:       install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
                   3567:       install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
                   3568:       install_element (CONFIG_NODE, &service_password_encrypt_cmd);
                   3569:       install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
                   3570:       install_element (CONFIG_NODE, &banner_motd_default_cmd);
                   3571:       install_element (CONFIG_NODE, &banner_motd_file_cmd);
                   3572:       install_element (CONFIG_NODE, &no_banner_motd_cmd);
                   3573:       install_element (CONFIG_NODE, &service_terminal_length_cmd);
                   3574:       install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
                   3575: 
                   3576:       install_element (VIEW_NODE, &show_thread_cpu_cmd);
                   3577:       install_element (ENABLE_NODE, &show_thread_cpu_cmd);
                   3578:       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
                   3579:       
                   3580:       install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
                   3581:       install_element (VIEW_NODE, &show_work_queues_cmd);
                   3582:       install_element (ENABLE_NODE, &show_work_queues_cmd);
                   3583:     }
                   3584:   srand(time(NULL));
                   3585: }
                   3586: 
                   3587: void
                   3588: cmd_terminate ()
                   3589: {
                   3590:   unsigned int i, j, k, l;
                   3591:   struct cmd_node *cmd_node;
                   3592:   struct cmd_element *cmd_element;
                   3593:   struct desc *desc;
                   3594:   vector cmd_node_v, cmd_element_v, desc_v;
                   3595: 
                   3596:   if (cmdvec)
                   3597:     {
                   3598:       for (i = 0; i < vector_active (cmdvec); i++) 
                   3599:         if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
                   3600:           {
                   3601:             cmd_node_v = cmd_node->cmd_vector;
                   3602: 
                   3603:             for (j = 0; j < vector_active (cmd_node_v); j++)
                   3604:               if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
                   3605:                   cmd_element->strvec != NULL)
                   3606:                 {
                   3607:                   cmd_element_v = cmd_element->strvec;
                   3608: 
                   3609:                   for (k = 0; k < vector_active (cmd_element_v); k++)
                   3610:                     if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
                   3611:                       {
                   3612:                         for (l = 0; l < vector_active (desc_v); l++)
                   3613:                           if ((desc = vector_slot (desc_v, l)) != NULL)
                   3614:                             {
                   3615:                               if (desc->cmd)
                   3616:                                 XFREE (MTYPE_STRVEC, desc->cmd);
                   3617:                               if (desc->str)
                   3618:                                 XFREE (MTYPE_STRVEC, desc->str);
                   3619: 
                   3620:                               XFREE (MTYPE_DESC, desc);
                   3621:                             }
                   3622:                         vector_free (desc_v);
                   3623:                       }
                   3624: 
                   3625:                   cmd_element->strvec = NULL;
                   3626:                   vector_free (cmd_element_v);
                   3627:                 }
                   3628: 
                   3629:             vector_free (cmd_node_v);
                   3630:           }
                   3631: 
                   3632:       vector_free (cmdvec);
                   3633:       cmdvec = NULL;
                   3634:     }
                   3635: 
                   3636:   if (command_cr)
                   3637:     XFREE(MTYPE_STRVEC, command_cr);
                   3638:   if (desc_cr.str)
                   3639:     XFREE(MTYPE_STRVEC, desc_cr.str);
                   3640:   if (host.name)
                   3641:     XFREE (MTYPE_HOST, host.name);
                   3642:   if (host.password)
                   3643:     XFREE (MTYPE_HOST, host.password);
                   3644:   if (host.password_encrypt)
                   3645:     XFREE (MTYPE_HOST, host.password_encrypt);
                   3646:   if (host.enable)
                   3647:     XFREE (MTYPE_HOST, host.enable);
                   3648:   if (host.enable_encrypt)
                   3649:     XFREE (MTYPE_HOST, host.enable_encrypt);
                   3650:   if (host.logfile)
                   3651:     XFREE (MTYPE_HOST, host.logfile);
                   3652:   if (host.motdfile)
                   3653:     XFREE (MTYPE_HOST, host.motdfile);
                   3654:   if (host.config)
                   3655:     XFREE (MTYPE_HOST, host.config);
                   3656: }

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