command.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:69k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* Command interpreter routine for virtual terminal [aka TeletYpe]
  2.    Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
  3. This file is part of GNU Zebra.
  4.  
  5. GNU Zebra is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published
  7. by the Free Software Foundation; either version 2, or (at your
  8. option) any later version.
  9. GNU Zebra is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Zebra; see the file COPYING.  If not, write to the
  15. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16. Boston, MA 02111-1307, USA.  */
  17. #include <zebra.h>
  18. #include "command.h"
  19. #include "memory.h"
  20. #include "log.h"
  21. #include "version.h"
  22. /* Command vector which includes some level of command lists. Normally
  23.    each daemon maintains each own cmdvec. */
  24. vector cmdvec;
  25. /* Host information structure. */
  26. struct host host;
  27. /* Default motd string. */
  28. char *default_motd = 
  29. "rn
  30. Hello, this is zebra (version " ZEBRA_VERSION ").rn
  31. Copyright 1996-2004 Kunihiro Ishiguro.rn
  32. rn";
  33. /* Standard command node structures. */
  34. struct cmd_node auth_node =
  35. {
  36.   AUTH_NODE,
  37.   "Password: ",
  38. };
  39. struct cmd_node view_node =
  40. {
  41.   VIEW_NODE,
  42.   "%s> ",
  43. };
  44. struct cmd_node auth_enable_node =
  45. {
  46.   AUTH_ENABLE_NODE,
  47.   "Password: ",
  48. };
  49. struct cmd_node enable_node =
  50. {
  51.   ENABLE_NODE,
  52.   "%s# ",
  53. };
  54. struct cmd_node config_node =
  55. {
  56.   CONFIG_NODE,
  57.   "%s(config)# ",
  58.   1
  59. };
  60. /* Utility function to concatenate argv argument into a single string
  61.    with inserting ' ' character between each argument.  */
  62. char *
  63. argv_concat (char **argv, int argc, int shift)
  64. {
  65.   int i;
  66.   int len;
  67.   int index;
  68.   char *str;
  69.   str = NULL;
  70.   index = 0;
  71.   for (i = shift; i < argc; i++)
  72.     {
  73.       len = strlen (argv[i]);
  74.       if (i == shift)
  75. {
  76.   str = XSTRDUP (MTYPE_TMP, argv[i]);
  77.   index = len;
  78. }
  79.       else
  80. {
  81.   str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
  82.   str[index++] = ' ';
  83.   memcpy (str + index, argv[i], len);
  84.   index += len;
  85.   str[index] = '';
  86. }
  87.     }
  88.   return str;
  89. }
  90. /* Install top node of command vector. */
  91. void
  92. install_node (struct cmd_node *node, 
  93.       int (*func) (struct vty *))
  94. {
  95.   vector_set_index (cmdvec, node->node, node);
  96.   node->func = func;
  97.   node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
  98. }
  99. /* Compare two command's string.  Used in sort_node (). */
  100. int
  101. cmp_node (const void *p, const void *q)
  102. {
  103.   struct cmd_element *a = *(struct cmd_element **)p;
  104.   struct cmd_element *b = *(struct cmd_element **)q;
  105.   return strcmp (a->string, b->string);
  106. }
  107. int
  108. cmp_desc (const void *p, const void *q)
  109. {
  110.   struct desc *a = *(struct desc **)p;
  111.   struct desc *b = *(struct desc **)q;
  112.   return strcmp (a->cmd, b->cmd);
  113. }
  114. /* Sort each node's command element according to command string. */
  115. void
  116. sort_node ()
  117. {
  118.   int i, j;
  119.   struct cmd_node *cnode;
  120.   vector descvec;
  121.   struct cmd_element *cmd_element;
  122.   for (i = 0; i < vector_max (cmdvec); i++) 
  123.     if ((cnode = vector_slot (cmdvec, i)) != NULL)
  124.       {
  125. vector cmd_vector = cnode->cmd_vector;
  126. qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
  127. for (j = 0; j < vector_max (cmd_vector); j++)
  128.   if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
  129.     {
  130.       descvec = vector_slot (cmd_element->strvec,
  131.      vector_max (cmd_element->strvec) - 1);
  132.       qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
  133.     }
  134.       }
  135. }
  136. /* Breaking up string into each command piece. I assume given
  137.    character is separated by a space character. Return value is a
  138.    vector which includes char ** data element. */
  139. vector
  140. cmd_make_strvec (char *string)
  141. {
  142.   char *cp, *start, *token;
  143.   int strlen;
  144.   vector strvec;
  145.   
  146.   if (string == NULL)
  147.     return NULL;
  148.   
  149.   cp = string;
  150.   /* Skip white spaces. */
  151.   while (isspace ((int) *cp) && *cp != '')
  152.     cp++;
  153.   /* Return if there is only white spaces */
  154.   if (*cp == '')
  155.     return NULL;
  156.   if (*cp == '!' || *cp == '#')
  157.     return NULL;
  158.   /* Prepare return vector. */
  159.   strvec = vector_init (VECTOR_MIN_SIZE);
  160.   /* Copy each command piece and set into vector. */
  161.   while (1) 
  162.     {
  163.       start = cp;
  164.       while (!(isspace ((int) *cp) || *cp == 'r' || *cp == 'n') &&
  165.      *cp != '')
  166. cp++;
  167.       strlen = cp - start;
  168.       token = XMALLOC (MTYPE_STRVEC, strlen + 1);
  169.       memcpy (token, start, strlen);
  170.       *(token + strlen) = '';
  171.       vector_set (strvec, token);
  172.       while ((isspace ((int) *cp) || *cp == 'n' || *cp == 'r') &&
  173.      *cp != '')
  174. cp++;
  175.       if (*cp == '')
  176. return strvec;
  177.     }
  178. }
  179. /* Free allocated string vector. */
  180. void
  181. cmd_free_strvec (vector v)
  182. {
  183.   int i;
  184.   char *cp;
  185.   if (!v)
  186.     return;
  187.   for (i = 0; i < vector_max (v); i++)
  188.     if ((cp = vector_slot (v, i)) != NULL)
  189.       XFREE (MTYPE_STRVEC, cp);
  190.   vector_free (v);
  191. }
  192. /* Fetch next description.  Used in cmd_make_descvec(). */
  193. char *
  194. cmd_desc_str (char **string)
  195. {
  196.   char *cp, *start, *token;
  197.   int strlen;
  198.   
  199.   cp = *string;
  200.   if (cp == NULL)
  201.     return NULL;
  202.   /* Skip white spaces. */
  203.   while (isspace ((int) *cp) && *cp != '')
  204.     cp++;
  205.   /* Return if there is only white spaces */
  206.   if (*cp == '')
  207.     return NULL;
  208.   start = cp;
  209.   while (!(*cp == 'r' || *cp == 'n') && *cp != '')
  210.     cp++;
  211.   strlen = cp - start;
  212.   token = XMALLOC (MTYPE_STRVEC, strlen + 1);
  213.   memcpy (token, start, strlen);
  214.   *(token + strlen) = '';
  215.   *string = cp;
  216.   return token;
  217. }
  218. /* New string vector. */
  219. vector
  220. cmd_make_descvec (char *string, char *descstr)
  221. {
  222.   int multiple = 0;
  223.   char *sp;
  224.   char *token;
  225.   int len;
  226.   char *cp;
  227.   char *dp;
  228.   vector allvec;
  229.   vector strvec = NULL;
  230.   struct desc *desc;
  231.   cp = string;
  232.   dp = descstr;
  233.   if (cp == NULL)
  234.     return NULL;
  235.   allvec = vector_init (VECTOR_MIN_SIZE);
  236.   while (1)
  237.     {
  238.       while (isspace ((int) *cp) && *cp != '')
  239. cp++;
  240.       if (*cp == '(')
  241. {
  242.   multiple = 1;
  243.   cp++;
  244. }
  245.       if (*cp == ')')
  246. {
  247.   multiple = 0;
  248.   cp++;
  249. }
  250.       if (*cp == '|')
  251. {
  252.   if (! multiple)
  253.     {
  254.       fprintf (stderr, "Command parse error!: %sn", string);
  255.       exit (1);
  256.     }
  257.   cp++;
  258. }
  259.       
  260.       while (isspace ((int) *cp) && *cp != '')
  261. cp++;
  262.       if (*cp == '(')
  263. {
  264.   multiple = 1;
  265.   cp++;
  266. }
  267.       if (*cp == '') 
  268. return allvec;
  269.       sp = cp;
  270.       while (! (isspace ((int) *cp) || *cp == 'r' || *cp == 'n' || *cp == ')' || *cp == '|') && *cp != '')
  271. cp++;
  272.       len = cp - sp;
  273.       token = XMALLOC (MTYPE_STRVEC, len + 1);
  274.       memcpy (token, sp, len);
  275.       *(token + len) = '';
  276.       desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
  277.       desc->cmd = token;
  278.       desc->str = cmd_desc_str (&dp);
  279.       if (multiple)
  280. {
  281.   if (multiple == 1)
  282.     {
  283.       strvec = vector_init (VECTOR_MIN_SIZE);
  284.       vector_set (allvec, strvec);
  285.     }
  286.   multiple++;
  287. }
  288.       else
  289. {
  290.   strvec = vector_init (VECTOR_MIN_SIZE);
  291.   vector_set (allvec, strvec);
  292. }
  293.       vector_set (strvec, desc);
  294.     }
  295. }
  296. /* Count mandantory string vector size.  This is to determine inputed
  297.    command has enough command length. */
  298. int
  299. cmd_cmdsize (vector strvec)
  300. {
  301.   int i;
  302.   char *str;
  303.   int size = 0;
  304.   vector descvec;
  305.   for (i = 0; i < vector_max (strvec); i++)
  306.     {
  307.       descvec = vector_slot (strvec, i);
  308.       if (vector_max (descvec) == 1)
  309. {
  310.   struct desc *desc = vector_slot (descvec, 0);
  311.   str = desc->cmd;
  312.   
  313.   if (str == NULL || CMD_OPTION (str))
  314.     return size;
  315.   else
  316.     size++;
  317. }
  318.       else
  319. size++;
  320.     }
  321.   return size;
  322. }
  323. /* Return prompt character of specified node. */
  324. char *
  325. cmd_prompt (enum node_type node)
  326. {
  327.   struct cmd_node *cnode;
  328.   cnode = vector_slot (cmdvec, node);
  329.   return cnode->prompt;
  330. }
  331. /* Install a command into a node. */
  332. void
  333. install_element (enum node_type ntype, struct cmd_element *cmd)
  334. {
  335.   struct cmd_node *cnode;
  336.   cnode = vector_slot (cmdvec, ntype);
  337.   if (cnode == NULL) 
  338.     {
  339.       fprintf (stderr, "Command node %d doesn't exist, please check itn",
  340.        ntype);
  341.       exit (1);
  342.     }
  343.   vector_set (cnode->cmd_vector, cmd);
  344.   cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
  345.   cmd->cmdsize = cmd_cmdsize (cmd->strvec);
  346. }
  347. static unsigned char itoa64[] =
  348. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  349. void
  350. to64(char *s, long v, int n)
  351. {
  352.   while (--n >= 0) 
  353.     {
  354.       *s++ = itoa64[v&0x3f];
  355.       v >>= 6;
  356.     }
  357. }
  358. char *zencrypt (char *passwd)
  359. {
  360.   char salt[6];
  361.   struct timeval tv;
  362.   char *crypt (const char *, const char *);
  363.   gettimeofday(&tv,0);
  364.   
  365.   to64(&salt[0], random(), 3);
  366.   to64(&salt[3], tv.tv_usec, 3);
  367.   salt[5] = '';
  368.   return crypt (passwd, salt);
  369. }
  370. char *
  371. syslog_facility_print (int facility)
  372. {
  373.   switch (facility)
  374.     {
  375.       case LOG_KERN:
  376. return "kern";
  377. break;
  378.       case LOG_USER:
  379. return "user";
  380. break;
  381.       case LOG_MAIL:
  382. return "mail";
  383. break;
  384.       case LOG_DAEMON:
  385. return "daemon";
  386. break;
  387.       case LOG_AUTH:
  388. return "auth";
  389. break;
  390.       case LOG_SYSLOG:
  391. return "syslog";
  392. break;
  393.       case LOG_LPR:
  394. return "lpr";
  395. break;
  396.       case LOG_NEWS:
  397. return "news";
  398. break;
  399.       case LOG_UUCP:
  400. return "uucp";
  401. break;
  402.       case LOG_CRON:
  403. return "cron";
  404. break;
  405.       case LOG_LOCAL0:
  406. return "local0";
  407. break;
  408.       case LOG_LOCAL1:
  409. return "local1";
  410. break;
  411.       case LOG_LOCAL2:
  412. return "local2";
  413. break;
  414.       case LOG_LOCAL3:
  415. return "local3";
  416. break;
  417.       case LOG_LOCAL4:
  418. return "local4";
  419. break;
  420.       case LOG_LOCAL5:
  421. return "local5";
  422. break;
  423.       case LOG_LOCAL6:
  424. return "local6";
  425. break;
  426.       case LOG_LOCAL7:
  427. return "local7";
  428. break;
  429.       default:
  430. break;
  431.     }
  432.   return "";
  433. }
  434. /* This function write configuration of this host. */
  435. int
  436. config_write_host (struct vty *vty)
  437. {
  438.   if (host.name)
  439.     vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
  440.   if (host.encrypt)
  441.     {
  442.       if (host.password_encrypt)
  443.         vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); 
  444.       if (host.enable_encrypt)
  445.         vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); 
  446.     }
  447.   else
  448.     {
  449.       if (host.password)
  450.         vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
  451.       else if (host.password_encrypt)
  452.         vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); 
  453.       if (host.enable)
  454.         vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
  455.       else if (host.enable_encrypt)
  456.         vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); 
  457.     }
  458.   if (host.logfile)
  459.     vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
  460.   if (host.log_stdout)
  461.     vty_out (vty, "log stdout%s", VTY_NEWLINE);
  462.   if (host.log_syslog)
  463.     {
  464.       vty_out (vty, "log syslog");
  465.       if (zlog_default->facility != LOG_DAEMON)
  466. vty_out (vty, " facility %s", syslog_facility_print (zlog_default->facility));
  467.       vty_out (vty, "%s", VTY_NEWLINE);
  468.     }
  469.   if (zlog_default->maskpri != LOG_DEBUG)
  470.     vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
  471.   if (zlog_default->record_priority == 1)
  472.     vty_out (vty, "log record-priority%s", VTY_NEWLINE);
  473.   if (host.advanced)
  474.     vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
  475.   if (host.encrypt)
  476.     vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
  477.   if (host.lines >= 0)
  478.     vty_out (vty, "service terminal-length %d%s", host.lines,
  479.      VTY_NEWLINE);
  480.   if (! host.motd)
  481.     vty_out (vty, "no banner motd%s", VTY_NEWLINE);
  482.   return 1;
  483. }
  484. /* Utility function for getting command vector. */
  485. vector
  486. cmd_node_vector (vector v, enum node_type ntype)
  487. {
  488.   struct cmd_node *cnode = vector_slot (v, ntype);
  489.   return cnode->cmd_vector;
  490. }
  491. /* Filter command vector by symbol */
  492. int
  493. cmd_filter_by_symbol (char *command, char *symbol)
  494. {
  495.   int i, lim;
  496.   if (strcmp (symbol, "IPV4_ADDRESS") == 0)
  497.     {
  498.       i = 0;
  499.       lim = strlen (command);
  500.       while (i < lim)
  501. {
  502.   if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
  503.     return 1;
  504.   i++;
  505. }
  506.       return 0;
  507.     }
  508.   if (strcmp (symbol, "STRING") == 0)
  509.     {
  510.       i = 0;
  511.       lim = strlen (command);
  512.       while (i < lim)
  513. {
  514.   if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
  515.     return 1;
  516.   i++;
  517. }
  518.       return 0;
  519.     }
  520.   if (strcmp (symbol, "IFNAME") == 0)
  521.     {
  522.       i = 0;
  523.       lim = strlen (command);
  524.       while (i < lim)
  525. {
  526.   if (! isalnum ((int) command[i]))
  527.     return 1;
  528.   i++;
  529. }
  530.       return 0;
  531.     }
  532.   return 0;
  533. }
  534. /* Completion match types. */
  535. enum match_type 
  536. {
  537.   no_match,
  538.   extend_match,
  539.   ipv4_prefix_match,
  540.   ipv4_match,
  541.   ipv6_prefix_match,
  542.   ipv6_match,
  543.   range_match,
  544.   vararg_match,
  545.   partly_match,
  546.   exact_match 
  547. };
  548. enum match_type
  549. cmd_ipv4_match (char *str)
  550. {
  551.   char *sp;
  552.   int dots = 0, nums = 0;
  553.   char buf[4];
  554.   if (str == NULL)
  555.     return partly_match;
  556.   for (;;)
  557.     {
  558.       memset (buf, 0, sizeof (buf));
  559.       sp = str;
  560.       while (*str != '')
  561. {
  562.   if (*str == '.')
  563.     {
  564.       if (dots >= 3)
  565. return no_match;
  566.       if (*(str + 1) == '.')
  567. return no_match;
  568.       if (*(str + 1) == '')
  569. return partly_match;
  570.       dots++;
  571.       break;
  572.     }
  573.   if (!isdigit ((int) *str))
  574.     return no_match;
  575.   str++;
  576. }
  577.       if (str - sp > 3)
  578. return no_match;
  579.       strncpy (buf, sp, str - sp);
  580.       if (atoi (buf) > 255)
  581. return no_match;
  582.       nums++;
  583.       if (*str == '')
  584. break;
  585.       str++;
  586.     }
  587.   if (nums < 4)
  588.     return partly_match;
  589.   return exact_match;
  590. }
  591. enum match_type
  592. cmd_ipv4_prefix_match (char *str)
  593. {
  594.   char *sp;
  595.   int dots = 0;
  596.   char buf[4];
  597.   if (str == NULL)
  598.     return partly_match;
  599.   for (;;)
  600.     {
  601.       memset (buf, 0, sizeof (buf));
  602.       sp = str;
  603.       while (*str != '' && *str != '/')
  604. {
  605.   if (*str == '.')
  606.     {
  607.       if (dots == 3)
  608. return no_match;
  609.       if (*(str + 1) == '.' || *(str + 1) == '/')
  610. return no_match;
  611.       if (*(str + 1) == '')
  612. return partly_match;
  613.       dots++;
  614.       break;
  615.     }
  616.   if (!isdigit ((int) *str))
  617.     return no_match;
  618.   str++;
  619. }
  620.       if (str - sp > 3)
  621. return no_match;
  622.       strncpy (buf, sp, str - sp);
  623.       if (atoi (buf) > 255)
  624. return no_match;
  625.       if (dots == 3)
  626. {
  627.   if (*str == '/')
  628.     {
  629.       if (*(str + 1) == '')
  630. return partly_match;
  631.       str++;
  632.       break;
  633.     }
  634.   else if (*str == '')
  635.     return partly_match;
  636. }
  637.       if (*str == '')
  638. return partly_match;
  639.       str++;
  640.     }
  641.   sp = str;
  642.   while (*str != '')
  643.     {
  644.       if (!isdigit ((int) *str))
  645. return no_match;
  646.       str++;
  647.     }
  648.   if (atoi (sp) > 32)
  649.     return no_match;
  650.   return exact_match;
  651. }
  652. #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
  653. #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
  654. #define STATE_START 1
  655. #define STATE_COLON 2
  656. #define STATE_DOUBLE 3
  657. #define STATE_ADDR 4
  658. #define STATE_DOT               5
  659. #define STATE_SLASH 6
  660. #define STATE_MASK 7
  661. enum match_type
  662. cmd_ipv6_match (char *str)
  663. {
  664.   int state = STATE_START;
  665.   int colons = 0, nums = 0, double_colon = 0;
  666.   char *sp = NULL;
  667.   if (str == NULL)
  668.     return partly_match;
  669.   if (strspn (str, IPV6_ADDR_STR) != strlen (str))
  670.     return no_match;
  671.   while (*str != '')
  672.     {
  673.       switch (state)
  674. {
  675. case STATE_START:
  676.   if (*str == ':')
  677.     {
  678.       if (*(str + 1) != ':' && *(str + 1) != '')
  679. return no_match;
  680.             colons--;
  681.       state = STATE_COLON;
  682.     }
  683.   else
  684.     {
  685.       sp = str;
  686.       state = STATE_ADDR;
  687.     }
  688.   continue;
  689. case STATE_COLON:
  690.   colons++;
  691.   if (*(str + 1) == ':')
  692.     state = STATE_DOUBLE;
  693.   else
  694.     {
  695.       sp = str + 1;
  696.       state = STATE_ADDR;
  697.     }
  698.   break;
  699. case STATE_DOUBLE:
  700.   if (double_colon)
  701.     return no_match;
  702.   if (*(str + 1) == ':')
  703.     return no_match;
  704.   else
  705.     {
  706.       if (*(str + 1) != '')
  707. colons++;
  708.       sp = str + 1;
  709.       state = STATE_ADDR;
  710.     }
  711.   double_colon++;
  712.   nums++;
  713.   break;
  714. case STATE_ADDR:
  715.   if (*(str + 1) == ':' || *(str + 1) == '')
  716.     {
  717.       if (str - sp > 3)
  718. return no_match;
  719.       nums++;
  720.       state = STATE_COLON;
  721.     }
  722.   if (*(str + 1) == '.')
  723.     state = STATE_DOT;
  724.   break;
  725. case STATE_DOT:
  726.   state = STATE_ADDR;
  727.   break;
  728. default:
  729.   break;
  730. }
  731.       if (nums > 8)
  732. return no_match;
  733.       if (colons > 7)
  734. return no_match;
  735.       str++;
  736.     }
  737. #if 0
  738.   if (nums < 11)
  739.     return partly_match;
  740. #endif /* 0 */
  741.   return exact_match;
  742. }
  743. enum match_type
  744. cmd_ipv6_prefix_match (char *str)
  745. {
  746.   int state = STATE_START;
  747.   int colons = 0, nums = 0, double_colon = 0;
  748.   int mask;
  749.   char *sp = NULL;
  750.   char *endptr = NULL;
  751.   if (str == NULL)
  752.     return partly_match;
  753.   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
  754.     return no_match;
  755.   while (*str != '' && state != STATE_MASK)
  756.     {
  757.       switch (state)
  758. {
  759. case STATE_START:
  760.   if (*str == ':')
  761.     {
  762.       if (*(str + 1) != ':' && *(str + 1) != '')
  763. return no_match;
  764.       colons--;
  765.       state = STATE_COLON;
  766.     }
  767.   else
  768.     {
  769.       sp = str;
  770.       state = STATE_ADDR;
  771.     }
  772.   continue;
  773. case STATE_COLON:
  774.   colons++;
  775.   if (*(str + 1) == '/')
  776.     return no_match;
  777.   else if (*(str + 1) == ':')
  778.     state = STATE_DOUBLE;
  779.   else
  780.     {
  781.       sp = str + 1;
  782.       state = STATE_ADDR;
  783.     }
  784.   break;
  785. case STATE_DOUBLE:
  786.   if (double_colon)
  787.     return no_match;
  788.   if (*(str + 1) == ':')
  789.     return no_match;
  790.   else
  791.     {
  792.       if (*(str + 1) != '' && *(str + 1) != '/')
  793. colons++;
  794.       sp = str + 1;
  795.       if (*(str + 1) == '/')
  796. state = STATE_SLASH;
  797.       else
  798. state = STATE_ADDR;
  799.     }
  800.   double_colon++;
  801.   nums += 1;
  802.   break;
  803. case STATE_ADDR:
  804.   if (*(str + 1) == ':' || *(str + 1) == '.'
  805.       || *(str + 1) == '' || *(str + 1) == '/')
  806.     {
  807.       if (str - sp > 3)
  808. return no_match;
  809.       for (; sp <= str; sp++)
  810. if (*sp == '/')
  811.   return no_match;
  812.       nums++;
  813.       if (*(str + 1) == ':')
  814. state = STATE_COLON;
  815.       else if (*(str + 1) == '.')
  816. state = STATE_DOT;
  817.       else if (*(str + 1) == '/')
  818. state = STATE_SLASH;
  819.     }
  820.   break;
  821. case STATE_DOT:
  822.   state = STATE_ADDR;
  823.   break;
  824. case STATE_SLASH:
  825.   if (*(str + 1) == '')
  826.     return partly_match;
  827.   state = STATE_MASK;
  828.   break;
  829. default:
  830.   break;
  831. }
  832.       if (nums > 11)
  833. return no_match;
  834.       if (colons > 7)
  835. return no_match;
  836.       str++;
  837.     }
  838.   if (state < STATE_MASK)
  839.     return partly_match;
  840.   mask = strtol (str, &endptr, 10);
  841.   if (*endptr != '')
  842.     return no_match;
  843.   if (mask < 0 || mask > 128)
  844.     return no_match;
  845.   
  846. /* I don't know why mask < 13 makes command match partly.
  847.    Forgive me to make this comments. I Want to set static default route
  848.    because of lack of function to originate default in ospf6d; sorry
  849.        yasu
  850.   if (mask < 13)
  851.     return partly_match;
  852. */
  853.   return exact_match;
  854. }
  855. #define DECIMAL_STRLEN_MAX 10
  856. int
  857. cmd_range_match (char *range, char *str)
  858. {
  859.   char *p;
  860.   char buf[DECIMAL_STRLEN_MAX + 1];
  861.   char *endptr = NULL;
  862.   unsigned long min, max, val;
  863.   if (str == NULL)
  864.     return 1;
  865.   val = strtoul (str, &endptr, 10);
  866.   if (*endptr != '')
  867.     return 0;
  868.   range++;
  869.   p = strchr (range, '-');
  870.   if (p == NULL)
  871.     return 0;
  872.   if (p - range > DECIMAL_STRLEN_MAX)
  873.     return 0;
  874.   strncpy (buf, range, p - range);
  875.   buf[p - range] = '';
  876.   min = strtoul (buf, &endptr, 10);
  877.   if (*endptr != '')
  878.     return 0;
  879.   range = p + 1;
  880.   p = strchr (range, '>');
  881.   if (p == NULL)
  882.     return 0;
  883.   if (p - range > DECIMAL_STRLEN_MAX)
  884.     return 0;
  885.   strncpy (buf, range, p - range);
  886.   buf[p - range] = '';
  887.   max = strtoul (buf, &endptr, 10);
  888.   if (*endptr != '')
  889.     return 0;
  890.   if (val < min || val > max)
  891.     return 0;
  892.   return 1;
  893. }
  894. /* Make completion match and return match type flag. */
  895. enum match_type
  896. cmd_filter_by_completion (char *command, vector v, int index)
  897. {
  898.   int i;
  899.   char *str;
  900.   struct cmd_element *cmd_element;
  901.   enum match_type match_type;
  902.   vector descvec;
  903.   struct desc *desc;
  904.   
  905.   match_type = no_match;
  906.   /* If command and cmd_element string does not match set NULL to vector */
  907.   for (i = 0; i < vector_max (v); i++) 
  908.     if ((cmd_element = vector_slot (v, i)) != NULL)
  909.       {
  910. if (index >= vector_max (cmd_element->strvec))
  911.   vector_slot (v, i) = NULL;
  912. else
  913.   {
  914.     int j;
  915.     int matched = 0;
  916.     descvec = vector_slot (cmd_element->strvec, index);
  917.     
  918.     for (j = 0; j < vector_max (descvec); j++)
  919.       {
  920. desc = vector_slot (descvec, j);
  921. str = desc->cmd;
  922. if (CMD_VARARG (str))
  923.   {
  924.     if (match_type < vararg_match)
  925.       match_type = vararg_match;
  926.     matched++;
  927.   }
  928. else if (CMD_RANGE (str))
  929.   {
  930.     if (cmd_range_match (str, command))
  931.       {
  932. if (match_type < range_match)
  933.   match_type = range_match;
  934. matched++;
  935.       }
  936.   }
  937. else if (CMD_IPV6 (str))
  938.   {
  939.     if (cmd_ipv6_match (command))
  940.       {
  941. if (match_type < ipv6_match)
  942.   match_type = ipv6_match;
  943. matched++;
  944.       }
  945.   }
  946. else if (CMD_IPV6_PREFIX (str))
  947.   {
  948.     if (cmd_ipv6_prefix_match (command))
  949.       {
  950. if (match_type < ipv6_prefix_match)
  951.   match_type = ipv6_prefix_match;
  952. matched++;
  953.       }
  954.   }
  955. else if (CMD_IPV4 (str))
  956.   {
  957.     if (cmd_ipv4_match (command))
  958.       {
  959. if (match_type < ipv4_match)
  960.   match_type = ipv4_match;
  961. matched++;
  962.       }
  963.   }
  964. else if (CMD_IPV4_PREFIX (str))
  965.   {
  966.     if (cmd_ipv4_prefix_match (command))
  967.       {
  968. if (match_type < ipv4_prefix_match)
  969.   match_type = ipv4_prefix_match;
  970. matched++;
  971.       }
  972.   }
  973. else
  974. /* Check is this point's argument optional ? */
  975. if (CMD_OPTION (str) || CMD_VARIABLE (str))
  976.   {
  977.     if (match_type < extend_match)
  978.       match_type = extend_match;
  979.     matched++;
  980.   }
  981. else if (strncmp (command, str, strlen (command)) == 0)
  982.   {
  983.     if (strcmp (command, str) == 0) 
  984.       match_type = exact_match;
  985.     else
  986.       {
  987. if (match_type < partly_match)
  988.   match_type = partly_match;
  989.       }
  990.     matched++;
  991.   }
  992.       }
  993.     if (! matched)
  994.       vector_slot (v, i) = NULL;
  995.   }
  996.       }
  997.   return match_type;
  998. }
  999. /* Filter vector by command character with index. */
  1000. enum match_type
  1001. cmd_filter_by_string (char *command, vector v, int index)
  1002. {
  1003.   int i;
  1004.   char *str;
  1005.   struct cmd_element *cmd_element;
  1006.   enum match_type match_type;
  1007.   vector descvec;
  1008.   struct desc *desc;
  1009.   
  1010.   match_type = no_match;
  1011.   /* If command and cmd_element string does not match set NULL to vector */
  1012.   for (i = 0; i < vector_max (v); i++) 
  1013.     if ((cmd_element = vector_slot (v, i)) != NULL)
  1014.       {
  1015. /* If given index is bigger than max string vector of command,
  1016.            set NULL*/
  1017. if (index >= vector_max (cmd_element->strvec))
  1018.   vector_slot (v, i) = NULL;
  1019. else 
  1020.   {
  1021.     int j;
  1022.     int matched = 0;
  1023.     descvec = vector_slot (cmd_element->strvec, index);
  1024.     for (j = 0; j < vector_max (descvec); j++)
  1025.       {
  1026. desc = vector_slot (descvec, j);
  1027. str = desc->cmd;
  1028. if (CMD_VARARG (str))
  1029.   {
  1030.     if (match_type < vararg_match)
  1031.       match_type = vararg_match;
  1032.     matched++;
  1033.   }
  1034. else if (CMD_RANGE (str))
  1035.   {
  1036.     if (cmd_range_match (str, command))
  1037.       {
  1038. if (match_type < range_match)
  1039.   match_type = range_match;
  1040. matched++;
  1041.       }
  1042.   }
  1043. else if (CMD_IPV6 (str))
  1044.   {
  1045.     if (cmd_ipv6_match (command) == exact_match)
  1046.       {
  1047. if (match_type < ipv6_match)
  1048.   match_type = ipv6_match;
  1049. matched++;
  1050.       }
  1051.   }
  1052. else if (CMD_IPV6_PREFIX (str))
  1053.   {
  1054.     if (cmd_ipv6_prefix_match (command) == exact_match)
  1055.       {
  1056. if (match_type < ipv6_prefix_match)
  1057.   match_type = ipv6_prefix_match;
  1058. matched++;
  1059.       }
  1060.   }
  1061. else if (CMD_IPV4 (str))
  1062.   {
  1063.     if (cmd_ipv4_match (command) == exact_match)
  1064.       {
  1065. if (match_type < ipv4_match)
  1066.   match_type = ipv4_match;
  1067. matched++;
  1068.       }
  1069.   }
  1070. else if (CMD_IPV4_PREFIX (str))
  1071.   {
  1072.     if (cmd_ipv4_prefix_match (command) == exact_match)
  1073.       {
  1074. if (match_type < ipv4_prefix_match)
  1075.   match_type = ipv4_prefix_match;
  1076. matched++;
  1077.       }
  1078.   }
  1079. else if (CMD_OPTION (str) || CMD_VARIABLE (str))
  1080.   {
  1081.     if (match_type < extend_match)
  1082.       match_type = extend_match;
  1083.     matched++;
  1084.   }
  1085. else
  1086.   {   
  1087.     if (strcmp (command, str) == 0)
  1088.       {
  1089. match_type = exact_match;
  1090. matched++;
  1091.       }
  1092.   }
  1093.       }
  1094.     if (! matched)
  1095.       vector_slot (v, i) = NULL;
  1096.   }
  1097.       }
  1098.   return match_type;
  1099. }
  1100. /* Check ambiguous match */
  1101. int
  1102. is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
  1103. {
  1104.   int i;
  1105.   int j;
  1106.   char *str = NULL;
  1107.   struct cmd_element *cmd_element;
  1108.   char *matched = NULL;
  1109.   vector descvec;
  1110.   struct desc *desc;
  1111.   
  1112.   for (i = 0; i < vector_max (v); i++) 
  1113.     if ((cmd_element = vector_slot (v, i)) != NULL)
  1114.       {
  1115. int match = 0;
  1116. descvec = vector_slot (cmd_element->strvec, index);
  1117. for (j = 0; j < vector_max (descvec); j++)
  1118.   {
  1119.     enum match_type ret;
  1120.     desc = vector_slot (descvec, j);
  1121.     str = desc->cmd;
  1122.     switch (type)
  1123.       {
  1124.       case exact_match:
  1125. if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
  1126.     && strcmp (command, str) == 0)
  1127.   match++;
  1128. break;
  1129.       case partly_match:
  1130. if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
  1131.     && strncmp (command, str, strlen (command)) == 0)
  1132.   {
  1133.     if (matched && strcmp (matched, str) != 0)
  1134.       return 1; /* There is ambiguous match. */
  1135.     else
  1136.       matched = str;
  1137.     match++;
  1138.   }
  1139. break;
  1140.       case range_match:
  1141. if (cmd_range_match (str, command))
  1142.   {
  1143.     if (matched && strcmp (matched, str) != 0)
  1144.       return 1;
  1145.     else
  1146.       matched = str;
  1147.     match++;
  1148.   }
  1149. break;
  1150.         case ipv6_match:
  1151. if (CMD_IPV6 (str))
  1152.   match++;
  1153. break;
  1154.       case ipv6_prefix_match:
  1155. if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
  1156.   {
  1157.     if (ret == partly_match)
  1158.       return 2; /* There is incomplete match. */
  1159.     match++;
  1160.   }
  1161. break;
  1162.       case ipv4_match:
  1163. if (CMD_IPV4 (str))
  1164.   match++;
  1165. break;
  1166.       case ipv4_prefix_match:
  1167. if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
  1168.   {
  1169.     if (ret == partly_match)
  1170.       return 2; /* There is incomplete match. */
  1171.     match++;
  1172.   }
  1173. break;
  1174.       case extend_match:
  1175. if (CMD_OPTION (str) || CMD_VARIABLE (str))
  1176.   match++;
  1177. break;
  1178.       case no_match:
  1179.       default:
  1180. break;
  1181.       }
  1182.   }
  1183. if (! match)
  1184.   vector_slot (v, i) = NULL;
  1185.       }
  1186.   return 0;
  1187. }
  1188. /* If src matches dst return dst string, otherwise return NULL */
  1189. char *
  1190. cmd_entry_function (char *src, char *dst)
  1191. {
  1192.   /* Skip variable arguments. */
  1193.   if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
  1194.       CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
  1195.     return NULL;
  1196.   /* In case of 'command t', given src is NULL string. */
  1197.   if (src == NULL)
  1198.     return dst;
  1199.   /* Matched with input string. */
  1200.   if (strncmp (src, dst, strlen (src)) == 0)
  1201.     return dst;
  1202.   return NULL;
  1203. }
  1204. /* If src matches dst return dst string, otherwise return NULL */
  1205. /* This version will return the dst string always if it is
  1206.    CMD_VARIABLE for '?' key processing */
  1207. char *
  1208. cmd_entry_function_desc (char *src, char *dst)
  1209. {
  1210.   if (CMD_VARARG (dst))
  1211.     return dst;
  1212.   if (CMD_RANGE (dst))
  1213.     {
  1214.       if (cmd_range_match (dst, src))
  1215. return dst;
  1216.       else
  1217. return NULL;
  1218.     }
  1219.   if (CMD_IPV6 (dst))
  1220.     {
  1221.       if (cmd_ipv6_match (src))
  1222. return dst;
  1223.       else
  1224. return NULL;
  1225.     }
  1226.   if (CMD_IPV6_PREFIX (dst))
  1227.     {
  1228.       if (cmd_ipv6_prefix_match (src))
  1229. return dst;
  1230.       else
  1231. return NULL;
  1232.     }
  1233.   if (CMD_IPV4 (dst))
  1234.     {
  1235.       if (cmd_ipv4_match (src))
  1236. return dst;
  1237.       else
  1238. return NULL;
  1239.     }
  1240.   if (CMD_IPV4_PREFIX (dst))
  1241.     {
  1242.       if (cmd_ipv4_prefix_match (src))
  1243. return dst;
  1244.       else
  1245. return NULL;
  1246.     }
  1247.   /* Optional or variable commands always match on '?' */
  1248.   if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
  1249.     return dst;
  1250.   /* In case of 'command t', given src is NULL string. */
  1251.   if (src == NULL)
  1252.     return dst;
  1253.   if (strncmp (src, dst, strlen (src)) == 0)
  1254.     return dst;
  1255.   else
  1256.     return NULL;
  1257. }
  1258. /* Check same string element existence.  If it isn't there return
  1259.     1. */
  1260. int
  1261. cmd_unique_string (vector v, char *str)
  1262. {
  1263.   int i;
  1264.   char *match;
  1265.   for (i = 0; i < vector_max (v); i++)
  1266.     if ((match = vector_slot (v, i)) != NULL)
  1267.       if (strcmp (match, str) == 0)
  1268. return 0;
  1269.   return 1;
  1270. }
  1271. /* Compare string to description vector.  If there is same string
  1272.    return 1 else return 0. */
  1273. int
  1274. desc_unique_string (vector v, char *str)
  1275. {
  1276.   int i;
  1277.   struct desc *desc;
  1278.   for (i = 0; i < vector_max (v); i++)
  1279.     if ((desc = vector_slot (v, i)) != NULL)
  1280.       if (strcmp (desc->cmd, str) == 0)
  1281. return 1;
  1282.   return 0;
  1283. }
  1284. /* '?' describe command support. */
  1285. vector
  1286. cmd_describe_command (vector vline, struct vty *vty, int *status)
  1287. {
  1288.   int i;
  1289.   vector cmd_vector;
  1290. #define INIT_MATCHVEC_SIZE 10
  1291.   vector matchvec;
  1292.   struct cmd_element *cmd_element;
  1293.   int index;
  1294.   int ret;
  1295.   enum match_type match;
  1296.   char *command;
  1297.   static struct desc desc_cr = { "<cr>", "" };
  1298.   /* Set index. */
  1299.   index = vector_max (vline) - 1;
  1300.   /* Make copy vector of current node's command vector. */
  1301.   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1302.   /* Prepare match vector */
  1303.   matchvec = vector_init (INIT_MATCHVEC_SIZE);
  1304.   /* Filter commands. */
  1305.   /* Only words precedes current word will be checked in this loop. */
  1306.   for (i = 0; i < index; i++)
  1307.     {
  1308.       command = vector_slot (vline, i);
  1309.       match = cmd_filter_by_completion (command, cmd_vector, i);
  1310.       if (match == vararg_match)
  1311. {
  1312.   struct cmd_element *cmd_element;
  1313.   vector descvec;
  1314.   int j, k;
  1315.   for (j = 0; j < vector_max (cmd_vector); j++)
  1316.     if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
  1317.       {
  1318. descvec = vector_slot (cmd_element->strvec,
  1319.        vector_max (cmd_element->strvec) - 1);
  1320. for (k = 0; k < vector_max (descvec); k++)
  1321.   {
  1322.     struct desc *desc = vector_slot (descvec, k);
  1323.     vector_set (matchvec, desc);
  1324.   }
  1325.       }
  1326.   vector_set (matchvec, &desc_cr);
  1327.   vector_free (cmd_vector);
  1328.   return matchvec;
  1329. }
  1330.       if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
  1331. {
  1332.   vector_free (cmd_vector);
  1333.   *status = CMD_ERR_AMBIGUOUS;
  1334.   return NULL;
  1335. }
  1336.       else if (ret == 2)
  1337. {
  1338.   vector_free (cmd_vector);
  1339.   *status = CMD_ERR_NO_MATCH;
  1340.   return NULL;
  1341. }
  1342.     }
  1343.   /* Prepare match vector */
  1344.   /*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
  1345.   /* Make sure that cmd_vector is filtered based on current word */
  1346.   command = vector_slot (vline, index);
  1347.   if (command)
  1348.     match = cmd_filter_by_completion (command, cmd_vector, index);
  1349.   /* Make description vector. */
  1350.   for (i = 0; i < vector_max (cmd_vector); i++)
  1351.     if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
  1352.       {
  1353. char *string = NULL;
  1354. vector strvec = cmd_element->strvec;
  1355.         /* if command is NULL, index may be equal to vector_max */
  1356. if (command && index >= vector_max (strvec))
  1357.   vector_slot (cmd_vector, i) = NULL;
  1358. else
  1359.   {
  1360.     /* Check if command is completed. */
  1361.             if (command == NULL && index == vector_max (strvec))
  1362.       {
  1363. string = "<cr>";
  1364. if (! desc_unique_string (matchvec, string))
  1365.   vector_set (matchvec, &desc_cr);
  1366.       }
  1367.     else
  1368.       {
  1369. int j;
  1370. vector descvec = vector_slot (strvec, index);
  1371. struct desc *desc;
  1372. for (j = 0; j < vector_max (descvec); j++)
  1373.   {
  1374.     desc = vector_slot (descvec, j);
  1375.     string = cmd_entry_function_desc (command, desc->cmd);
  1376.     if (string)
  1377.       {
  1378. /* Uniqueness check */
  1379. if (! desc_unique_string (matchvec, string))
  1380.   vector_set (matchvec, desc);
  1381.       }
  1382.   }
  1383.       }
  1384.   }
  1385.       }
  1386.   vector_free (cmd_vector);
  1387.   if (vector_slot (matchvec, 0) == NULL)
  1388.     {
  1389.       vector_free (matchvec);
  1390.       *status= CMD_ERR_NO_MATCH;
  1391.     }
  1392.   else
  1393.     *status = CMD_SUCCESS;
  1394.   return matchvec;
  1395. }
  1396. /* Check LCD of matched command. */
  1397. int
  1398. cmd_lcd (char **matched)
  1399. {
  1400.   int i;
  1401.   int j;
  1402.   int lcd = -1;
  1403.   char *s1, *s2;
  1404.   char c1, c2;
  1405.   if (matched[0] == NULL || matched[1] == NULL)
  1406.     return 0;
  1407.   for (i = 1; matched[i] != NULL; i++)
  1408.     {
  1409.       s1 = matched[i - 1];
  1410.       s2 = matched[i];
  1411.       for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
  1412. if (c1 != c2)
  1413.   break;
  1414.       if (lcd < 0)
  1415. lcd = j;
  1416.       else
  1417. {
  1418.   if (lcd > j)
  1419.     lcd = j;
  1420. }
  1421.     }
  1422.   return lcd;
  1423. }
  1424. /* Command line completion support. */
  1425. char **
  1426. cmd_complete_command (vector vline, struct vty *vty, int *status)
  1427. {
  1428.   int i;
  1429.   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1430. #define INIT_MATCHVEC_SIZE 10
  1431.   vector matchvec;
  1432.   struct cmd_element *cmd_element;
  1433.   int index = vector_max (vline) - 1;
  1434.   char **match_str;
  1435.   struct desc *desc;
  1436.   vector descvec;
  1437.   char *command;
  1438.   int lcd;
  1439.   /* First, filter by preceeding command string */
  1440.   for (i = 0; i < index; i++)
  1441.     {
  1442.       enum match_type match;
  1443.       int ret;
  1444.       command = vector_slot (vline, i);
  1445.       /* First try completion match, if there is exactly match return 1 */
  1446.       match = cmd_filter_by_completion (command, cmd_vector, i);
  1447.       /* If there is exact match then filter ambiguous match else check
  1448.  ambiguousness. */
  1449.       if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
  1450. {
  1451.   vector_free (cmd_vector);
  1452.   *status = CMD_ERR_AMBIGUOUS;
  1453.   return NULL;
  1454. }
  1455.       /*
  1456. else if (ret == 2)
  1457. {
  1458.   vector_free (cmd_vector);
  1459.   *status = CMD_ERR_NO_MATCH;
  1460.   return NULL;
  1461. }
  1462.       */
  1463.     }
  1464.   /* Prepare match vector. */
  1465.   matchvec = vector_init (INIT_MATCHVEC_SIZE);
  1466.   /* Now we got into completion */
  1467.   for (i = 0; i < vector_max (cmd_vector); i++)
  1468.     if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
  1469.       {
  1470. char *string;
  1471. vector strvec = cmd_element->strvec;
  1472. /* Check field length */
  1473. if (index >= vector_max (strvec))
  1474.   vector_slot (cmd_vector, i) = NULL;
  1475. else 
  1476.   {
  1477.     int j;
  1478.     descvec = vector_slot (strvec, index);
  1479.     for (j = 0; j < vector_max (descvec); j++)
  1480.       {
  1481. desc = vector_slot (descvec, j);
  1482. if ((string = cmd_entry_function (vector_slot (vline, index),
  1483.   desc->cmd)))
  1484.   if (cmd_unique_string (matchvec, string))
  1485.     vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
  1486.       }
  1487.   }
  1488.       }
  1489.   /* We don't need cmd_vector any more. */
  1490.   vector_free (cmd_vector);
  1491.   /* No matched command */
  1492.   if (vector_slot (matchvec, 0) == NULL)
  1493.     {
  1494.       vector_free (matchvec);
  1495.       /* In case of 'command t' pattern.  Do you need '?' command at
  1496.          the end of the line. */
  1497.       if (vector_slot (vline, index) == '')
  1498. *status = CMD_ERR_NOTHING_TODO;
  1499.       else
  1500. *status = CMD_ERR_NO_MATCH;
  1501.       return NULL;
  1502.     }
  1503.   /* Only one matched */
  1504.   if (vector_slot (matchvec, 1) == NULL)
  1505.     {
  1506.       match_str = (char **) matchvec->index;
  1507.       vector_only_wrapper_free (matchvec);
  1508.       *status = CMD_COMPLETE_FULL_MATCH;
  1509.       return match_str;
  1510.     }
  1511.   /* Make it sure last element is NULL. */
  1512.   vector_set (matchvec, NULL);
  1513.   /* Check LCD of matched strings. */
  1514.   if (vector_slot (vline, index) != NULL)
  1515.     {
  1516.       lcd = cmd_lcd ((char **) matchvec->index);
  1517.       if (lcd)
  1518. {
  1519.   int len = strlen (vector_slot (vline, index));
  1520.   
  1521.   if (len < lcd)
  1522.     {
  1523.       char *lcdstr;
  1524.       
  1525.       lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
  1526.       memcpy (lcdstr, matchvec->index[0], lcd);
  1527.       lcdstr[lcd] = '';
  1528.       /* match_str = (char **) &lcdstr; */
  1529.       /* Free matchvec. */
  1530.       for (i = 0; i < vector_max (matchvec); i++)
  1531. {
  1532.   if (vector_slot (matchvec, i))
  1533.     XFREE (MTYPE_TMP, vector_slot (matchvec, i));
  1534. }
  1535.       vector_free (matchvec);
  1536.              /* Make new matchvec. */
  1537.       matchvec = vector_init (INIT_MATCHVEC_SIZE);
  1538.       vector_set (matchvec, lcdstr);
  1539.       match_str = (char **) matchvec->index;
  1540.       vector_only_wrapper_free (matchvec);
  1541.       *status = CMD_COMPLETE_MATCH;
  1542.       return match_str;
  1543.     }
  1544. }
  1545.     }
  1546.   match_str = (char **) matchvec->index;
  1547.   vector_only_wrapper_free (matchvec);
  1548.   *status = CMD_COMPLETE_LIST_MATCH;
  1549.   return match_str;
  1550. }
  1551. /* Execute command by argument vline vector. */
  1552. int
  1553. cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd)
  1554. {
  1555.   int i;
  1556.   int index;
  1557.   vector cmd_vector;
  1558.   struct cmd_element *cmd_element;
  1559.   struct cmd_element *matched_element;
  1560.   unsigned int matched_count, incomplete_count;
  1561.   int argc;
  1562.   char *argv[CMD_ARGC_MAX];
  1563.   enum match_type match = 0;
  1564.   int varflag;
  1565.   char *command;
  1566.   /* Make copy of command elements. */
  1567.   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1568.   for (index = 0; index < vector_max (vline); index++) 
  1569.     {
  1570.       int ret;
  1571.       command = vector_slot (vline, index);
  1572.       match = cmd_filter_by_completion (command, cmd_vector, index);
  1573.       if (match == vararg_match)
  1574. break;
  1575.       ret = is_cmd_ambiguous (command, cmd_vector, index, match);
  1576.       if (ret == 1)
  1577. {
  1578.   vector_free (cmd_vector);
  1579.   return CMD_ERR_AMBIGUOUS;
  1580. }
  1581.       else if (ret == 2)
  1582. {
  1583.   vector_free (cmd_vector);
  1584.   return CMD_ERR_NO_MATCH;
  1585. }
  1586.     }
  1587.   /* Check matched count. */
  1588.   matched_element = NULL;
  1589.   matched_count = 0;
  1590.   incomplete_count = 0;
  1591.   for (i = 0; i < vector_max (cmd_vector); i++) 
  1592.     if (vector_slot (cmd_vector,i) != NULL)
  1593.       {
  1594. cmd_element = vector_slot (cmd_vector,i);
  1595. if (match == vararg_match || index >= cmd_element->cmdsize)
  1596.   {
  1597.     matched_element = cmd_element;
  1598. #if 0
  1599.     printf ("DEBUG: %sn", cmd_element->string);
  1600. #endif
  1601.     matched_count++;
  1602.   }
  1603. else
  1604.   {
  1605.     incomplete_count++;
  1606.   }
  1607.       }
  1608.   
  1609.   /* Finish of using cmd_vector. */
  1610.   vector_free (cmd_vector);
  1611.   /* To execute command, matched_count must be 1.*/
  1612.   if (matched_count == 0) 
  1613.     {
  1614.       if (incomplete_count)
  1615. return CMD_ERR_INCOMPLETE;
  1616.       else
  1617. return CMD_ERR_NO_MATCH;
  1618.     }
  1619.   if (matched_count > 1) 
  1620.     return CMD_ERR_AMBIGUOUS;
  1621.   /* Argument treatment */
  1622.   varflag = 0;
  1623.   argc = 0;
  1624.   for (i = 0; i < vector_max (vline); i++)
  1625.     {
  1626.       if (varflag)
  1627. argv[argc++] = vector_slot (vline, i);
  1628.       else
  1629. {   
  1630.   vector descvec = vector_slot (matched_element->strvec, i);
  1631.   if (vector_max (descvec) == 1)
  1632.     {
  1633.       struct desc *desc = vector_slot (descvec, 0);
  1634.       char *str = desc->cmd;
  1635.       if (CMD_VARARG (str))
  1636. varflag = 1;
  1637.       if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
  1638. argv[argc++] = vector_slot (vline, i);
  1639.     }
  1640.   else
  1641.     argv[argc++] = vector_slot (vline, i);
  1642. }
  1643.       if (argc >= CMD_ARGC_MAX)
  1644. return CMD_ERR_EXEED_ARGC_MAX;
  1645.     }
  1646.   /* For vtysh execution. */
  1647.   if (cmd)
  1648.     *cmd = matched_element;
  1649.   if (matched_element->daemon)
  1650.     return CMD_SUCCESS_DAEMON;
  1651.   /* Execute matched command. */
  1652.   return (*matched_element->func) (matched_element, vty, argc, argv);
  1653. }
  1654. /* Execute command by argument readline. */
  1655. int
  1656. cmd_execute_command_strict (vector vline, struct vty *vty, 
  1657.     struct cmd_element **cmd)
  1658. {
  1659.   int i;
  1660.   int index;
  1661.   vector cmd_vector;
  1662.   struct cmd_element *cmd_element;
  1663.   struct cmd_element *matched_element;
  1664.   unsigned int matched_count, incomplete_count;
  1665.   int argc;
  1666.   char *argv[CMD_ARGC_MAX];
  1667.   int varflag;
  1668.   enum match_type match = 0;
  1669.   char *command;
  1670.   /* Make copy of command element */
  1671.   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1672.   for (index = 0; index < vector_max (vline); index++) 
  1673.     {
  1674.       int ret;
  1675.       command = vector_slot (vline, index);
  1676.       match = cmd_filter_by_string (vector_slot (vline, index), 
  1677.     cmd_vector, index);
  1678.       /* If command meets '.VARARG' then finish matching. */
  1679.       if (match == vararg_match)
  1680. break;
  1681.       ret = is_cmd_ambiguous (command, cmd_vector, index, match);
  1682.       if (ret == 1)
  1683. {
  1684.   vector_free (cmd_vector);
  1685.   return CMD_ERR_AMBIGUOUS;
  1686. }
  1687.       if (ret == 2)
  1688. {
  1689.   vector_free (cmd_vector);
  1690.   return CMD_ERR_NO_MATCH;
  1691. }
  1692.     }
  1693.   /* Check matched count. */
  1694.   matched_element = NULL;
  1695.   matched_count = 0;
  1696.   incomplete_count = 0;
  1697.   for (i = 0; i < vector_max (cmd_vector); i++) 
  1698.     if (vector_slot (cmd_vector,i) != NULL)
  1699.       {
  1700. cmd_element = vector_slot (cmd_vector,i);
  1701. if (match == vararg_match || index >= cmd_element->cmdsize)
  1702.   {
  1703.     matched_element = cmd_element;
  1704.     matched_count++;
  1705.   }
  1706. else
  1707.   incomplete_count++;
  1708.       }
  1709.   
  1710.   /* Finish of using cmd_vector. */
  1711.   vector_free (cmd_vector);
  1712.   /* To execute command, matched_count must be 1.*/
  1713.   if (matched_count == 0) 
  1714.     {
  1715.       if (incomplete_count)
  1716. return CMD_ERR_INCOMPLETE;
  1717.       else
  1718. return CMD_ERR_NO_MATCH;
  1719.     }
  1720.   if (matched_count > 1) 
  1721.     return CMD_ERR_AMBIGUOUS;
  1722.   /* Argument treatment */
  1723.   varflag = 0;
  1724.   argc = 0;
  1725.   for (i = 0; i < vector_max (vline); i++)
  1726.     {
  1727.       if (varflag)
  1728. argv[argc++] = vector_slot (vline, i);
  1729.       else
  1730. {   
  1731.   vector descvec = vector_slot (matched_element->strvec, i);
  1732.   if (vector_max (descvec) == 1)
  1733.     {
  1734.       struct desc *desc = vector_slot (descvec, 0);
  1735.       char *str = desc->cmd;
  1736.       if (CMD_VARARG (str))
  1737. varflag = 1;
  1738.   
  1739.       if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
  1740. argv[argc++] = vector_slot (vline, i);
  1741.     }
  1742.   else
  1743.     argv[argc++] = vector_slot (vline, i);
  1744. }
  1745.       if (argc >= CMD_ARGC_MAX)
  1746. return CMD_ERR_EXEED_ARGC_MAX;
  1747.     }
  1748.   /* For vtysh execution. */
  1749.   if (cmd)
  1750.     *cmd = matched_element;
  1751.   if (matched_element->daemon)
  1752.     return CMD_SUCCESS_DAEMON;
  1753.   /* Now execute matched command */
  1754.   return (*matched_element->func) (matched_element, vty, argc, argv);
  1755. }
  1756. /* Configration make from file. */
  1757. int
  1758. config_from_file (struct vty *vty, FILE *fp)
  1759. {
  1760.   int ret;
  1761.   vector vline;
  1762.   while (fgets (vty->buf, VTY_BUFSIZ, fp))
  1763.     {
  1764.       vline = cmd_make_strvec (vty->buf);
  1765.       /* In case of comment line */
  1766.       if (vline == NULL)
  1767. continue;
  1768.       /* Execute configuration command : this is strict match */
  1769.       ret = cmd_execute_command_strict (vline, vty, NULL);
  1770.       /* Try again with setting node to CONFIG_NODE */
  1771.       if (ret != CMD_SUCCESS && ret != CMD_WARNING)
  1772. {
  1773.   if (vty->node == KEYCHAIN_KEY_NODE)
  1774.     {
  1775.       vty->node = KEYCHAIN_NODE;
  1776.       ret = cmd_execute_command_strict (vline, vty, NULL);
  1777.       if (ret != CMD_SUCCESS && ret != CMD_WARNING)
  1778. {
  1779.   vty->node = CONFIG_NODE;
  1780.   ret = cmd_execute_command_strict (vline, vty, NULL);
  1781. }
  1782.     }
  1783.   else
  1784.     {
  1785.       vty->node = CONFIG_NODE;
  1786.       ret = cmd_execute_command_strict (vline, vty, NULL);
  1787.     }
  1788. }   
  1789.       cmd_free_strvec (vline);
  1790.       if (ret != CMD_SUCCESS && ret != CMD_WARNING)
  1791. return ret;
  1792.     }
  1793.   return CMD_SUCCESS;
  1794. }
  1795. /* Configration from terminal */
  1796. DEFUN (config_terminal,
  1797.        config_terminal_cmd,
  1798.        "configure terminal",
  1799.        "Configuration from vty interfacen"
  1800.        "Configuration terminaln")
  1801. {
  1802.   if (vty_config_lock (vty))
  1803.     vty->node = CONFIG_NODE;
  1804.   else
  1805.     {
  1806.       vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
  1807.       return CMD_WARNING;
  1808.     }
  1809.   return CMD_SUCCESS;
  1810. }
  1811. /* Enable command */
  1812. DEFUN (enable, 
  1813.        config_enable_cmd,
  1814.        "enable",
  1815.        "Turn on privileged mode commandn")
  1816. {
  1817.   /* If enable password is NULL, change to ENABLE_NODE */
  1818.   if ((host.enable == NULL && host.enable_encrypt == NULL) ||
  1819.       vty->type == VTY_SHELL_SERV)
  1820.     vty->node = ENABLE_NODE;
  1821.   else
  1822.     vty->node = AUTH_ENABLE_NODE;
  1823.   return CMD_SUCCESS;
  1824. }
  1825. /* Disable command */
  1826. DEFUN (disable, 
  1827.        config_disable_cmd,
  1828.        "disable",
  1829.        "Turn off privileged mode commandn")
  1830. {
  1831.   if (vty->node == ENABLE_NODE)
  1832.     vty->node = VIEW_NODE;
  1833.   return CMD_SUCCESS;
  1834. }
  1835. /* Down vty node level. */
  1836. DEFUN (config_exit,
  1837.        config_exit_cmd,
  1838.        "exit",
  1839.        "Exit current mode and down to previous moden")
  1840. {
  1841.   switch (vty->node)
  1842.     {
  1843.     case VIEW_NODE:
  1844.     case ENABLE_NODE:
  1845.       if (vty_shell (vty))
  1846. exit (0);
  1847.       else
  1848. vty->status = VTY_CLOSE;
  1849.       break;
  1850.     case CONFIG_NODE:
  1851.       vty->node = ENABLE_NODE;
  1852.       vty_config_unlock (vty);
  1853.       break;
  1854.     case INTERFACE_NODE:
  1855.     case ZEBRA_NODE:
  1856.     case BGP_NODE:
  1857.     case RIP_NODE:
  1858.     case RIPNG_NODE:
  1859.     case OSPF_NODE:
  1860.     case OSPF6_NODE:
  1861.     case KEYCHAIN_NODE:
  1862.     case MASC_NODE:
  1863.     case RMAP_NODE:
  1864.     case VTY_NODE:
  1865.       vty->node = CONFIG_NODE;
  1866.       break;
  1867.     case BGP_VPNV4_NODE:
  1868.     case BGP_IPV4_NODE:
  1869.     case BGP_IPV4M_NODE:
  1870.     case BGP_IPV6_NODE:
  1871.       vty->node = BGP_NODE;
  1872.       break;
  1873.     case KEYCHAIN_KEY_NODE:
  1874.       vty->node = KEYCHAIN_NODE;
  1875.       break;
  1876.     default:
  1877.       break;
  1878.     }
  1879.   return CMD_SUCCESS;
  1880. }
  1881. /* quit is alias of exit. */
  1882. ALIAS (config_exit,
  1883.        config_quit_cmd,
  1884.        "quit",
  1885.        "Exit current mode and down to previous moden");
  1886.        
  1887. /* End of configuration. */
  1888. DEFUN (config_end,
  1889.        config_end_cmd,
  1890.        "end",
  1891.        "End current mode and change to enable mode.")
  1892. {
  1893.   switch (vty->node)
  1894.     {
  1895.     case VIEW_NODE:
  1896.     case ENABLE_NODE:
  1897.       /* Nothing to do. */
  1898.       break;
  1899.     case CONFIG_NODE:
  1900.     case INTERFACE_NODE:
  1901.     case ZEBRA_NODE:
  1902.     case RIP_NODE:
  1903.     case RIPNG_NODE:
  1904.     case BGP_NODE:
  1905.     case BGP_VPNV4_NODE:
  1906.     case BGP_IPV4_NODE:
  1907.     case BGP_IPV4M_NODE:
  1908.     case BGP_IPV6_NODE:
  1909.     case RMAP_NODE:
  1910.     case OSPF_NODE:
  1911.     case OSPF6_NODE:
  1912.     case KEYCHAIN_NODE:
  1913.     case KEYCHAIN_KEY_NODE:
  1914.     case MASC_NODE:
  1915.     case VTY_NODE:
  1916.       vty_config_unlock (vty);
  1917.       vty->node = ENABLE_NODE;
  1918.       break;
  1919.     default:
  1920.       break;
  1921.     }
  1922.   return CMD_SUCCESS;
  1923. }
  1924. /* Show version. */
  1925. DEFUN (show_version,
  1926.        show_version_cmd,
  1927.        "show version",
  1928.        SHOW_STR
  1929.        "Displays zebra versionn")
  1930. {
  1931.   vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
  1932.    host_name,
  1933.    VTY_NEWLINE);
  1934.   vty_out (vty, "Copyright 1996-2004, Kunihiro Ishiguro.%s", VTY_NEWLINE);
  1935.   return CMD_SUCCESS;
  1936. }
  1937. /* Help display function for all node. */
  1938. DEFUN (config_help,
  1939.        config_help_cmd,
  1940.        "help",
  1941.        "Description of the interactive help systemn")
  1942. {
  1943.   vty_out (vty, 
  1944.    "Zebra VTY provides advanced help feature.  When you need help,%s
  1945. anytime at the command line please press '?'.%s
  1946. %s
  1947. If nothing matches, the help list will be empty and you must backup%s
  1948.  until entering a '?' shows the available options.%s
  1949. Two styles of help are provided:%s
  1950. 1. Full help is available when you are ready to enter a%s
  1951. command argument (e.g. 'show ?') and describes each possible%s
  1952. argument.%s
  1953. 2. Partial help is provided when an abbreviated argument is entered%s
  1954.    and you want to know what arguments match the input%s
  1955.    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
  1956.    VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
  1957.    VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
  1958.   return CMD_SUCCESS;
  1959. }
  1960. /* Help display function for all node. */
  1961. DEFUN (config_list,
  1962.        config_list_cmd,
  1963.        "list",
  1964.        "Print command listn")
  1965. {
  1966.   int i;
  1967.   struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
  1968.   struct cmd_element *cmd;
  1969.   for (i = 0; i < vector_max (cnode->cmd_vector); i++)
  1970.     if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
  1971.       vty_out (vty, "  %s%s", cmd->string,
  1972.        VTY_NEWLINE);
  1973.   return CMD_SUCCESS;
  1974. }
  1975. /* Write current configuration into file. */
  1976. DEFUN (config_write_file, 
  1977.        config_write_file_cmd,
  1978.        "write file",  
  1979.        "Write running configuration to memory, network, or terminaln"
  1980.        "Write to configuration filen")
  1981. {
  1982.   int i;
  1983.   int fd;
  1984.   struct cmd_node *node;
  1985.   char *config_file;
  1986.   char *config_file_tmp = NULL;
  1987.   char *config_file_sav = NULL;
  1988.   struct vty *file_vty;
  1989.   /* Check and see if we are operating under vtysh configuration */
  1990.   if (host.config == NULL)
  1991.     {
  1992.       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
  1993.        VTY_NEWLINE);
  1994.       return CMD_WARNING;
  1995.     }
  1996.   /* Get filename. */
  1997.   config_file = host.config;
  1998.   
  1999.   config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
  2000.   strcpy (config_file_sav, config_file);
  2001.   strcat (config_file_sav, CONF_BACKUP_EXT);
  2002.   config_file_tmp = malloc (strlen (config_file) + 8);
  2003.   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
  2004.   
  2005.   /* Open file to configuration write. */
  2006.   fd = mkstemp (config_file_tmp);
  2007.   if (fd < 0)
  2008.     {
  2009.       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
  2010.        VTY_NEWLINE);
  2011.       free (config_file_tmp);
  2012.       free (config_file_sav);
  2013.       return CMD_WARNING;
  2014.     }
  2015.   
  2016.   /* Make vty for configuration file. */
  2017.   file_vty = vty_new ();
  2018.   file_vty->fd = fd;
  2019.   file_vty->type = VTY_FILE;
  2020.   /* Config file header print. */
  2021.   vty_out (file_vty, "!n! Zebra configuration saved from vtyn!   ");
  2022.   vty_time_print (file_vty, 1);
  2023.   vty_out (file_vty, "!n");
  2024.   for (i = 0; i < vector_max (cmdvec); i++)
  2025.     if ((node = vector_slot (cmdvec, i)) && node->func)
  2026.       {
  2027. if ((*node->func) (file_vty))
  2028.   vty_out (file_vty, "!n");
  2029.       }
  2030.   vty_close (file_vty);
  2031.   if (unlink (config_file_sav) != 0)
  2032.     if (errno != ENOENT)
  2033.       {
  2034. vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
  2035.  VTY_NEWLINE);
  2036. free (config_file_sav);
  2037. free (config_file_tmp);
  2038. unlink (config_file_tmp);
  2039. return CMD_WARNING;
  2040.       }
  2041.   if (link (config_file, config_file_sav) != 0)
  2042.     {
  2043.       vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
  2044.         VTY_NEWLINE);
  2045.       free (config_file_sav);
  2046.       free (config_file_tmp);
  2047.       unlink (config_file_tmp);
  2048.       return CMD_WARNING;
  2049.     }
  2050.   sync ();
  2051.   if (unlink (config_file) != 0)
  2052.     {
  2053.       vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
  2054.         VTY_NEWLINE);
  2055.       free (config_file_sav);
  2056.       free (config_file_tmp);
  2057.       unlink (config_file_tmp);
  2058.       return CMD_WARNING;      
  2059.     }
  2060.   if (link (config_file_tmp, config_file) != 0)
  2061.     {
  2062.       vty_out (vty, "Can't save configuration file %s.%s", config_file,
  2063.        VTY_NEWLINE);
  2064.       free (config_file_sav);
  2065.       free (config_file_tmp);
  2066.       unlink (config_file_tmp);
  2067.       return CMD_WARNING;      
  2068.     }
  2069.   unlink (config_file_tmp);
  2070.   sync ();
  2071.   
  2072.   free (config_file_sav);
  2073.   free (config_file_tmp);
  2074.   vty_out (vty, "Configuration saved to %s%s", config_file,
  2075.    VTY_NEWLINE);
  2076.   return CMD_SUCCESS;
  2077. }
  2078. ALIAS (config_write_file, 
  2079.        config_write_cmd,
  2080.        "write",  
  2081.        "Write running configuration to memory, network, or terminaln");
  2082. ALIAS (config_write_file, 
  2083.        config_write_memory_cmd,
  2084.        "write memory",  
  2085.        "Write running configuration to memory, network, or terminaln"
  2086.        "Write configuration to the file (same as write file)n");
  2087. ALIAS (config_write_file, 
  2088.        copy_runningconfig_startupconfig_cmd,
  2089.        "copy running-config startup-config",  
  2090.        "Copy configurationn"
  2091.        "Copy running config to... n"
  2092.        "Copy running config to startup config (same as write file)n");
  2093. /* Write current configuration into the terminal. */
  2094. DEFUN (config_write_terminal,
  2095.        config_write_terminal_cmd,
  2096.        "write terminal",
  2097.        "Write running configuration to memory, network, or terminaln"
  2098.        "Write to terminaln")
  2099. {
  2100.   int i;
  2101.   struct cmd_node *node;
  2102.   if (vty->type == VTY_SHELL_SERV)
  2103.     {
  2104.       for (i = 0; i < vector_max (cmdvec); i++)
  2105. if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
  2106.   {
  2107.     if ((*node->func) (vty))
  2108.       vty_out (vty, "!%s", VTY_NEWLINE);
  2109.   }
  2110.     }
  2111.   else
  2112.     {
  2113.       vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
  2114.        VTY_NEWLINE);
  2115.       vty_out (vty, "!%s", VTY_NEWLINE);
  2116.       for (i = 0; i < vector_max (cmdvec); i++)
  2117. if ((node = vector_slot (cmdvec, i)) && node->func)
  2118.   {
  2119.     if ((*node->func) (vty))
  2120.       vty_out (vty, "!%s", VTY_NEWLINE);
  2121.   }
  2122.       vty_out (vty, "end%s",VTY_NEWLINE);
  2123.     }
  2124.   return CMD_SUCCESS;
  2125. }
  2126. /* Write current configuration into the terminal. */
  2127. ALIAS (config_write_terminal,
  2128.        show_running_config_cmd,
  2129.        "show running-config",
  2130.        SHOW_STR
  2131.        "running configurationn");
  2132. /* Write startup configuration into the terminal. */
  2133. DEFUN (show_startup_config,
  2134.        show_startup_config_cmd,
  2135.        "show startup-config",
  2136.        SHOW_STR
  2137.        "Contentes of startup configurationn")
  2138. {
  2139.   char buf[BUFSIZ];
  2140.   FILE *confp;
  2141.   confp = fopen (host.config, "r");
  2142.   if (confp == NULL)
  2143.     {
  2144.       vty_out (vty, "Can't open configuration file [%s]%s",
  2145.        host.config, VTY_NEWLINE);
  2146.       return CMD_WARNING;
  2147.     }
  2148.   while (fgets (buf, BUFSIZ, confp))
  2149.     {
  2150.       char *cp = buf;
  2151.       while (*cp != 'r' && *cp != 'n' && *cp != '')
  2152. cp++;
  2153.       *cp = '';
  2154.       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
  2155.     }
  2156.   fclose (confp);
  2157.   return CMD_SUCCESS;
  2158. }
  2159. /* Hostname configuration */
  2160. DEFUN (config_hostname, 
  2161.        hostname_cmd,
  2162.        "hostname WORD",
  2163.        "Set system's network namen"
  2164.        "This system's network namen")
  2165. {
  2166.   if (!isalpha((int) *argv[0]))
  2167.     {
  2168.       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
  2169.       return CMD_WARNING;
  2170.     }
  2171.   if (host.name)
  2172.     XFREE (0, host.name);
  2173.     
  2174.   host.name = strdup (argv[0]);
  2175.   return CMD_SUCCESS;
  2176. }
  2177. DEFUN (config_no_hostname, 
  2178.        no_hostname_cmd,
  2179.        "no hostname [HOSTNAME]",
  2180.        NO_STR
  2181.        "Reset system's network namen"
  2182.        "Host name of this routern")
  2183. {
  2184.   if (host.name)
  2185.     XFREE (0, host.name);
  2186.   host.name = NULL;
  2187.   return CMD_SUCCESS;
  2188. }
  2189. /* VTY interface password set. */
  2190. DEFUN (config_password, password_cmd,
  2191.        "password (8|) WORD",
  2192.        "Assign the terminal connection passwordn"
  2193.        "Specifies a HIDDEN password will follown"
  2194.        "dummy string n"
  2195.        "The HIDDEN line password stringn")
  2196. {
  2197.   /* Argument check. */
  2198.   if (argc == 0)
  2199.     {
  2200.       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
  2201.       return CMD_WARNING;
  2202.     }
  2203.   if (argc == 2)
  2204.     {
  2205.       if (*argv[0] == '8')
  2206. {
  2207.   if (host.password)
  2208.     XFREE (0, host.password);
  2209.   host.password = NULL;
  2210.   if (host.password_encrypt)
  2211.     XFREE (0, host.password_encrypt);
  2212.   host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
  2213.   return CMD_SUCCESS;
  2214. }
  2215.       else
  2216. {
  2217.   vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
  2218.   return CMD_WARNING;
  2219. }
  2220.     }
  2221.   if (!isalnum ((int) *argv[0]))
  2222.     {
  2223.       vty_out (vty, 
  2224.        "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
  2225.       return CMD_WARNING;
  2226.     }
  2227.   if (host.password)
  2228.     XFREE (0, host.password);
  2229.   host.password = NULL;
  2230.   if (host.password_encrypt)
  2231.     XFREE (0, host.password_encrypt);
  2232.   host.password_encrypt = NULL;
  2233.   if (host.encrypt)
  2234.     host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
  2235.   else
  2236.     host.password = XSTRDUP (0, argv[0]);
  2237.   return CMD_SUCCESS;
  2238. }
  2239. ALIAS (config_password, password_text_cmd,
  2240.        "password LINE",
  2241.        "Assign the terminal connection passwordn"
  2242.        "The UNENCRYPTED (cleartext) line passwordn");
  2243. /* VTY enable password set. */
  2244. DEFUN (config_enable_password, enable_password_cmd,
  2245.        "enable password (8|) WORD",
  2246.        "Modify enable password parametersn"
  2247.        "Assign the privileged level passwordn"
  2248.        "Specifies a HIDDEN password will follown"
  2249.        "dummy string n"
  2250.        "The HIDDEN 'enable' password stringn")
  2251. {
  2252.   /* Argument check. */
  2253.   if (argc == 0)
  2254.     {
  2255.       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
  2256.       return CMD_WARNING;
  2257.     }
  2258.   /* Crypt type is specified. */
  2259.   if (argc == 2)
  2260.     {
  2261.       if (*argv[0] == '8')
  2262. {
  2263.   if (host.enable)
  2264.     XFREE (0, host.enable);
  2265.   host.enable = NULL;
  2266.   if (host.enable_encrypt)
  2267.     XFREE (0, host.enable_encrypt);
  2268.   host.enable_encrypt = XSTRDUP (0, argv[1]);
  2269.   return CMD_SUCCESS;
  2270. }
  2271.       else
  2272. {
  2273.   vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
  2274.   return CMD_WARNING;
  2275. }
  2276.     }
  2277.   if (!isalnum ((int) *argv[0]))
  2278.     {
  2279.       vty_out (vty, 
  2280.        "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
  2281.       return CMD_WARNING;
  2282.     }
  2283.   if (host.enable)
  2284.     XFREE (0, host.enable);
  2285.   host.enable = NULL;
  2286.   if (host.enable_encrypt)
  2287.     XFREE (0, host.enable_encrypt);
  2288.   host.enable_encrypt = NULL;
  2289.   /* Plain password input. */
  2290.   if (host.encrypt)
  2291.     host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
  2292.   else
  2293.     host.enable = XSTRDUP (0, argv[0]);
  2294.   return CMD_SUCCESS;
  2295. }
  2296. ALIAS (config_enable_password,
  2297.        enable_password_text_cmd,
  2298.        "enable password LINE",
  2299.        "Modify enable password parametersn"
  2300.        "Assign the privileged level passwordn"
  2301.        "The UNENCRYPTED (cleartext) 'enable' passwordn");
  2302. /* VTY enable password delete. */
  2303. DEFUN (no_config_enable_password, no_enable_password_cmd,
  2304.        "no enable password",
  2305.        NO_STR
  2306.        "Modify enable password parametersn"
  2307.        "Assign the privileged level passwordn")
  2308. {
  2309.   if (host.enable)
  2310.     XFREE (0, host.enable);
  2311.   host.enable = NULL;
  2312.   if (host.enable_encrypt)
  2313.     XFREE (0, host.enable_encrypt);
  2314.   host.enable_encrypt = NULL;
  2315.   return CMD_SUCCESS;
  2316. }
  2317. DEFUN (service_password_encrypt,
  2318.        service_password_encrypt_cmd,
  2319.        "service password-encryption",
  2320.        "Set up miscellaneous servicen"
  2321.        "Enable encrypted passwordsn")
  2322. {
  2323.   if (host.encrypt)
  2324.     return CMD_SUCCESS;
  2325.   host.encrypt = 1;
  2326.   if (host.password)
  2327.     {
  2328.       if (host.password_encrypt)
  2329. XFREE (0, host.password_encrypt);
  2330.       host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
  2331.     }
  2332.   if (host.enable)
  2333.     {
  2334.       if (host.enable_encrypt)
  2335. XFREE (0, host.enable_encrypt);
  2336.       host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
  2337.     }
  2338.   return CMD_SUCCESS;
  2339. }
  2340. DEFUN (no_service_password_encrypt,
  2341.        no_service_password_encrypt_cmd,
  2342.        "no service password-encryption",
  2343.        NO_STR
  2344.        "Set up miscellaneous servicen"
  2345.        "Enable encrypted passwordsn")
  2346. {
  2347.   if (! host.encrypt)
  2348.     return CMD_SUCCESS;
  2349.   host.encrypt = 0;
  2350.   if (host.password)
  2351.     {
  2352.       if (host.password_encrypt)
  2353. XFREE (0, host.password_encrypt);
  2354.       host.password_encrypt = NULL;
  2355.     }
  2356.   if (host.enable)
  2357.     {
  2358.       if (host.enable_encrypt)
  2359. XFREE (0, host.enable_encrypt);
  2360.       host.enable_encrypt = NULL;
  2361.     }
  2362.   return CMD_SUCCESS;
  2363. }
  2364. DEFUN (config_terminal_length, config_terminal_length_cmd,
  2365.        "terminal length <0-512>",
  2366.        "Set terminal line parametersn"
  2367.        "Set number of lines on a screenn"
  2368.        "Number of lines on screen (0 for no pausing)n")
  2369. {
  2370.   int lines;
  2371.   char *endptr = NULL;
  2372.   lines = strtol (argv[0], &endptr, 10);
  2373.   if (lines < 0 || lines > 512 || *endptr != '')
  2374.     {
  2375.       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
  2376.       return CMD_WARNING;
  2377.     }
  2378.   vty->lines = lines;
  2379.   return CMD_SUCCESS;
  2380. }
  2381. DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
  2382.        "terminal no length",
  2383.        "Set terminal line parametersn"
  2384.        NO_STR
  2385.        "Set number of lines on a screenn")
  2386. {
  2387.   vty->lines = -1;
  2388.   return CMD_SUCCESS;
  2389. }
  2390. DEFUN (service_terminal_length, service_terminal_length_cmd,
  2391.        "service terminal-length <0-512>",
  2392.        "Set up miscellaneous servicen"
  2393.        "System wide terminal length configurationn"
  2394.        "Number of lines of VTY (0 means no line control)n")
  2395. {
  2396.   int lines;
  2397.   char *endptr = NULL;
  2398.   lines = strtol (argv[0], &endptr, 10);
  2399.   if (lines < 0 || lines > 512 || *endptr != '')
  2400.     {
  2401.       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
  2402.       return CMD_WARNING;
  2403.     }
  2404.   host.lines = lines;
  2405.   return CMD_SUCCESS;
  2406. }
  2407. DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
  2408.        "no service terminal-length [<0-512>]",
  2409.        NO_STR
  2410.        "Set up miscellaneous servicen"
  2411.        "System wide terminal length configurationn"
  2412.        "Number of lines of VTY (0 means no line control)n")
  2413. {
  2414.   host.lines = -1;
  2415.   return CMD_SUCCESS;
  2416. }
  2417. DEFUN (config_log_stdout,
  2418.        config_log_stdout_cmd,
  2419.        "log stdout",
  2420.        "Logging controln"
  2421.        "Logging goes to stdoutn")
  2422. {
  2423.   zlog_set_flag (NULL, ZLOG_STDOUT);
  2424.   host.log_stdout = 1;
  2425.   return CMD_SUCCESS;
  2426. }
  2427. DEFUN (no_config_log_stdout,
  2428.        no_config_log_stdout_cmd,
  2429.        "no log stdout",
  2430.        NO_STR
  2431.        "Logging controln"
  2432.        "Cancel logging to stdoutn")
  2433. {
  2434.   zlog_reset_flag (NULL, ZLOG_STDOUT);
  2435.   host.log_stdout = 0;
  2436.   return CMD_SUCCESS;
  2437. }
  2438. DEFUN (config_log_file,
  2439.        config_log_file_cmd,
  2440.        "log file FILENAME",
  2441.        "Logging controln"
  2442.        "Logging to filen"
  2443.        "Logging filenamen")
  2444. {
  2445.   int ret;
  2446.   char *cwd;
  2447.   char *fullpath;
  2448.   /* Path detection. */
  2449.   if (! IS_DIRECTORY_SEP (*argv[0]))
  2450.     {
  2451.       cwd = getcwd (NULL, MAXPATHLEN);
  2452.       fullpath = XMALLOC (MTYPE_TMP,
  2453.   strlen (cwd) + strlen (argv[0]) + 2);
  2454.       sprintf (fullpath, "%s/%s", cwd, argv[0]);
  2455.     }
  2456.   else
  2457.     fullpath = argv[0];
  2458.   ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
  2459.   if (!ret)
  2460.     {
  2461.       vty_out (vty, "can't open logfile %sn", argv[0]);
  2462.       return CMD_WARNING;
  2463.     }
  2464.   if (host.logfile)
  2465.     XFREE (MTYPE_TMP, host.logfile);
  2466.   host.logfile = strdup (argv[0]);
  2467.   return CMD_SUCCESS;
  2468. }
  2469. DEFUN (no_config_log_file,
  2470.        no_config_log_file_cmd,
  2471.        "no log file [FILENAME]",
  2472.        NO_STR
  2473.        "Logging controln"
  2474.        "Cancel logging to filen"
  2475.        "Logging file namen")
  2476. {
  2477.   zlog_reset_file (NULL);
  2478.   if (host.logfile)
  2479.     XFREE (MTYPE_TMP, host.logfile);
  2480.   host.logfile = NULL;
  2481.   return CMD_SUCCESS;
  2482. }
  2483. DEFUN (config_log_syslog,
  2484.        config_log_syslog_cmd,
  2485.        "log syslog",
  2486.        "Logging controln"
  2487.        "Logging goes to syslogn")
  2488. {
  2489.   zlog_set_flag (NULL, ZLOG_SYSLOG);
  2490.   host.log_syslog = 1;
  2491.   zlog_default->facility = LOG_DAEMON;
  2492.   return CMD_SUCCESS;
  2493. }
  2494. DEFUN (config_log_syslog_facility,
  2495.        config_log_syslog_facility_cmd,
  2496.        "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
  2497.        "Logging controln"
  2498.        "Logging goes to syslogn"
  2499.        "Facility parameter for syslog messagesn"
  2500.        "Kerneln"
  2501.        "User processn"
  2502.        "Mail systemn"
  2503.        "System daemonsn"
  2504.        "Authorization systemn"
  2505.        "Syslog itselfn"
  2506.        "Line printer systemn"
  2507.        "USENET newsn"
  2508.        "Unix-to-Unix copy systemn"
  2509.        "Cron/at facilityn"
  2510.        "Local usen"
  2511.        "Local usen"
  2512.        "Local usen"
  2513.        "Local usen"
  2514.        "Local usen"
  2515.        "Local usen"
  2516.        "Local usen"
  2517.        "Local usen")
  2518. {
  2519.   int facility = LOG_DAEMON;
  2520.   zlog_set_flag (NULL, ZLOG_SYSLOG);
  2521.   host.log_syslog = 1;
  2522.   if (strncmp (argv[0], "kern", 1) == 0)
  2523.     facility = LOG_KERN;
  2524.   else if (strncmp (argv[0], "user", 2) == 0)
  2525.     facility = LOG_USER;
  2526.   else if (strncmp (argv[0], "mail", 1) == 0)
  2527.     facility = LOG_MAIL;
  2528.   else if (strncmp (argv[0], "daemon", 1) == 0)
  2529.     facility = LOG_DAEMON;
  2530.   else if (strncmp (argv[0], "auth", 1) == 0)
  2531.     facility = LOG_AUTH;
  2532.   else if (strncmp (argv[0], "syslog", 1) == 0)
  2533.     facility = LOG_SYSLOG;
  2534.   else if (strncmp (argv[0], "lpr", 2) == 0)
  2535.     facility = LOG_LPR;
  2536.   else if (strncmp (argv[0], "news", 1) == 0)
  2537.     facility = LOG_NEWS;
  2538.   else if (strncmp (argv[0], "uucp", 2) == 0)
  2539.     facility = LOG_UUCP;
  2540.   else if (strncmp (argv[0], "cron", 1) == 0)
  2541.     facility = LOG_CRON;
  2542.   else if (strncmp (argv[0], "local0", 6) == 0)
  2543.     facility = LOG_LOCAL0;
  2544.   else if (strncmp (argv[0], "local1", 6) == 0)
  2545.     facility = LOG_LOCAL1;
  2546.   else if (strncmp (argv[0], "local2", 6) == 0)
  2547.     facility = LOG_LOCAL2;
  2548.   else if (strncmp (argv[0], "local3", 6) == 0)
  2549.     facility = LOG_LOCAL3;
  2550.   else if (strncmp (argv[0], "local4", 6) == 0)
  2551.     facility = LOG_LOCAL4;
  2552.   else if (strncmp (argv[0], "local5", 6) == 0)
  2553.     facility = LOG_LOCAL5;
  2554.   else if (strncmp (argv[0], "local6", 6) == 0)
  2555.     facility = LOG_LOCAL6;
  2556.   else if (strncmp (argv[0], "local7", 6) == 0)
  2557.     facility = LOG_LOCAL7;
  2558.   zlog_default->facility = facility;
  2559.   return CMD_SUCCESS;
  2560. }
  2561. DEFUN (no_config_log_syslog,
  2562.        no_config_log_syslog_cmd,
  2563.        "no log syslog",
  2564.        NO_STR
  2565.        "Logging controln"
  2566.        "Cancel logging to syslogn")
  2567. {
  2568.   zlog_reset_flag (NULL, ZLOG_SYSLOG);
  2569.   host.log_syslog = 0;
  2570.   zlog_default->facility = LOG_DAEMON;
  2571.   return CMD_SUCCESS;
  2572. }
  2573. ALIAS (no_config_log_syslog,
  2574.        no_config_log_syslog_facility_cmd,
  2575.        "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
  2576.        NO_STR
  2577.        "Logging controln"
  2578.        "Logging goes to syslogn"
  2579.        "Facility parameter for syslog messagesn"
  2580.        "Kerneln"
  2581.        "User processn"
  2582.        "Mail systemn"
  2583.        "System daemonsn"
  2584.        "Authorization systemn"
  2585.        "Syslog itselfn"
  2586.        "Line printer systemn"
  2587.        "USENET newsn"
  2588.        "Unix-to-Unix copy systemn"
  2589.        "Cron/at facilityn"
  2590.        "Local usen"
  2591.        "Local usen"
  2592.        "Local usen"
  2593.        "Local usen"
  2594.        "Local usen"
  2595.        "Local usen"
  2596.        "Local usen"
  2597.        "Local usen");
  2598. DEFUN (config_log_trap,
  2599.        config_log_trap_cmd,
  2600.        "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
  2601.        "Logging controln"
  2602.        "Limit logging to specifed leveln")
  2603. {
  2604.   int new_level ;
  2605.   
  2606.   for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
  2607.     {
  2608.     if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
  2609.       /* found new logging level */
  2610.       {
  2611.       zlog_default->maskpri = new_level;
  2612.       return CMD_SUCCESS;
  2613.       }
  2614.     }
  2615.   return CMD_ERR_NO_MATCH;
  2616. }
  2617. DEFUN (no_config_log_trap,
  2618.        no_config_log_trap_cmd,
  2619.        "no log trap",
  2620.        NO_STR
  2621.        "Logging controln"
  2622.        "Permit all logging informationn")
  2623. {
  2624.   zlog_default->maskpri = LOG_DEBUG;
  2625.   return CMD_SUCCESS;
  2626. }
  2627. DEFUN (config_log_record_priority,
  2628.        config_log_record_priority_cmd,
  2629.        "log record-priority",
  2630.        "Logging controln"
  2631.        "Log the priority of the message within the messagen")
  2632. {
  2633.   zlog_default->record_priority = 1 ;
  2634.   return CMD_SUCCESS;
  2635. }
  2636. DEFUN (no_config_log_record_priority,
  2637.        no_config_log_record_priority_cmd,
  2638.        "no log record-priority",
  2639.        NO_STR
  2640.        "Logging controln"
  2641.        "Do not log the priority of the message within the messagen")
  2642. {
  2643.   zlog_default->record_priority = 0 ;
  2644.   return CMD_SUCCESS;
  2645. }
  2646. DEFUN (banner_motd_default,
  2647.        banner_motd_default_cmd,
  2648.        "banner motd default",
  2649.        "Set banner stringn"
  2650.        "Strings for motdn"
  2651.        "Default stringn")
  2652. {
  2653.   host.motd = default_motd;
  2654.   return CMD_SUCCESS;
  2655. }
  2656. DEFUN (no_banner_motd,
  2657.        no_banner_motd_cmd,
  2658.        "no banner motd",
  2659.        NO_STR
  2660.        "Set banner stringn"
  2661.        "Strings for motdn")
  2662. {
  2663.   host.motd = NULL;
  2664.   return CMD_SUCCESS;
  2665. }
  2666. /* Set config filename.  Called from vty.c */
  2667. void
  2668. host_config_set (char *filename)
  2669. {
  2670.   host.config = strdup (filename);
  2671. }
  2672. void
  2673. install_default (enum node_type node)
  2674. {
  2675.   install_element (node, &config_exit_cmd);
  2676.   install_element (node, &config_quit_cmd);
  2677.   install_element (node, &config_end_cmd);
  2678.   install_element (node, &config_help_cmd);
  2679.   install_element (node, &config_list_cmd);
  2680.   install_element (node, &config_write_terminal_cmd);
  2681.   install_element (node, &config_write_file_cmd);
  2682.   install_element (node, &config_write_memory_cmd);
  2683.   install_element (node, &config_write_cmd);
  2684.   install_element (node, &show_running_config_cmd);
  2685. }
  2686. /* Initialize command interface. Install basic nodes and commands. */
  2687. void
  2688. cmd_init (int terminal)
  2689. {
  2690.   /* Allocate initial top vector of commands. */
  2691.   cmdvec = vector_init (VECTOR_MIN_SIZE);
  2692.   /* Default host value settings. */
  2693.   host.name = NULL;
  2694.   host.password = NULL;
  2695.   host.enable = NULL;
  2696.   host.logfile = NULL;
  2697.   host.config = NULL;
  2698.   host.lines = -1;
  2699.   host.motd = default_motd;
  2700.   /* Install top nodes. */
  2701.   install_node (&view_node, NULL);
  2702.   install_node (&enable_node, NULL);
  2703.   install_node (&auth_node, NULL);
  2704.   install_node (&auth_enable_node, NULL);
  2705.   install_node (&config_node, config_write_host);
  2706.   /* Each node's basic commands. */
  2707.   install_element (VIEW_NODE, &show_version_cmd);
  2708.   if (terminal)
  2709.     {
  2710.       install_element (VIEW_NODE, &config_list_cmd);
  2711.       install_element (VIEW_NODE, &config_exit_cmd);
  2712.       install_element (VIEW_NODE, &config_quit_cmd);
  2713.       install_element (VIEW_NODE, &config_help_cmd);
  2714.       install_element (VIEW_NODE, &config_enable_cmd);
  2715.       install_element (VIEW_NODE, &config_terminal_length_cmd);
  2716.       install_element (VIEW_NODE, &config_terminal_no_length_cmd);
  2717.     }
  2718.   if (terminal)
  2719.     {
  2720.       install_default (ENABLE_NODE);
  2721.       install_element (ENABLE_NODE, &config_disable_cmd);
  2722.       install_element (ENABLE_NODE, &config_terminal_cmd);
  2723.       install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
  2724.     }
  2725.   install_element (ENABLE_NODE, &show_startup_config_cmd);
  2726.   install_element (ENABLE_NODE, &show_version_cmd);
  2727.   install_element (ENABLE_NODE, &config_terminal_length_cmd);
  2728.   install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
  2729.   if (terminal)
  2730.     install_default (CONFIG_NODE);
  2731.   install_element (CONFIG_NODE, &hostname_cmd);
  2732.   install_element (CONFIG_NODE, &no_hostname_cmd);
  2733.   install_element (CONFIG_NODE, &password_cmd);
  2734.   install_element (CONFIG_NODE, &password_text_cmd);
  2735.   install_element (CONFIG_NODE, &enable_password_cmd);
  2736.   install_element (CONFIG_NODE, &enable_password_text_cmd);
  2737.   install_element (CONFIG_NODE, &no_enable_password_cmd);
  2738.   if (terminal)
  2739.     {
  2740.       install_element (CONFIG_NODE, &config_log_stdout_cmd);
  2741.       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
  2742.       install_element (CONFIG_NODE, &config_log_file_cmd);
  2743.       install_element (CONFIG_NODE, &no_config_log_file_cmd);
  2744.       install_element (CONFIG_NODE, &config_log_syslog_cmd);
  2745.       install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
  2746.       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
  2747.       install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
  2748.       install_element (CONFIG_NODE, &config_log_trap_cmd);
  2749.       install_element (CONFIG_NODE, &no_config_log_trap_cmd);
  2750.       install_element (CONFIG_NODE, &config_log_record_priority_cmd);
  2751.       install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
  2752.       install_element (CONFIG_NODE, &service_password_encrypt_cmd);
  2753.       install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
  2754.       install_element (CONFIG_NODE, &banner_motd_default_cmd);
  2755.       install_element (CONFIG_NODE, &no_banner_motd_cmd);
  2756.       install_element (CONFIG_NODE, &service_terminal_length_cmd);
  2757.       install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
  2758.     }
  2759.   srand(time(NULL));
  2760. }