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

网络

开发平台:

Unix_Linux

  1. /*
  2.  * Virtual terminal [aka TeletYpe] interface routine.
  3.  * Copyright (C) 1997, 98 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 it
  8.  * under the terms of the GNU General Public License as published by the
  9.  * Free Software Foundation; either version 2, or (at your option) any
  10.  * 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 Free
  19.  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  20.  * 02111-1307, USA.  
  21.  */
  22. #include <zebra.h>
  23. #include "linklist.h"
  24. #include "buffer.h"
  25. #include "version.h"
  26. #include "command.h"
  27. #include "sockunion.h"
  28. #include "thread.h"
  29. #include "memory.h"
  30. #include "str.h"
  31. #include "log.h"
  32. #include "prefix.h"
  33. #include "filter.h"
  34. /* Vty events */
  35. enum event 
  36.   {
  37.     VTY_SERV,
  38.     VTY_READ,
  39.     VTY_WRITE,
  40.     VTY_TIMEOUT_RESET,
  41. #ifdef VTYSH
  42.     VTYSH_SERV,
  43.     VTYSH_READ
  44. #endif /* VTYSH */
  45.   };
  46. static void vty_event (enum event, int, struct vty *);
  47. /* Extern host structure from command.c */
  48. extern struct host host;
  49. /* Vector which store each vty structure. */
  50. static vector vtyvec;
  51. /* Vty timeout value. */
  52. static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
  53. /* Vty access-class command */
  54. static char *vty_accesslist_name = NULL;
  55. /* Vty access-calss for IPv6. */
  56. static char *vty_ipv6_accesslist_name = NULL;
  57. /* VTY server thread. */
  58. vector Vvty_serv_thread;
  59. /* Current directory. */
  60. char *vty_cwd = NULL;
  61. /* Configure lock. */
  62. static int vty_config;
  63. /* Login password check. */
  64. static int no_password_check = 0;
  65. /* Integrated configuration file path */
  66. char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
  67. /* VTY standard output function. */
  68. int
  69. vty_out (struct vty *vty, const char *format, ...)
  70. {
  71.   va_list args;
  72.   int len = 0;
  73.   int size = 1024;
  74.   char buf[1024];
  75.   char *p = NULL;
  76.   
  77.   va_start (args, format);
  78.   if (vty_shell (vty))
  79.     vprintf (format, args);
  80.   else
  81.     {
  82.       /* Try to write to initial buffer.  */
  83.       len = vsnprintf (buf, sizeof buf, format, args);
  84.       /* Initial buffer is not enough.  */
  85.       if (len < 0 || len >= size)
  86. {
  87.   while (1)
  88.     {
  89.       if (len > -1)
  90. size = len + 1;
  91.       else
  92. size = size * 2;
  93.       p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
  94.       if (! p)
  95. return -1;
  96.       len = vsnprintf (p, size, format, args);
  97.       if (len > -1 && len < size)
  98. break;
  99.     }
  100. }
  101.       /* When initial buffer is enough to store all output.  */
  102.       if (! p)
  103. p = buf;
  104.       /* Pointer p must point out buffer. */
  105.       if (vty_shell_serv (vty))
  106. write (vty->fd, (u_char *) p, len);
  107.       else
  108. buffer_write (vty->obuf, (u_char *) p, len);
  109.       /* If p is not different with buf, it is allocated buffer.  */
  110.       if (p != buf)
  111. XFREE (MTYPE_VTY_OUT_BUF, p);
  112.     }
  113.   va_end (args);
  114.   return len;
  115. }
  116. #define TIME_BUF 27
  117. /* current time string. */
  118. int
  119. time_str (char *buf)
  120. {
  121.   time_t clock;
  122.   struct tm *tm;
  123.   int ret;
  124.   time (&clock);
  125.   tm = localtime (&clock);
  126.   ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
  127.   return ret;
  128. }
  129. int
  130. vty_log_out (struct vty *vty, const char *proto_str, const char *format,
  131.      va_list va)
  132. {
  133.   int len;
  134.   int ret;
  135.   char buf[1024];
  136.   char time_buf[TIME_BUF];
  137.   ret = time_str (time_buf);
  138.   if (ret != 0)
  139.     {
  140.       snprintf (buf, sizeof buf, "%s ", time_buf);
  141.       write (vty->fd, buf, strlen (time_buf) + 1);
  142.     }
  143.   snprintf (buf, sizeof buf, "%s: ", proto_str);
  144.   write (vty->fd, buf, strlen (proto_str) + 2);
  145.   len = vsnprintf (buf, sizeof buf, format, va);
  146.   if (len < 0)
  147.     return -1;
  148.   write (vty->fd, (u_char *)buf, len);
  149.   snprintf (buf, sizeof buf, "rn");
  150.   write (vty->fd, buf, 2);
  151.   return len;
  152. }
  153. /* Output current time to the vty. */
  154. void
  155. vty_time_print (struct vty *vty, int cr)
  156. {
  157.   int ret;
  158.   char buf [TIME_BUF];
  159.  
  160.   ret = time_str (buf);
  161.   if (ret == 0)
  162.     {
  163.       zlog (NULL, LOG_INFO, "strftime error");
  164.       return;
  165.     }
  166.   if (cr)
  167.     vty_out (vty, "%sn", buf);
  168.   else
  169.     vty_out (vty, "%s ", buf);
  170.   return;
  171. }
  172. /* Say hello to vty interface. */
  173. void
  174. vty_hello (struct vty *vty)
  175. {
  176.   if (host.motd)
  177.     vty_out (vty, host.motd);
  178. }
  179. /* Put out prompt and wait input from user. */
  180. static void
  181. vty_prompt (struct vty *vty)
  182. {
  183.   struct utsname names;
  184.   const char*hostname;
  185.   if (vty->type == VTY_TERM)
  186.     {
  187.       hostname = host.name;
  188.       if (!hostname)
  189. {
  190.   uname (&names);
  191.   hostname = names.nodename;
  192. }
  193.       vty_out (vty, cmd_prompt (vty->node), hostname);
  194.     }
  195. }
  196. /* Send WILL TELOPT_ECHO to remote server. */
  197. void
  198. vty_will_echo (struct vty *vty)
  199. {
  200.   char cmd[] = { IAC, WILL, TELOPT_ECHO, '' };
  201.   vty_out (vty, "%s", cmd);
  202. }
  203. /* Make suppress Go-Ahead telnet option. */
  204. static void
  205. vty_will_suppress_go_ahead (struct vty *vty)
  206. {
  207.   char cmd[] = { IAC, WILL, TELOPT_SGA, '' };
  208.   vty_out (vty, "%s", cmd);
  209. }
  210. /* Make don't use linemode over telnet. */
  211. static void
  212. vty_dont_linemode (struct vty *vty)
  213. {
  214.   char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '' };
  215.   vty_out (vty, "%s", cmd);
  216. }
  217. /* Use window size. */
  218. static void
  219. vty_do_window_size (struct vty *vty)
  220. {
  221.   char cmd[] = { IAC, DO, TELOPT_NAWS, '' };
  222.   vty_out (vty, "%s", cmd);
  223. }
  224. #if 0 /* Currently not used. */
  225. /* Make don't use lflow vty interface. */
  226. static void
  227. vty_dont_lflow_ahead (struct vty *vty)
  228. {
  229.   char cmd[] = { IAC, DONT, TELOPT_LFLOW, '' };
  230.   vty_out (vty, "%s", cmd);
  231. }
  232. #endif /* 0 */
  233. /* Allocate new vty struct. */
  234. struct vty *
  235. vty_new ()
  236. {
  237.   struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
  238.   new->obuf = (struct buffer *) buffer_new (100);
  239.   new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
  240.   new->max = VTY_BUFSIZ;
  241.   new->sb_buffer = NULL;
  242.   return new;
  243. }
  244. /* Authentication of vty */
  245. static void
  246. vty_auth (struct vty *vty, char *buf)
  247. {
  248.   char *passwd = NULL;
  249.   enum node_type next_node = 0;
  250.   int fail;
  251.   char *crypt (const char *, const char *);
  252.   switch (vty->node)
  253.     {
  254.     case AUTH_NODE:
  255.       if (host.password_encrypt)
  256. passwd = host.password_encrypt;
  257.       else
  258. passwd = host.password;
  259.       if (host.advanced)
  260. next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
  261.       else
  262. next_node = VIEW_NODE;
  263.       break;
  264.     case AUTH_ENABLE_NODE:
  265.       if (host.enable_encrypt)
  266. passwd = host.enable_encrypt;
  267.       else
  268. passwd = host.enable;
  269.       next_node = ENABLE_NODE;
  270.       break;
  271.     }
  272.   if (passwd)
  273.     {
  274.       if (strcmp (crypt(buf, passwd), passwd) == 0
  275.   || strcmp (buf, passwd) == 0)
  276. fail = 0;
  277.       else
  278. fail = 1;
  279.     }
  280.   else
  281.     fail = 1;
  282.   if (! fail)
  283.     {
  284.       vty->fail = 0;
  285.       vty->node = next_node; /* Success ! */
  286.     }
  287.   else
  288.     {
  289.       vty->fail++;
  290.       if (vty->fail >= 3)
  291. {
  292.   if (vty->node == AUTH_NODE)
  293.     {
  294.       vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
  295.       vty->status = VTY_CLOSE;
  296.     }
  297.   else
  298.     {
  299.       /* AUTH_ENABLE_NODE */
  300.       vty->fail = 0;
  301.       vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
  302.       vty->node = VIEW_NODE;
  303.     }
  304. }
  305.     }
  306. }
  307. /* Command execution over the vty interface. */
  308. int
  309. vty_command (struct vty *vty, char *buf)
  310. {
  311.   int ret;
  312.   vector vline;
  313.   /* Split readline string up into the vector */
  314.   vline = cmd_make_strvec (buf);
  315.   if (vline == NULL)
  316.     return CMD_SUCCESS;
  317.   ret = cmd_execute_command (vline, vty, NULL);
  318.   if (ret != CMD_SUCCESS)
  319.     switch (ret)
  320.       {
  321.       case CMD_WARNING:
  322. if (vty->type == VTY_FILE)
  323.   vty_out (vty, "Warning...%s", VTY_NEWLINE);
  324. break;
  325.       case CMD_ERR_AMBIGUOUS:
  326. vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
  327. break;
  328.       case CMD_ERR_NO_MATCH:
  329. vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
  330. break;
  331.       case CMD_ERR_INCOMPLETE:
  332. vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
  333. break;
  334.       }
  335.   cmd_free_strvec (vline);
  336.   return ret;
  337. }
  338. char telnet_backward_char = 0x08;
  339. char telnet_space_char = ' ';
  340. /* Basic function to write buffer to vty. */
  341. static void
  342. vty_write (struct vty *vty, char *buf, size_t nbytes)
  343. {
  344.   if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
  345.     return;
  346.   /* Should we do buffering here ?  And make vty_flush (vty) ? */
  347.   buffer_write (vty->obuf, (u_char *)buf, nbytes);
  348. }
  349. /* Ensure length of input buffer.  Is buffer is short, double it. */
  350. static void
  351. vty_ensure (struct vty *vty, int length)
  352. {
  353.   if (vty->max <= length)
  354.     {
  355.       vty->max *= 2;
  356.       vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
  357.     }
  358. }
  359. /* Basic function to insert character into vty. */
  360. static void
  361. vty_self_insert (struct vty *vty, char c)
  362. {
  363.   int i;
  364.   int length;
  365.   vty_ensure (vty, vty->length + 1);
  366.   length = vty->length - vty->cp;
  367.   memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
  368.   vty->buf[vty->cp] = c;
  369.   vty_write (vty, &vty->buf[vty->cp], length + 1);
  370.   for (i = 0; i < length; i++)
  371.     vty_write (vty, &telnet_backward_char, 1);
  372.   vty->cp++;
  373.   vty->length++;
  374. }
  375. /* Self insert character 'c' in overwrite mode. */
  376. static void
  377. vty_self_insert_overwrite (struct vty *vty, char c)
  378. {
  379.   vty_ensure (vty, vty->length + 1);
  380.   vty->buf[vty->cp++] = c;
  381.   if (vty->cp > vty->length)
  382.     vty->length++;
  383.   if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
  384.     return;
  385.   vty_write (vty, &c, 1);
  386. }
  387. /* Insert a word into vty interface with overwrite mode. */
  388. static void
  389. vty_insert_word_overwrite (struct vty *vty, char *str)
  390. {
  391.   int len = strlen (str);
  392.   vty_write (vty, str, len);
  393.   strcpy (&vty->buf[vty->cp], str);
  394.   vty->cp += len;
  395.   vty->length = vty->cp;
  396. }
  397. /* Forward character. */
  398. static void
  399. vty_forward_char (struct vty *vty)
  400. {
  401.   if (vty->cp < vty->length)
  402.     {
  403.       vty_write (vty, &vty->buf[vty->cp], 1);
  404.       vty->cp++;
  405.     }
  406. }
  407. /* Backward character. */
  408. static void
  409. vty_backward_char (struct vty *vty)
  410. {
  411.   if (vty->cp > 0)
  412.     {
  413.       vty->cp--;
  414.       vty_write (vty, &telnet_backward_char, 1);
  415.     }
  416. }
  417. /* Move to the beginning of the line. */
  418. static void
  419. vty_beginning_of_line (struct vty *vty)
  420. {
  421.   while (vty->cp)
  422.     vty_backward_char (vty);
  423. }
  424. /* Move to the end of the line. */
  425. static void
  426. vty_end_of_line (struct vty *vty)
  427. {
  428.   while (vty->cp < vty->length)
  429.     vty_forward_char (vty);
  430. }
  431. static void vty_kill_line_from_beginning (struct vty *);
  432. static void vty_redraw_line (struct vty *);
  433. /* Print command line history.  This function is called from
  434.    vty_next_line and vty_previous_line. */
  435. static void
  436. vty_history_print (struct vty *vty)
  437. {
  438.   int length;
  439.   vty_kill_line_from_beginning (vty);
  440.   /* Get previous line from history buffer */
  441.   length = strlen (vty->hist[vty->hp]);
  442.   memcpy (vty->buf, vty->hist[vty->hp], length);
  443.   vty->cp = vty->length = length;
  444.   /* Redraw current line */
  445.   vty_redraw_line (vty);
  446. }
  447. /* Show next command line history. */
  448. void
  449. vty_next_line (struct vty *vty)
  450. {
  451.   int try_index;
  452.   if (vty->hp == vty->hindex)
  453.     return;
  454.   /* Try is there history exist or not. */
  455.   try_index = vty->hp;
  456.   if (try_index == (VTY_MAXHIST - 1))
  457.     try_index = 0;
  458.   else
  459.     try_index++;
  460.   /* If there is not history return. */
  461.   if (vty->hist[try_index] == NULL)
  462.     return;
  463.   else
  464.     vty->hp = try_index;
  465.   vty_history_print (vty);
  466. }
  467. /* Show previous command line history. */
  468. void
  469. vty_previous_line (struct vty *vty)
  470. {
  471.   int try_index;
  472.   try_index = vty->hp;
  473.   if (try_index == 0)
  474.     try_index = VTY_MAXHIST - 1;
  475.   else
  476.     try_index--;
  477.   if (vty->hist[try_index] == NULL)
  478.     return;
  479.   else
  480.     vty->hp = try_index;
  481.   vty_history_print (vty);
  482. }
  483. /* This function redraw all of the command line character. */
  484. static void
  485. vty_redraw_line (struct vty *vty)
  486. {
  487.   vty_write (vty, vty->buf, vty->length);
  488.   vty->cp = vty->length;
  489. }
  490. /* Forward word. */
  491. static void
  492. vty_forward_word (struct vty *vty)
  493. {
  494.   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
  495.     vty_forward_char (vty);
  496.   
  497.   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
  498.     vty_forward_char (vty);
  499. }
  500. /* Backward word without skipping training space. */
  501. static void
  502. vty_backward_pure_word (struct vty *vty)
  503. {
  504.   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
  505.     vty_backward_char (vty);
  506. }
  507. /* Backward word. */
  508. static void
  509. vty_backward_word (struct vty *vty)
  510. {
  511.   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
  512.     vty_backward_char (vty);
  513.   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
  514.     vty_backward_char (vty);
  515. }
  516. /* When '^D' is typed at the beginning of the line we move to the down
  517.    level. */
  518. static void
  519. vty_down_level (struct vty *vty)
  520. {
  521.   vty_out (vty, "%s", VTY_NEWLINE);
  522.   config_exit (NULL, vty, 0, NULL);
  523.   vty_prompt (vty);
  524.   vty->cp = 0;
  525. }
  526. /* When '^Z' is received from vty, move down to the enable mode. */
  527. void
  528. vty_end_config (struct vty *vty)
  529. {
  530.   vty_out (vty, "%s", VTY_NEWLINE);
  531.   switch (vty->node)
  532.     {
  533.     case VIEW_NODE:
  534.     case ENABLE_NODE:
  535.       /* Nothing to do. */
  536.       break;
  537.     case CONFIG_NODE:
  538.     case INTERFACE_NODE:
  539.     case ZEBRA_NODE:
  540.     case RIP_NODE:
  541.     case RIPNG_NODE:
  542.     case BGP_NODE:
  543.     case BGP_VPNV4_NODE:
  544.     case BGP_IPV4_NODE:
  545.     case BGP_IPV4M_NODE:
  546.     case BGP_IPV6_NODE:
  547.     case RMAP_NODE:
  548.     case OSPF_NODE:
  549.     case OSPF6_NODE:
  550.     case KEYCHAIN_NODE:
  551.     case KEYCHAIN_KEY_NODE:
  552.     case MASC_NODE:
  553.     case VTY_NODE:
  554.       vty_config_unlock (vty);
  555.       vty->node = ENABLE_NODE;
  556.       break;
  557.     default:
  558.       /* Unknown node, we have to ignore it. */
  559.       break;
  560.     }
  561.   vty_prompt (vty);
  562.   vty->cp = 0;
  563. }
  564. /* Delete a charcter at the current point. */
  565. static void
  566. vty_delete_char (struct vty *vty)
  567. {
  568.   int i;
  569.   int size;
  570.   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
  571.     return;
  572.   if (vty->length == 0)
  573.     {
  574.       vty_down_level (vty);
  575.       return;
  576.     }
  577.   if (vty->cp == vty->length)
  578.     return; /* completion need here? */
  579.   size = vty->length - vty->cp;
  580.   vty->length--;
  581.   memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
  582.   vty->buf[vty->length] = '';
  583.   vty_write (vty, &vty->buf[vty->cp], size - 1);
  584.   vty_write (vty, &telnet_space_char, 1);
  585.   for (i = 0; i < size; i++)
  586.     vty_write (vty, &telnet_backward_char, 1);
  587. }
  588. /* Delete a character before the point. */
  589. static void
  590. vty_delete_backward_char (struct vty *vty)
  591. {
  592.   if (vty->cp == 0)
  593.     return;
  594.   vty_backward_char (vty);
  595.   vty_delete_char (vty);
  596. }
  597. /* Kill rest of line from current point. */
  598. static void
  599. vty_kill_line (struct vty *vty)
  600. {
  601.   int i;
  602.   int size;
  603.   size = vty->length - vty->cp;
  604.   
  605.   if (size == 0)
  606.     return;
  607.   for (i = 0; i < size; i++)
  608.     vty_write (vty, &telnet_space_char, 1);
  609.   for (i = 0; i < size; i++)
  610.     vty_write (vty, &telnet_backward_char, 1);
  611.   memset (&vty->buf[vty->cp], 0, size);
  612.   vty->length = vty->cp;
  613. }
  614. /* Kill line from the beginning. */
  615. static void
  616. vty_kill_line_from_beginning (struct vty *vty)
  617. {
  618.   vty_beginning_of_line (vty);
  619.   vty_kill_line (vty);
  620. }
  621. /* Delete a word before the point. */
  622. static void
  623. vty_forward_kill_word (struct vty *vty)
  624. {
  625.   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
  626.     vty_delete_char (vty);
  627.   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
  628.     vty_delete_char (vty);
  629. }
  630. /* Delete a word before the point. */
  631. static void
  632. vty_backward_kill_word (struct vty *vty)
  633. {
  634.   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
  635.     vty_delete_backward_char (vty);
  636.   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
  637.     vty_delete_backward_char (vty);
  638. }
  639. /* Transpose chars before or at the point. */
  640. static void
  641. vty_transpose_chars (struct vty *vty)
  642. {
  643.   char c1, c2;
  644.   /* If length is short or point is near by the beginning of line then
  645.      return. */
  646.   if (vty->length < 2 || vty->cp < 1)
  647.     return;
  648.   /* In case of point is located at the end of the line. */
  649.   if (vty->cp == vty->length)
  650.     {
  651.       c1 = vty->buf[vty->cp - 1];
  652.       c2 = vty->buf[vty->cp - 2];
  653.       vty_backward_char (vty);
  654.       vty_backward_char (vty);
  655.       vty_self_insert_overwrite (vty, c1);
  656.       vty_self_insert_overwrite (vty, c2);
  657.     }
  658.   else
  659.     {
  660.       c1 = vty->buf[vty->cp];
  661.       c2 = vty->buf[vty->cp - 1];
  662.       vty_backward_char (vty);
  663.       vty_self_insert_overwrite (vty, c1);
  664.       vty_self_insert_overwrite (vty, c2);
  665.     }
  666. }
  667. /* Do completion at vty interface. */
  668. static void
  669. vty_complete_command (struct vty *vty)
  670. {
  671.   int i;
  672.   int ret;
  673.   char **matched = NULL;
  674.   vector vline;
  675.   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
  676.     return;
  677.   vline = cmd_make_strvec (vty->buf);
  678.   if (vline == NULL)
  679.     return;
  680.   /* In case of 'help t'. */
  681.   if (isspace ((int) vty->buf[vty->length - 1]))
  682.     vector_set (vline, '');
  683.   matched = cmd_complete_command (vline, vty, &ret);
  684.   
  685.   cmd_free_strvec (vline);
  686.   vty_out (vty, "%s", VTY_NEWLINE);
  687.   switch (ret)
  688.     {
  689.     case CMD_ERR_AMBIGUOUS:
  690.       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
  691.       vty_prompt (vty);
  692.       vty_redraw_line (vty);
  693.       break;
  694.     case CMD_ERR_NO_MATCH:
  695.       /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
  696.       vty_prompt (vty);
  697.       vty_redraw_line (vty);
  698.       break;
  699.     case CMD_COMPLETE_FULL_MATCH:
  700.       vty_prompt (vty);
  701.       vty_redraw_line (vty);
  702.       vty_backward_pure_word (vty);
  703.       vty_insert_word_overwrite (vty, matched[0]);
  704.       vty_self_insert (vty, ' ');
  705.       XFREE (MTYPE_TMP, matched[0]);
  706.       break;
  707.     case CMD_COMPLETE_MATCH:
  708.       vty_prompt (vty);
  709.       vty_redraw_line (vty);
  710.       vty_backward_pure_word (vty);
  711.       vty_insert_word_overwrite (vty, matched[0]);
  712.       XFREE (MTYPE_TMP, matched[0]);
  713.       vector_only_index_free (matched);
  714.       return;
  715.       break;
  716.     case CMD_COMPLETE_LIST_MATCH:
  717.       for (i = 0; matched[i] != NULL; i++)
  718. {
  719.   if (i != 0 && ((i % 6) == 0))
  720.     vty_out (vty, "%s", VTY_NEWLINE);
  721.   vty_out (vty, "%-10s ", matched[i]);
  722.   XFREE (MTYPE_TMP, matched[i]);
  723. }
  724.       vty_out (vty, "%s", VTY_NEWLINE);
  725.       vty_prompt (vty);
  726.       vty_redraw_line (vty);
  727.       break;
  728.     case CMD_ERR_NOTHING_TODO:
  729.       vty_prompt (vty);
  730.       vty_redraw_line (vty);
  731.       break;
  732.     default:
  733.       break;
  734.     }
  735.   if (matched)
  736.     vector_only_index_free (matched);
  737. }
  738. void
  739. vty_describe_fold (struct vty *vty, int cmd_width,
  740.    int desc_width, struct desc *desc)
  741. {
  742.   char *buf, *cmd, *p;
  743.   int pos;
  744.   cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
  745.   if (desc_width <= 0)
  746.     {
  747.       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
  748.       return;
  749.     }
  750.   buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
  751.   for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
  752.     {
  753.       for (pos = desc_width; pos > 0; pos--)
  754. if (*(p + pos) == ' ')
  755.   break;
  756.       if (pos == 0)
  757. break;
  758.       strncpy (buf, p, pos);
  759.       buf[pos] = '';
  760.       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
  761.       cmd = "";
  762.     }
  763.   vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
  764.   XFREE (MTYPE_TMP, buf);
  765. }
  766. /* Describe matched command function. */
  767. static void
  768. vty_describe_command (struct vty *vty)
  769. {
  770.   int ret;
  771.   vector vline;
  772.   vector describe;
  773.   int i, width, desc_width;
  774.   struct desc *desc, *desc_cr = NULL;
  775.   vline = cmd_make_strvec (vty->buf);
  776.   /* In case of '> ?'. */
  777.   if (vline == NULL)
  778.     {
  779.       vline = vector_init (1);
  780.       vector_set (vline, '');
  781.     }
  782.   else 
  783.     if (isspace ((int) vty->buf[vty->length - 1]))
  784.       vector_set (vline, '');
  785.   describe = cmd_describe_command (vline, vty, &ret);
  786.   vty_out (vty, "%s", VTY_NEWLINE);
  787.   /* Ambiguous error. */
  788.   switch (ret)
  789.     {
  790.     case CMD_ERR_AMBIGUOUS:
  791.       cmd_free_strvec (vline);
  792.       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
  793.       vty_prompt (vty);
  794.       vty_redraw_line (vty);
  795.       return;
  796.       break;
  797.     case CMD_ERR_NO_MATCH:
  798.       cmd_free_strvec (vline);
  799.       vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
  800.       vty_prompt (vty);
  801.       vty_redraw_line (vty);
  802.       return;
  803.       break;
  804.     }  
  805.   /* Get width of command string. */
  806.   width = 0;
  807.   for (i = 0; i < vector_max (describe); i++)
  808.     if ((desc = vector_slot (describe, i)) != NULL)
  809.       {
  810. int len;
  811. if (desc->cmd[0] == '')
  812.   continue;
  813. len = strlen (desc->cmd);
  814. if (desc->cmd[0] == '.')
  815.   len--;
  816. if (width < len)
  817.   width = len;
  818.       }
  819.   /* Get width of description string. */
  820.   desc_width = vty->width - (width + 6);
  821.   /* Print out description. */
  822.   for (i = 0; i < vector_max (describe); i++)
  823.     if ((desc = vector_slot (describe, i)) != NULL)
  824.       {
  825. if (desc->cmd[0] == '')
  826.   continue;
  827. if (strcmp (desc->cmd, "<cr>") == 0)
  828.   {
  829.     desc_cr = desc;
  830.     continue;
  831.   }
  832. if (!desc->str)
  833.   vty_out (vty, "  %-s%s",
  834.    desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
  835.    VTY_NEWLINE);
  836. else if (desc_width >= strlen (desc->str))
  837.   vty_out (vty, "  %-*s  %s%s", width,
  838.    desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
  839.    desc->str, VTY_NEWLINE);
  840. else
  841.   vty_describe_fold (vty, width, desc_width, desc);
  842. #if 0
  843. vty_out (vty, "  %-*s %s%s", width
  844.  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
  845.  desc->str ? desc->str : "", VTY_NEWLINE);
  846. #endif /* 0 */
  847.       }
  848.   if ((desc = desc_cr))
  849.     {
  850.       if (!desc->str)
  851. vty_out (vty, "  %-s%s",
  852.  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
  853.  VTY_NEWLINE);
  854.       else if (desc_width >= strlen (desc->str))
  855. vty_out (vty, "  %-*s  %s%s", width,
  856.  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
  857.  desc->str, VTY_NEWLINE);
  858.       else
  859. vty_describe_fold (vty, width, desc_width, desc);
  860.     }
  861.   cmd_free_strvec (vline);
  862.   vector_free (describe);
  863.   vty_prompt (vty);
  864.   vty_redraw_line (vty);
  865. }
  866. void
  867. vty_clear_buf (struct vty *vty)
  868. {
  869.   memset (vty->buf, 0, vty->max);
  870. }
  871. /* ^C stop current input and do not add command line to the history. */
  872. static void
  873. vty_stop_input (struct vty *vty)
  874. {
  875.   vty->cp = vty->length = 0;
  876.   vty_clear_buf (vty);
  877.   vty_out (vty, "%s", VTY_NEWLINE);
  878.   switch (vty->node)
  879.     {
  880.     case VIEW_NODE:
  881.     case ENABLE_NODE:
  882.       /* Nothing to do. */
  883.       break;
  884.     case CONFIG_NODE:
  885.     case INTERFACE_NODE:
  886.     case ZEBRA_NODE:
  887.     case RIP_NODE:
  888.     case RIPNG_NODE:
  889.     case BGP_NODE:
  890.     case RMAP_NODE:
  891.     case OSPF_NODE:
  892.     case OSPF6_NODE:
  893.     case KEYCHAIN_NODE:
  894.     case KEYCHAIN_KEY_NODE:
  895.     case MASC_NODE:
  896.     case VTY_NODE:
  897.       vty_config_unlock (vty);
  898.       vty->node = ENABLE_NODE;
  899.       break;
  900.     default:
  901.       /* Unknown node, we have to ignore it. */
  902.       break;
  903.     }
  904.   vty_prompt (vty);
  905.   /* Set history pointer to the latest one. */
  906.   vty->hp = vty->hindex;
  907. }
  908. /* Add current command line to the history buffer. */
  909. static void
  910. vty_hist_add (struct vty *vty)
  911. {
  912.   int index;
  913.   if (vty->length == 0)
  914.     return;
  915.   index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
  916.   /* Ignore the same string as previous one. */
  917.   if (vty->hist[index])
  918.     if (strcmp (vty->buf, vty->hist[index]) == 0)
  919.       {
  920. vty->hp = vty->hindex;
  921. return;
  922.       }
  923.   /* Insert history entry. */
  924.   if (vty->hist[vty->hindex])
  925.     XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
  926.   vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
  927.   /* History index rotation. */
  928.   vty->hindex++;
  929.   if (vty->hindex == VTY_MAXHIST)
  930.     vty->hindex = 0;
  931.   vty->hp = vty->hindex;
  932. }
  933. /* #define TELNET_OPTION_DEBUG */
  934. /* Get telnet window size. */
  935. static int
  936. vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
  937. {
  938. #ifdef TELNET_OPTION_DEBUG
  939.   int i;
  940.   for (i = 0; i < nbytes; i++)
  941.     {
  942.       switch (buf[i])
  943. {
  944. case IAC:
  945.   vty_out (vty, "IAC ");
  946.   break;
  947. case WILL:
  948.   vty_out (vty, "WILL ");
  949.   break;
  950. case WONT:
  951.   vty_out (vty, "WONT ");
  952.   break;
  953. case DO:
  954.   vty_out (vty, "DO ");
  955.   break;
  956. case DONT:
  957.   vty_out (vty, "DONT ");
  958.   break;
  959. case SB:
  960.   vty_out (vty, "SB ");
  961.   break;
  962. case SE:
  963.   vty_out (vty, "SE ");
  964.   break;
  965. case TELOPT_ECHO:
  966.   vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
  967.   break;
  968. case TELOPT_SGA:
  969.   vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
  970.   break;
  971. case TELOPT_NAWS:
  972.   vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
  973.   break;
  974. default:
  975.   vty_out (vty, "%x ", buf[i]);
  976.   break;
  977. }
  978.     }
  979.   vty_out (vty, "%s", VTY_NEWLINE);
  980. #endif /* TELNET_OPTION_DEBUG */
  981.   switch (buf[0])
  982.     {
  983.     case SB:
  984.       buffer_reset(vty->sb_buffer);
  985.       vty->iac_sb_in_progress = 1;
  986.       return 0;
  987.       break;
  988.     case SE: 
  989.       {
  990. char *buffer;
  991. int length;
  992. if (!vty->iac_sb_in_progress)
  993.   return 0;
  994. buffer = (char *)vty->sb_buffer->head->data;
  995. length = vty->sb_buffer->length;
  996. if (buffer == NULL)
  997.   return 0;
  998. if (buffer[0] == '')
  999.   {
  1000.     vty->iac_sb_in_progress = 0;
  1001.     return 0;
  1002.   }
  1003. switch (buffer[0])
  1004.   {
  1005.   case TELOPT_NAWS:
  1006.     if (length < 5)
  1007.       break;
  1008.     vty->width = buffer[2];
  1009.     vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
  1010.     break;
  1011.   }
  1012. vty->iac_sb_in_progress = 0;
  1013. return 0;
  1014. break;
  1015.       }
  1016.     default:
  1017.       break;
  1018.     }
  1019.   return 1;
  1020. }
  1021. /* Execute current command line. */
  1022. static int
  1023. vty_execute (struct vty *vty)
  1024. {
  1025.   int ret;
  1026.   ret = CMD_SUCCESS;
  1027.   switch (vty->node)
  1028.     {
  1029.     case AUTH_NODE:
  1030.     case AUTH_ENABLE_NODE:
  1031.       vty_auth (vty, vty->buf);
  1032.       break;
  1033.     default:
  1034.       ret = vty_command (vty, vty->buf);
  1035.       if (vty->type == VTY_TERM)
  1036. vty_hist_add (vty);
  1037.       break;
  1038.     }
  1039.   /* Clear command line buffer. */
  1040.   vty->cp = vty->length = 0;
  1041.   vty_clear_buf (vty);
  1042.   if (vty->status != VTY_CLOSE 
  1043.       && vty->status != VTY_START
  1044.       && vty->status != VTY_CONTINUE)
  1045.     vty_prompt (vty);
  1046.   return ret;
  1047. }
  1048. #define CONTROL(X)  ((X) - '@')
  1049. #define VTY_NORMAL     0
  1050. #define VTY_PRE_ESCAPE 1
  1051. #define VTY_ESCAPE     2
  1052. /* Escape character command map. */
  1053. static void
  1054. vty_escape_map (unsigned char c, struct vty *vty)
  1055. {
  1056.   switch (c)
  1057.     {
  1058.     case ('A'):
  1059.       vty_previous_line (vty);
  1060.       break;
  1061.     case ('B'):
  1062.       vty_next_line (vty);
  1063.       break;
  1064.     case ('C'):
  1065.       vty_forward_char (vty);
  1066.       break;
  1067.     case ('D'):
  1068.       vty_backward_char (vty);
  1069.       break;
  1070.     default:
  1071.       break;
  1072.     }
  1073.   /* Go back to normal mode. */
  1074.   vty->escape = VTY_NORMAL;
  1075. }
  1076. /* Quit print out to the buffer. */
  1077. static void
  1078. vty_buffer_reset (struct vty *vty)
  1079. {
  1080.   buffer_reset (vty->obuf);
  1081.   vty_prompt (vty);
  1082.   vty_redraw_line (vty);
  1083. }
  1084. /* Read data via vty socket. */
  1085. static int
  1086. vty_read (struct thread *thread)
  1087. {
  1088.   int i;
  1089.   int ret;
  1090.   int nbytes;
  1091.   unsigned char buf[VTY_READ_BUFSIZ];
  1092.   int vty_sock = THREAD_FD (thread);
  1093.   struct vty *vty = THREAD_ARG (thread);
  1094.   vty->t_read = NULL;
  1095.   /* Read raw data from socket */
  1096.   nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
  1097.   if (nbytes <= 0)
  1098.     vty->status = VTY_CLOSE;
  1099.   for (i = 0; i < nbytes; i++) 
  1100.     {
  1101.       if (buf[i] == IAC)
  1102. {
  1103.   if (!vty->iac)
  1104.     {
  1105.       vty->iac = 1;
  1106.       continue;
  1107.     }
  1108.   else
  1109.     {
  1110.       vty->iac = 0;
  1111.     }
  1112. }
  1113.       
  1114.       if (vty->iac_sb_in_progress && !vty->iac)
  1115. {
  1116.   buffer_putc(vty->sb_buffer, buf[i]);
  1117.   continue;
  1118. }
  1119.       if (vty->iac)
  1120. {
  1121.   /* In case of telnet command */
  1122.   ret = vty_telnet_option (vty, buf + i, nbytes - i);
  1123.   vty->iac = 0;
  1124.   i += ret;
  1125.   continue;
  1126. }
  1127.       if (vty->status == VTY_MORE)
  1128. {
  1129.   switch (buf[i])
  1130.     {
  1131.     case CONTROL('C'):
  1132.     case 'q':
  1133.     case 'Q':
  1134.       if (vty->output_func)
  1135. (*vty->output_func) (vty, 1);
  1136.       vty_buffer_reset (vty);
  1137.       break;
  1138. #if 1 /* More line for "show ip bgp" is fixed */
  1139.     case 'n':
  1140.     case 'r':
  1141.       vty->status = VTY_MORELINE;
  1142.       if (vty->output_func)
  1143. (*vty->output_func) (vty, 0);
  1144.       break;
  1145. #endif
  1146.     default:
  1147.       if (vty->output_func)
  1148. (*vty->output_func) (vty, 0);
  1149.       break;
  1150.     }
  1151.   continue;
  1152. }
  1153.       /* Escape character. */
  1154.       if (vty->escape == VTY_ESCAPE)
  1155. {
  1156.   vty_escape_map (buf[i], vty);
  1157.   continue;
  1158. }
  1159.       /* Pre-escape status. */
  1160.       if (vty->escape == VTY_PRE_ESCAPE)
  1161. {
  1162.   switch (buf[i])
  1163.     {
  1164.     case '[':
  1165.       vty->escape = VTY_ESCAPE;
  1166.       break;
  1167.     case 'b':
  1168.       vty_backward_word (vty);
  1169.       vty->escape = VTY_NORMAL;
  1170.       break;
  1171.     case 'f':
  1172.       vty_forward_word (vty);
  1173.       vty->escape = VTY_NORMAL;
  1174.       break;
  1175.     case 'd':
  1176.       vty_forward_kill_word (vty);
  1177.       vty->escape = VTY_NORMAL;
  1178.       break;
  1179.     case CONTROL('H'):
  1180.     case 0x7f:
  1181.       vty_backward_kill_word (vty);
  1182.       vty->escape = VTY_NORMAL;
  1183.       break;
  1184.     default:
  1185.       vty->escape = VTY_NORMAL;
  1186.       break;
  1187.     }
  1188.   continue;
  1189. }
  1190.       switch (buf[i])
  1191. {
  1192. case CONTROL('A'):
  1193.   vty_beginning_of_line (vty);
  1194.   break;
  1195. case CONTROL('B'):
  1196.   vty_backward_char (vty);
  1197.   break;
  1198. case CONTROL('C'):
  1199.   vty_stop_input (vty);
  1200.   break;
  1201. case CONTROL('D'):
  1202.   vty_delete_char (vty);
  1203.   break;
  1204. case CONTROL('E'):
  1205.   vty_end_of_line (vty);
  1206.   break;
  1207. case CONTROL('F'):
  1208.   vty_forward_char (vty);
  1209.   break;
  1210. case CONTROL('H'):
  1211. case 0x7f:
  1212.   vty_delete_backward_char (vty);
  1213.   break;
  1214. case CONTROL('K'):
  1215.   vty_kill_line (vty);
  1216.   break;
  1217. case CONTROL('N'):
  1218.   vty_next_line (vty);
  1219.   break;
  1220. case CONTROL('P'):
  1221.   vty_previous_line (vty);
  1222.   break;
  1223. case CONTROL('T'):
  1224.   vty_transpose_chars (vty);
  1225.   break;
  1226. case CONTROL('U'):
  1227.   vty_kill_line_from_beginning (vty);
  1228.   break;
  1229. case CONTROL('W'):
  1230.   vty_backward_kill_word (vty);
  1231.   break;
  1232. case CONTROL('Z'):
  1233.   vty_end_config (vty);
  1234.   break;
  1235. case 'n':
  1236. case 'r':
  1237.   vty_out (vty, "%s", VTY_NEWLINE);
  1238.   vty_execute (vty);
  1239.   break;
  1240. case 't':
  1241.   vty_complete_command (vty);
  1242.   break;
  1243. case '?':
  1244.   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
  1245.     vty_self_insert (vty, buf[i]);
  1246.   else
  1247.     vty_describe_command (vty);
  1248.   break;
  1249. case '33':
  1250.   if (i + 1 < nbytes && buf[i + 1] == '[')
  1251.     {
  1252.       vty->escape = VTY_ESCAPE;
  1253.       i++;
  1254.     }
  1255.   else
  1256.     vty->escape = VTY_PRE_ESCAPE;
  1257.   break;
  1258. default:
  1259.   if (buf[i] > 31 && buf[i] < 127)
  1260.     vty_self_insert (vty, buf[i]);
  1261.   break;
  1262. }
  1263.     }
  1264.   /* Check status. */
  1265.   if (vty->status == VTY_CLOSE)
  1266.     vty_close (vty);
  1267.   else
  1268.     {
  1269.       vty_event (VTY_WRITE, vty_sock, vty);
  1270.       vty_event (VTY_READ, vty_sock, vty);
  1271.     }
  1272.   return 0;
  1273. }
  1274. /* Flush buffer to the vty. */
  1275. static int
  1276. vty_flush (struct thread *thread)
  1277. {
  1278.   int erase;
  1279.   int dont_more;
  1280.   int vty_sock = THREAD_FD (thread);
  1281.   struct vty *vty = THREAD_ARG (thread);
  1282.   vty->t_write = NULL;
  1283.   /* Tempolary disable read thread. */
  1284.   if (vty->lines == 0)
  1285.     if (vty->t_read)
  1286.       {
  1287. thread_cancel (vty->t_read);
  1288. vty->t_read = NULL;
  1289.       }
  1290.   /* Function execution continue. */
  1291.   if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
  1292.     {
  1293.       if (vty->status == VTY_CONTINUE && vty->output_func)
  1294. erase = 1;
  1295.       else
  1296. erase = 0;
  1297.       if (vty->output_func == NULL)
  1298. dont_more = 1;
  1299.       else
  1300. dont_more = 0;
  1301.       if (vty->lines == 0)
  1302. {
  1303.   erase = 0;
  1304.   dont_more = 1;
  1305. }
  1306.       buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
  1307.       if (vty->status == VTY_CLOSE)
  1308. {
  1309.   vty_close (vty);
  1310.   return 0;
  1311. }
  1312.       if (vty->output_func == NULL)
  1313. {
  1314.   vty->status = VTY_NORMAL;
  1315.   vty_prompt (vty);
  1316.   vty_event (VTY_WRITE, vty_sock, vty);
  1317. }
  1318.       else
  1319. vty->status = VTY_MORE;
  1320.       if (vty->lines == 0)
  1321. {
  1322.   if (vty->output_func == NULL)
  1323.     vty_event (VTY_READ, vty_sock, vty);
  1324.   else
  1325.     {
  1326.       if (vty->output_func)
  1327. (*vty->output_func) (vty, 0);
  1328.       vty_event (VTY_WRITE, vty_sock, vty);
  1329.     }
  1330. }
  1331.     }
  1332.   else
  1333.     {
  1334.       if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
  1335. erase = 1;
  1336.       else
  1337. erase = 0;
  1338.       if (vty->lines == 0)
  1339. buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
  1340.       else if (vty->status == VTY_MORELINE)
  1341. buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
  1342.       else
  1343. buffer_flush_window (vty->obuf, vty->fd, vty->width,
  1344.      vty->lines >= 0 ? vty->lines : vty->height,
  1345.      erase, 0);
  1346.   
  1347.       if (buffer_empty (vty->obuf))
  1348. {
  1349.   if (vty->status == VTY_CLOSE)
  1350.     vty_close (vty);
  1351.   else
  1352.     {
  1353.       vty->status = VTY_NORMAL;
  1354.   
  1355.       if (vty->lines == 0)
  1356. vty_event (VTY_READ, vty_sock, vty);
  1357.     }
  1358. }
  1359.       else
  1360. {
  1361.   vty->status = VTY_MORE;
  1362.   if (vty->lines == 0)
  1363.     vty_event (VTY_WRITE, vty_sock, vty);
  1364. }
  1365.     }
  1366.   return 0;
  1367. }
  1368. /* Create new vty structure. */
  1369. struct vty *
  1370. vty_create (int vty_sock, union sockunion *su)
  1371. {
  1372.   struct vty *vty;
  1373.   /* Allocate new vty structure and set up default values. */
  1374.   vty = vty_new ();
  1375.   vty->fd = vty_sock;
  1376.   vty->type = VTY_TERM;
  1377.   vty->address = sockunion_su2str (su);
  1378.   if (no_password_check)
  1379.     {
  1380.       if (host.advanced)
  1381. vty->node = ENABLE_NODE;
  1382.       else
  1383. vty->node = VIEW_NODE;
  1384.     }
  1385.   else
  1386.     vty->node = AUTH_NODE;
  1387.   vty->fail = 0;
  1388.   vty->cp = 0;
  1389.   vty_clear_buf (vty);
  1390.   vty->length = 0;
  1391.   memset (vty->hist, 0, sizeof (vty->hist));
  1392.   vty->hp = 0;
  1393.   vty->hindex = 0;
  1394.   vector_set_index (vtyvec, vty_sock, vty);
  1395.   vty->status = VTY_NORMAL;
  1396.   vty->v_timeout = vty_timeout_val;
  1397.   if (host.lines >= 0)
  1398.     vty->lines = host.lines;
  1399.   else
  1400.     vty->lines = -1;
  1401.   vty->iac = 0;
  1402.   vty->iac_sb_in_progress = 0;
  1403.   vty->sb_buffer = buffer_new (1024);
  1404.   if (! no_password_check)
  1405.     {
  1406.       /* Vty is not available if password isn't set. */
  1407.       if (host.password == NULL && host.password_encrypt == NULL)
  1408. {
  1409.   vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
  1410.   vty->status = VTY_CLOSE;
  1411.   vty_close (vty);
  1412.   return NULL;
  1413. }
  1414.     }
  1415.   /* Say hello to the world. */
  1416.   vty_hello (vty);
  1417.   if (! no_password_check)
  1418.     vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
  1419.   /* Setting up terminal. */
  1420.   vty_will_echo (vty);
  1421.   vty_will_suppress_go_ahead (vty);
  1422.   vty_dont_linemode (vty);
  1423.   vty_do_window_size (vty);
  1424.   /* vty_dont_lflow_ahead (vty); */
  1425.   vty_prompt (vty);
  1426.   /* Add read/write thread. */
  1427.   vty_event (VTY_WRITE, vty_sock, vty);
  1428.   vty_event (VTY_READ, vty_sock, vty);
  1429.   return vty;
  1430. }
  1431. /* Accept connection from the network. */
  1432. static int
  1433. vty_accept (struct thread *thread)
  1434. {
  1435.   int vty_sock;
  1436.   struct vty *vty;
  1437.   union sockunion su;
  1438.   int ret;
  1439.   unsigned int on;
  1440.   int accept_sock;
  1441.   struct prefix *p = NULL;
  1442.   struct access_list *acl = NULL;
  1443.   accept_sock = THREAD_FD (thread);
  1444.   /* We continue hearing vty socket. */
  1445.   vty_event (VTY_SERV, accept_sock, NULL);
  1446.   memset (&su, 0, sizeof (union sockunion));
  1447.   /* We can handle IPv4 or IPv6 socket. */
  1448.   vty_sock = sockunion_accept (accept_sock, &su);
  1449.   if (vty_sock < 0)
  1450.     {
  1451.       zlog_warn ("can't accept vty socket : %s", strerror (errno));
  1452.       return -1;
  1453.     }
  1454.   p = sockunion2hostprefix (&su);
  1455.   /* VTY's accesslist apply. */
  1456.   if (p->family == AF_INET && vty_accesslist_name)
  1457.     {
  1458.       if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
  1459.   (access_list_apply (acl, p) == FILTER_DENY))
  1460. {
  1461.   char *buf;
  1462.   zlog (NULL, LOG_INFO, "Vty connection refused from %s",
  1463. (buf = sockunion_su2str (&su)));
  1464.   free (buf);
  1465.   close (vty_sock);
  1466.   
  1467.   /* continue accepting connections */
  1468.   vty_event (VTY_SERV, accept_sock, NULL);
  1469.   
  1470.   prefix_free (p);
  1471.   return 0;
  1472. }
  1473.     }
  1474. #ifdef HAVE_IPV6
  1475.   /* VTY's ipv6 accesslist apply. */
  1476.   if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
  1477.     {
  1478.       if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
  1479.   (access_list_apply (acl, p) == FILTER_DENY))
  1480. {
  1481.   char *buf;
  1482.   zlog (NULL, LOG_INFO, "Vty connection refused from %s",
  1483. (buf = sockunion_su2str (&su)));
  1484.   free (buf);
  1485.   close (vty_sock);
  1486.   
  1487.   /* continue accepting connections */
  1488.   vty_event (VTY_SERV, accept_sock, NULL);
  1489.   
  1490.   prefix_free (p);
  1491.   return 0;
  1492. }
  1493.     }
  1494. #endif /* HAVE_IPV6 */
  1495.   
  1496.   prefix_free (p);
  1497.   on = 1;
  1498.   ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
  1499.     (char *) &on, sizeof (on));
  1500.   if (ret < 0)
  1501.     zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
  1502.   strerror (errno));
  1503.   vty = vty_create (vty_sock, &su);
  1504.   return 0;
  1505. }
  1506. #if defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)
  1507. void
  1508. vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
  1509. {
  1510.   int ret;
  1511.   struct addrinfo req;
  1512.   struct addrinfo *ainfo;
  1513.   struct addrinfo *ainfo_save;
  1514.   int sock;
  1515.   char port_str[BUFSIZ];
  1516.   memset (&req, 0, sizeof (struct addrinfo));
  1517.   req.ai_flags = AI_PASSIVE;
  1518.   req.ai_family = AF_UNSPEC;
  1519.   req.ai_socktype = SOCK_STREAM;
  1520.   sprintf (port_str, "%d", port);
  1521.   port_str[sizeof (port_str) - 1] = '';
  1522.   ret = getaddrinfo (hostname, port_str, &req, &ainfo);
  1523.   if (ret != 0)
  1524.     {
  1525.       fprintf (stderr, "getaddrinfo failed: %sn", gai_strerror (ret));
  1526.       exit (1);
  1527.     }
  1528.   ainfo_save = ainfo;
  1529.   do
  1530.     {
  1531.       if (ainfo->ai_family != AF_INET
  1532. #ifdef HAVE_IPV6
  1533.   && ainfo->ai_family != AF_INET6
  1534. #endif /* HAVE_IPV6 */
  1535.   )
  1536. continue;
  1537.       sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
  1538.       if (sock < 0)
  1539. continue;
  1540.       sockopt_reuseaddr (sock);
  1541.       sockopt_reuseport (sock);
  1542.       ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
  1543.       if (ret < 0)
  1544. {
  1545.   close (sock); /* Avoid sd leak. */
  1546.   continue;
  1547. }
  1548.       ret = listen (sock, 3);
  1549.       if (ret < 0) 
  1550. {
  1551.   close (sock); /* Avoid sd leak. */
  1552.   continue;
  1553. }
  1554.       vty_event (VTY_SERV, sock, NULL);
  1555.     }
  1556.   while ((ainfo = ainfo->ai_next) != NULL);
  1557.   freeaddrinfo (ainfo_save);
  1558. }
  1559. #endif /* ! (defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)) */
  1560. /* Make vty server socket. */
  1561. void
  1562. vty_serv_sock_family (unsigned short port, int family)
  1563. {
  1564.   int ret;
  1565.   union sockunion su;
  1566.   int accept_sock;
  1567.   memset (&su, 0, sizeof (union sockunion));
  1568.   su.sa.sa_family = family;
  1569.   /* Make new socket. */
  1570.   accept_sock = sockunion_stream_socket (&su);
  1571.   if (accept_sock < 0)
  1572.     return;
  1573.   /* This is server, so reuse address. */
  1574.   sockopt_reuseaddr (accept_sock);
  1575.   sockopt_reuseport (accept_sock);
  1576.   /* Bind socket to universal address and given port. */
  1577.   ret = sockunion_bind (accept_sock, &su, port, NULL);
  1578.   if (ret < 0)
  1579.     {
  1580.       close (accept_sock); /* Avoid sd leak. */
  1581.       return;
  1582.     }
  1583.   /* Listen socket under queue 3. */
  1584.   ret = listen (accept_sock, 3);
  1585.   if (ret < 0) 
  1586.     {
  1587.       zlog (NULL, LOG_WARNING, "can't listen socket");
  1588.       close (accept_sock); /* Avoid sd leak. */
  1589.       return;
  1590.     }
  1591.   /* Add vty server event. */
  1592.   vty_event (VTY_SERV, accept_sock, NULL);
  1593. }
  1594. #ifdef VTYSH
  1595. /* For sockaddr_un. */
  1596. #include <sys/un.h>
  1597. /* VTY shell UNIX domain socket. */
  1598. void
  1599. vty_serv_un (char *path)
  1600. {
  1601.   int ret;
  1602.   int sock, len;
  1603.   struct sockaddr_un serv;
  1604.   mode_t old_mask;
  1605.   /* First of all, unlink existing socket */
  1606.   unlink (path);
  1607.   /* Set umask */
  1608.   old_mask = umask (0077);
  1609.   /* Make UNIX domain socket. */
  1610.   sock = socket (AF_UNIX, SOCK_STREAM, 0);
  1611.   if (sock < 0)
  1612.     {
  1613.       perror ("sock");
  1614.       return;
  1615.     }
  1616.   /* Make server socket. */
  1617.   memset (&serv, 0, sizeof (struct sockaddr_un));
  1618.   serv.sun_family = AF_UNIX;
  1619.   strncpy (serv.sun_path, path, strlen (path));
  1620. #ifdef HAVE_SUN_LEN
  1621.   len = serv.sun_len = SUN_LEN(&serv);
  1622. #else
  1623.   len = sizeof (serv.sun_family) + strlen (serv.sun_path);
  1624. #endif /* HAVE_SUN_LEN */
  1625.   ret = bind (sock, (struct sockaddr *) &serv, len);
  1626.   if (ret < 0)
  1627.     {
  1628.       perror ("bind");
  1629.       close (sock); /* Avoid sd leak. */
  1630.       return;
  1631.     }
  1632.   ret = listen (sock, 5);
  1633.   if (ret < 0)
  1634.     {
  1635.       perror ("listen");
  1636.       close (sock); /* Avoid sd leak. */
  1637.       return;
  1638.     }
  1639.   umask (old_mask);
  1640.   vty_event (VTYSH_SERV, sock, NULL);
  1641. }
  1642. /* #define VTYSH_DEBUG 1 */
  1643. static int
  1644. vtysh_accept (struct thread *thread)
  1645. {
  1646.   int accept_sock;
  1647.   int sock;
  1648.   int client_len;
  1649.   struct sockaddr_un client;
  1650.   struct vty *vty;
  1651.   
  1652.   accept_sock = THREAD_FD (thread);
  1653.   vty_event (VTYSH_SERV, accept_sock, NULL);
  1654.   memset (&client, 0, sizeof (struct sockaddr_un));
  1655.   client_len = sizeof (struct sockaddr_un);
  1656.   sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
  1657.   if (sock < 0)
  1658.     {
  1659.       zlog_warn ("can't accept vty socket : %s", strerror (errno));
  1660.       return -1;
  1661.     }
  1662. #ifdef VTYSH_DEBUG
  1663.   printf ("VTY shell acceptn");
  1664. #endif /* VTYSH_DEBUG */
  1665.   vty = vty_new ();
  1666.   vty->fd = sock;
  1667.   vty->type = VTY_SHELL_SERV;
  1668.   vty->node = VIEW_NODE;
  1669.   vty_event (VTYSH_READ, sock, vty);
  1670.   return 0;
  1671. }
  1672. static int
  1673. vtysh_read (struct thread *thread)
  1674. {
  1675.   int ret;
  1676.   int sock;
  1677.   int nbytes;
  1678.   struct vty *vty;
  1679.   unsigned char buf[VTY_READ_BUFSIZ];
  1680.   u_char header[4] = {0, 0, 0, 0};
  1681.   sock = THREAD_FD (thread);
  1682.   vty = THREAD_ARG (thread);
  1683.   vty->t_read = NULL;
  1684.   nbytes = read (sock, buf, VTY_READ_BUFSIZ);
  1685.   if (nbytes <= 0)
  1686.     {
  1687.       vty_close (vty);
  1688. #ifdef VTYSH_DEBUG
  1689.       printf ("close vtyshn");
  1690. #endif /* VTYSH_DEBUG */
  1691.       return 0;
  1692.     }
  1693. #ifdef VTYSH_DEBUG
  1694.   printf ("line: %sn", buf);
  1695. #endif /* VTYSH_DEBUG */
  1696.   vty_ensure (vty, nbytes);
  1697.   memcpy (vty->buf, buf, nbytes);
  1698.   
  1699.   /* Pass this line to parser. */
  1700.   ret = vty_execute (vty);
  1701.   vty_clear_buf (vty);
  1702.   /* Return result. */
  1703. #ifdef VTYSH_DEBUG
  1704.   printf ("result: %dn", ret);
  1705.   printf ("vtysh node: %dn", vty->node);
  1706. #endif /* VTYSH_DEBUG */
  1707.   header[3] = ret;
  1708.   write (vty->fd, header, 4);
  1709.   vty_event (VTYSH_READ, sock, vty);
  1710.   return 0;
  1711. }
  1712. #endif /* VTYSH */
  1713. /* Determine address family to bind. */
  1714. void
  1715. vty_serv_sock (const char *hostname, unsigned short port, char *path)
  1716. {
  1717.   /* If port is set to 0, do not listen on TCP/IP at all! */
  1718.   if (port)
  1719.     {
  1720. #if defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)
  1721.       vty_serv_sock_addrinfo (hostname, port);
  1722. #else /* ! (defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)) */
  1723.       vty_serv_sock_family (port, AF_INET);
  1724. #endif /* HAVE_IPV6 */
  1725.     }
  1726. #ifdef VTYSH
  1727.   vty_serv_un (path);
  1728. #endif /* VTYSH */
  1729. }
  1730. /* Close vty interface. */
  1731. void
  1732. vty_close (struct vty *vty)
  1733. {
  1734.   int i;
  1735.   /* Cancel threads.*/
  1736.   if (vty->t_read)
  1737.     thread_cancel (vty->t_read);
  1738.   if (vty->t_write)
  1739.     thread_cancel (vty->t_write);
  1740.   if (vty->t_timeout)
  1741.     thread_cancel (vty->t_timeout);
  1742.   if (vty->t_output)
  1743.     thread_cancel (vty->t_output);
  1744.   /* Flush buffer. */
  1745.   if (! buffer_empty (vty->obuf))
  1746.     buffer_flush_all (vty->obuf, vty->fd);
  1747.   /* Free input buffer. */
  1748.   buffer_free (vty->obuf);
  1749.   /* Free SB buffer. */
  1750.   if (vty->sb_buffer)
  1751.     buffer_free (vty->sb_buffer);
  1752.   /* Free command history. */
  1753.   for (i = 0; i < VTY_MAXHIST; i++)
  1754.     if (vty->hist[i])
  1755.       XFREE (MTYPE_VTY_HIST, vty->hist[i]);
  1756.   /* Unset vector. */
  1757.   vector_unset (vtyvec, vty->fd);
  1758.   /* Close socket. */
  1759.   if (vty->fd > 0)
  1760.     close (vty->fd);
  1761.   if (vty->address)
  1762.     XFREE (0, vty->address);
  1763.   if (vty->buf)
  1764.     XFREE (MTYPE_VTY, vty->buf);
  1765.   /* Check configure. */
  1766.   vty_config_unlock (vty);
  1767.   /* OK free vty. */
  1768.   XFREE (MTYPE_VTY, vty);
  1769. }
  1770. /* When time out occur output message then close connection. */
  1771. static int
  1772. vty_timeout (struct thread *thread)
  1773. {
  1774.   struct vty *vty;
  1775.   vty = THREAD_ARG (thread);
  1776.   vty->t_timeout = NULL;
  1777.   vty->v_timeout = 0;
  1778.   /* Clear buffer*/
  1779.   buffer_reset (vty->obuf);
  1780.   vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
  1781.   /* Close connection. */
  1782.   vty->status = VTY_CLOSE;
  1783.   vty_close (vty);
  1784.   return 0;
  1785. }
  1786. /* Read up configuration file from file_name. */
  1787. static void
  1788. vty_read_file (FILE *confp)
  1789. {
  1790.   int ret;
  1791.   struct vty *vty;
  1792.   vty = vty_new ();
  1793.   vty->fd = 0; /* stdout */
  1794.   vty->type = VTY_TERM;
  1795.   vty->node = CONFIG_NODE;
  1796.   
  1797.   /* Execute configuration file */
  1798.   ret = config_from_file (vty, confp);
  1799.   if (ret != CMD_SUCCESS) 
  1800.     {
  1801.       switch (ret)
  1802. {
  1803. case CMD_ERR_AMBIGUOUS:
  1804.   fprintf (stderr, "Ambiguous command.n");
  1805.   break;
  1806. case CMD_ERR_NO_MATCH:
  1807.   fprintf (stderr, "There is no such command.n");
  1808.   break;
  1809. }
  1810.       fprintf (stderr, "Error occured during reading below line.n%sn", 
  1811.        vty->buf);
  1812.       vty_close (vty);
  1813.       exit (1);
  1814.     }
  1815.   vty_close (vty);
  1816. }
  1817. FILE *
  1818. vty_use_backup_config (char *fullpath)
  1819. {
  1820.   char *fullpath_sav, *fullpath_tmp;
  1821.   FILE *ret = NULL;
  1822.   struct stat buf;
  1823.   int tmp, sav;
  1824.   int c;
  1825.   char buffer[512];
  1826.   
  1827.   fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
  1828.   strcpy (fullpath_sav, fullpath);
  1829.   strcat (fullpath_sav, CONF_BACKUP_EXT);
  1830.   if (stat (fullpath_sav, &buf) == -1)
  1831.     {
  1832.       free (fullpath_sav);
  1833.       return NULL;
  1834.     }
  1835.   fullpath_tmp = malloc (strlen (fullpath) + 8);
  1836.   sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
  1837.   
  1838.   /* Open file to configuration write. */
  1839.   tmp = mkstemp (fullpath_tmp);
  1840.   if (tmp < 0)
  1841.     {
  1842.       free (fullpath_sav);
  1843.       free (fullpath_tmp);
  1844.       return NULL;
  1845.     }
  1846.   sav = open (fullpath_sav, O_RDONLY);
  1847.   if (sav < 0)
  1848.     {
  1849.       free (fullpath_sav);
  1850.       free (fullpath_tmp);
  1851.       unlink (fullpath_tmp);
  1852.       return NULL;
  1853.     }
  1854.   
  1855.   while((c = read (sav, buffer, 512)) > 0)
  1856.     write (tmp, buffer, c);
  1857.   
  1858.   close (sav);
  1859.   close (tmp);
  1860.   
  1861.   if (link (fullpath_tmp, fullpath) == 0)
  1862.     ret = fopen (fullpath, "r");
  1863.   unlink (fullpath_tmp);
  1864.   
  1865.   free (fullpath_sav);
  1866.   free (fullpath_tmp);
  1867.   return fopen (fullpath, "r");
  1868. }
  1869. /* Read up configuration file from file_name. */
  1870. void
  1871. vty_read_config (char *config_file,
  1872.  char *config_current_dir,
  1873.  char *config_default_dir)
  1874. {
  1875.   char *cwd;
  1876.   FILE *confp = NULL;
  1877.   char *fullpath;
  1878.   /* If -f flag specified. */
  1879.   if (config_file != NULL)
  1880.     {
  1881.       if (! IS_DIRECTORY_SEP (config_file[0]))
  1882. {
  1883.   cwd = getcwd (NULL, MAXPATHLEN);
  1884.   fullpath = XMALLOC (MTYPE_TMP, 
  1885.       strlen (cwd) + strlen (config_file) + 2);
  1886.   sprintf (fullpath, "%s/%s", cwd, config_file);
  1887. }
  1888.       else
  1889. fullpath = config_file;
  1890.       confp = fopen (fullpath, "r");
  1891.       if (confp == NULL)
  1892. {
  1893.   confp = vty_use_backup_config (fullpath);
  1894.   if (confp)
  1895.     fprintf (stderr, "WARNING: using backup configuration file!n");
  1896.   else
  1897.     {
  1898.       fprintf (stderr, "can't open configuration file [%s]n", 
  1899.        config_file);
  1900.       exit(1);
  1901.     }
  1902. }
  1903.     }
  1904.   else
  1905.     {
  1906.       /* Relative path configuration file open. */
  1907.       if (config_current_dir)
  1908. {
  1909.   confp = fopen (config_current_dir, "r");
  1910.   if (confp == NULL)
  1911.     {
  1912.       confp = vty_use_backup_config (config_current_dir);
  1913.       if (confp)
  1914. fprintf (stderr, "WARNING: using backup configuration file!n");
  1915.     }
  1916. }
  1917.       /* If there is no relative path exists, open system default file. */
  1918.       if (confp == NULL)
  1919. {
  1920. #ifdef VTYSH
  1921.   int ret;
  1922.   struct stat conf_stat;
  1923.   /* !!!!PLEASE LEAVE!!!!
  1924.      This is NEEDED for use with vtysh -b, or else you can get
  1925.      a real configuration food fight with a lot garbage in the
  1926.      merged configuration file it creates coming from the per
  1927.      daemon configuration files.  This also allows the daemons
  1928.      to start if there default configuration file is not
  1929.      present or ignore them, as needed when using vtysh -b to
  1930.      configure the daemons at boot - MAG */
  1931.   /* Stat for vtysh Zebra.conf, if found startup and wait for
  1932.      boot configuration */
  1933.   if ( strstr(config_default_dir, "vtysh") == NULL)
  1934.     {
  1935.       ret = stat (integrate_default, &conf_stat);
  1936.       if (ret >= 0)
  1937. {
  1938.   return;
  1939. }
  1940.     }
  1941. #endif /* VTYSH */
  1942.   confp = fopen (config_default_dir, "r");
  1943.   if (confp == NULL)
  1944.     {
  1945.       confp = vty_use_backup_config (config_default_dir);
  1946.       if (confp)
  1947. {
  1948.   fprintf (stderr, "WARNING: using backup configuration file!n");
  1949.   fullpath = config_default_dir;
  1950. }
  1951.       else
  1952. {
  1953.   fprintf (stderr, "can't open configuration file [%s]n",
  1954.    config_default_dir);
  1955.   exit (1);
  1956. }
  1957.     }      
  1958.   else
  1959.     fullpath = config_default_dir;
  1960. }
  1961.       else
  1962. {
  1963.   /* Rleative path configuration file. */
  1964.   cwd = getcwd (NULL, MAXPATHLEN);
  1965.   fullpath = XMALLOC (MTYPE_TMP, 
  1966.       strlen (cwd) + strlen (config_current_dir) + 2);
  1967.   sprintf (fullpath, "%s/%s", cwd, config_current_dir);
  1968. }  
  1969.     }  
  1970.   vty_read_file (confp);
  1971.   fclose (confp);
  1972.   host_config_set (fullpath);
  1973. }
  1974. /* Small utility function which output log to the VTY. */
  1975. void
  1976. vty_log (const char *proto_str, const char *format, va_list va)
  1977. {
  1978.   int i;
  1979.   struct vty *vty;
  1980.   for (i = 0; i < vector_max (vtyvec); i++)
  1981.     if ((vty = vector_slot (vtyvec, i)) != NULL)
  1982.       if (vty->monitor)
  1983. vty_log_out (vty, proto_str, format, va);
  1984. }
  1985. int
  1986. vty_config_lock (struct vty *vty)
  1987. {
  1988.   if (vty_config == 0)
  1989.     {
  1990.       vty->config = 1;
  1991.       vty_config = 1;
  1992.     }
  1993.   return vty->config;
  1994. }
  1995. int
  1996. vty_config_unlock (struct vty *vty)
  1997. {
  1998.   if (vty_config == 1 && vty->config == 1)
  1999.     {
  2000.       vty->config = 0;
  2001.       vty_config = 0;
  2002.     }
  2003.   return vty->config;
  2004. }
  2005. /* Master of the threads. */
  2006. extern struct thread_master *master;
  2007. /* struct thread_master *master; */
  2008. static void
  2009. vty_event (enum event event, int sock, struct vty *vty)
  2010. {
  2011.   struct thread *vty_serv_thread;
  2012.   switch (event)
  2013.     {
  2014.     case VTY_SERV:
  2015.       vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
  2016.       vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
  2017.       break;
  2018. #ifdef VTYSH
  2019.     case VTYSH_SERV:
  2020.       thread_add_read (master, vtysh_accept, vty, sock);
  2021.       break;
  2022.     case VTYSH_READ:
  2023.       thread_add_read (master, vtysh_read, vty, sock);
  2024.       break;
  2025. #endif /* VTYSH */
  2026.     case VTY_READ:
  2027.       vty->t_read = thread_add_read (master, vty_read, vty, sock);
  2028.       /* Time out treatment. */
  2029.       if (vty->v_timeout)
  2030. {
  2031.   if (vty->t_timeout)
  2032.     thread_cancel (vty->t_timeout);
  2033.   vty->t_timeout = 
  2034.     thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
  2035. }
  2036.       break;
  2037.     case VTY_WRITE:
  2038.       if (! vty->t_write)
  2039. vty->t_write = thread_add_write (master, vty_flush, vty, sock);
  2040.       break;
  2041.     case VTY_TIMEOUT_RESET:
  2042.       if (vty->t_timeout)
  2043. {
  2044.   thread_cancel (vty->t_timeout);
  2045.   vty->t_timeout = NULL;
  2046. }
  2047.       if (vty->v_timeout)
  2048. {
  2049.   vty->t_timeout = 
  2050.     thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
  2051. }
  2052.       break;
  2053.     }
  2054. }
  2055. DEFUN (config_who,
  2056.        config_who_cmd,
  2057.        "who",
  2058.        "Display who is on vtyn")
  2059. {
  2060.   int i;
  2061.   struct vty *v;
  2062.   for (i = 0; i < vector_max (vtyvec); i++)
  2063.     if ((v = vector_slot (vtyvec, i)) != NULL)
  2064.       vty_out (vty, "%svty[%d] connected from %s.%s",
  2065.        v->config ? "*" : " ",
  2066.        i, v->address, VTY_NEWLINE);
  2067.   return CMD_SUCCESS;
  2068. }
  2069. /* Move to vty configuration mode. */
  2070. DEFUN (line_vty,
  2071.        line_vty_cmd,
  2072.        "line vty",
  2073.        "Configure a terminal linen"
  2074.        "Virtual terminaln")
  2075. {
  2076.   vty->node = VTY_NODE;
  2077.   return CMD_SUCCESS;
  2078. }
  2079. /* Set time out value. */
  2080. int
  2081. exec_timeout (struct vty *vty, char *min_str, char *sec_str)
  2082. {
  2083.   unsigned long timeout = 0;
  2084.   /* min_str and sec_str are already checked by parser.  So it must be
  2085.      all digit string. */
  2086.   if (min_str)
  2087.     {
  2088.       timeout = strtol (min_str, NULL, 10);
  2089.       timeout *= 60;
  2090.     }
  2091.   if (sec_str)
  2092.     timeout += strtol (sec_str, NULL, 10);
  2093.   vty_timeout_val = timeout;
  2094.   vty->v_timeout = timeout;
  2095.   vty_event (VTY_TIMEOUT_RESET, 0, vty);
  2096.   return CMD_SUCCESS;
  2097. }
  2098. DEFUN (exec_timeout_min,
  2099.        exec_timeout_min_cmd,
  2100.        "exec-timeout <0-35791>",
  2101.        "Set timeout valuen"
  2102.        "Timeout value in minutesn")
  2103. {
  2104.   return exec_timeout (vty, argv[0], NULL);
  2105. }
  2106. DEFUN (exec_timeout_sec,
  2107.        exec_timeout_sec_cmd,
  2108.        "exec-timeout <0-35791> <0-2147483>",
  2109.        "Set the EXEC timeoutn"
  2110.        "Timeout in minutesn"
  2111.        "Timeout in secondsn")
  2112. {
  2113.   return exec_timeout (vty, argv[0], argv[1]);
  2114. }
  2115. DEFUN (no_exec_timeout,
  2116.        no_exec_timeout_cmd,
  2117.        "no exec-timeout",
  2118.        NO_STR
  2119.        "Set the EXEC timeoutn")
  2120. {
  2121.   return exec_timeout (vty, NULL, NULL);
  2122. }
  2123. /* Set vty access class. */
  2124. DEFUN (vty_access_class,
  2125.        vty_access_class_cmd,
  2126.        "access-class WORD",
  2127.        "Filter connections based on an IP access listn"
  2128.        "IP access listn")
  2129. {
  2130.   if (vty_accesslist_name)
  2131.     XFREE(MTYPE_VTY, vty_accesslist_name);
  2132.   vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
  2133.   return CMD_SUCCESS;
  2134. }
  2135. /* Clear vty access class. */
  2136. DEFUN (no_vty_access_class,
  2137.        no_vty_access_class_cmd,
  2138.        "no access-class [WORD]",
  2139.        NO_STR
  2140.        "Filter connections based on an IP access listn"
  2141.        "IP access listn")
  2142. {
  2143.   if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
  2144.     {
  2145.       vty_out (vty, "Access-class is not currently applied to vty%s",
  2146.        VTY_NEWLINE);
  2147.       return CMD_WARNING;
  2148.     }
  2149.   XFREE(MTYPE_VTY, vty_accesslist_name);
  2150.   vty_accesslist_name = NULL;
  2151.   return CMD_SUCCESS;
  2152. }
  2153. #ifdef HAVE_IPV6
  2154. /* Set vty access class. */
  2155. DEFUN (vty_ipv6_access_class,
  2156.        vty_ipv6_access_class_cmd,
  2157.        "ipv6 access-class WORD",
  2158.        IPV6_STR
  2159.        "Filter connections based on an IP access listn"
  2160.        "IPv6 access listn")
  2161. {
  2162.   if (vty_ipv6_accesslist_name)
  2163.     XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
  2164.   vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
  2165.   return CMD_SUCCESS;
  2166. }
  2167. /* Clear vty access class. */
  2168. DEFUN (no_vty_ipv6_access_class,
  2169.        no_vty_ipv6_access_class_cmd,
  2170.        "no ipv6 access-class [WORD]",
  2171.        NO_STR
  2172.        IPV6_STR
  2173.        "Filter connections based on an IP access listn"
  2174.        "IPv6 access listn")
  2175. {
  2176.   if (! vty_ipv6_accesslist_name ||
  2177.       (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
  2178.     {
  2179.       vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
  2180.        VTY_NEWLINE);
  2181.       return CMD_WARNING;
  2182.     }
  2183.   XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
  2184.   vty_ipv6_accesslist_name = NULL;
  2185.   return CMD_SUCCESS;
  2186. }
  2187. #endif /* HAVE_IPV6 */
  2188. /* vty login. */
  2189. DEFUN (vty_login,
  2190.        vty_login_cmd,
  2191.        "login",
  2192.        "Enable password checkingn")
  2193. {
  2194.   no_password_check = 0;
  2195.   return CMD_SUCCESS;
  2196. }
  2197. DEFUN (no_vty_login,
  2198.        no_vty_login_cmd,
  2199.        "no login",
  2200.        NO_STR
  2201.        "Enable password checkingn")
  2202. {
  2203.   no_password_check = 1;
  2204.   return CMD_SUCCESS;
  2205. }
  2206. DEFUN (service_advanced_vty,
  2207.        service_advanced_vty_cmd,
  2208.        "service advanced-vty",
  2209.        "Set up miscellaneous servicen"
  2210.        "Enable advanced mode vty interfacen")
  2211. {
  2212.   host.advanced = 1;
  2213.   return CMD_SUCCESS;
  2214. }
  2215. DEFUN (no_service_advanced_vty,
  2216.        no_service_advanced_vty_cmd,
  2217.        "no service advanced-vty",
  2218.        NO_STR
  2219.        "Set up miscellaneous servicen"
  2220.        "Enable advanced mode vty interfacen")
  2221. {
  2222.   host.advanced = 0;
  2223.   return CMD_SUCCESS;
  2224. }
  2225. DEFUN (terminal_monitor,
  2226.        terminal_monitor_cmd,
  2227.        "terminal monitor",
  2228.        "Set terminal line parametersn"
  2229.        "Copy debug output to the current terminal linen")
  2230. {
  2231.   vty->monitor = 1;
  2232.   return CMD_SUCCESS;
  2233. }
  2234. DEFUN (terminal_no_monitor,
  2235.        terminal_no_monitor_cmd,
  2236.        "terminal no monitor",
  2237.        "Set terminal line parametersn"
  2238.        NO_STR
  2239.        "Copy debug output to the current terminal linen")
  2240. {
  2241.   vty->monitor = 0;
  2242.   return CMD_SUCCESS;
  2243. }
  2244. DEFUN (show_history,
  2245.        show_history_cmd,
  2246.        "show history",
  2247.        SHOW_STR
  2248.        "Display the session command historyn")
  2249. {
  2250.   int index;
  2251.   for (index = vty->hindex + 1; index != vty->hindex;)
  2252.     {
  2253.       if (index == VTY_MAXHIST)
  2254. {
  2255.   index = 0;
  2256.   continue;
  2257. }
  2258.       if (vty->hist[index] != NULL)
  2259. vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
  2260.       index++;
  2261.     }
  2262.   return CMD_SUCCESS;
  2263. }
  2264. /* Display current configuration. */
  2265. int
  2266. vty_config_write (struct vty *vty)
  2267. {
  2268.   vty_out (vty, "line vty%s", VTY_NEWLINE);
  2269.   if (vty_accesslist_name)
  2270.     vty_out (vty, " access-class %s%s",
  2271.      vty_accesslist_name, VTY_NEWLINE);
  2272.   if (vty_ipv6_accesslist_name)
  2273.     vty_out (vty, " ipv6 access-class %s%s",
  2274.      vty_ipv6_accesslist_name, VTY_NEWLINE);
  2275.   /* exec-timeout */
  2276.   if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
  2277.     vty_out (vty, " exec-timeout %ld %ld%s", 
  2278.      vty_timeout_val / 60,
  2279.      vty_timeout_val % 60, VTY_NEWLINE);
  2280.   /* login */
  2281.   if (no_password_check)
  2282.     vty_out (vty, " no login%s", VTY_NEWLINE);
  2283.   vty_out (vty, "!%s", VTY_NEWLINE);
  2284.   return CMD_SUCCESS;
  2285. }
  2286. struct cmd_node vty_node =
  2287.   {
  2288.     VTY_NODE,
  2289.     "%s(config-line)# ",
  2290.   };
  2291. /* Reset all VTY status. */
  2292. void
  2293. vty_reset ()
  2294. {
  2295.   int i;
  2296.   struct vty *vty;
  2297.   struct thread *vty_serv_thread;
  2298.   for (i = 0; i < vector_max (vtyvec); i++)
  2299.     if ((vty = vector_slot (vtyvec, i)) != NULL)
  2300.       {
  2301. buffer_reset (vty->obuf);
  2302. vty->status = VTY_CLOSE;
  2303. vty_close (vty);
  2304.       }
  2305.   for (i = 0; i < vector_max (Vvty_serv_thread); i++)
  2306.     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
  2307.       {
  2308. thread_cancel (vty_serv_thread);
  2309. vector_slot (Vvty_serv_thread, i) = NULL;
  2310.         close (i);
  2311.       }
  2312.   vty_timeout_val = VTY_TIMEOUT_DEFAULT;
  2313.   if (vty_accesslist_name)
  2314.     {
  2315.       XFREE(MTYPE_VTY, vty_accesslist_name);
  2316.       vty_accesslist_name = NULL;
  2317.     }
  2318.   if (vty_ipv6_accesslist_name)
  2319.     {
  2320.       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
  2321.       vty_ipv6_accesslist_name = NULL;
  2322.     }
  2323. }
  2324. /* for ospf6d easy temprary reload function */
  2325. /* vty_reset + close accept socket */
  2326. void
  2327. vty_finish ()
  2328. {
  2329.   int i;
  2330.   struct vty *vty;
  2331.   struct thread *vty_serv_thread;
  2332.   for (i = 0; i < vector_max (vtyvec); i++)
  2333.     if ((vty = vector_slot (vtyvec, i)) != NULL)
  2334.       {
  2335. buffer_reset (vty->obuf);
  2336. vty->status = VTY_CLOSE;
  2337. vty_close (vty);
  2338.       }
  2339.   for (i = 0; i < vector_max (Vvty_serv_thread); i++)
  2340.     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
  2341.       {
  2342. thread_cancel (vty_serv_thread);
  2343. vector_slot (Vvty_serv_thread, i) = NULL;
  2344.         close (i);
  2345.       }
  2346.   vty_timeout_val = VTY_TIMEOUT_DEFAULT;
  2347.   if (vty_accesslist_name)
  2348.     {
  2349.       XFREE(MTYPE_VTY, vty_accesslist_name);
  2350.       vty_accesslist_name = NULL;
  2351.     }
  2352.   if (vty_ipv6_accesslist_name)
  2353.     {
  2354.       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
  2355.       vty_ipv6_accesslist_name = NULL;
  2356.     }
  2357. }
  2358. void
  2359. vty_save_cwd ()
  2360. {
  2361.   char *cwd;
  2362.   cwd = getcwd (NULL, MAXPATHLEN);
  2363.   vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
  2364.   strcpy (vty_cwd, cwd);
  2365. }
  2366. char *
  2367. vty_get_cwd ()
  2368. {
  2369.   return vty_cwd;
  2370. }
  2371. int
  2372. vty_shell (struct vty *vty)
  2373. {
  2374.   return vty->type == VTY_SHELL ? 1 : 0;
  2375. }
  2376. int
  2377. vty_shell_serv (struct vty *vty)
  2378. {
  2379.   return vty->type == VTY_SHELL_SERV ? 1 : 0;
  2380. }
  2381. void
  2382. vty_init_vtysh ()
  2383. {
  2384.   vtyvec = vector_init (VECTOR_MIN_SIZE);
  2385. }
  2386. /* Install vty's own commands like `who' command. */
  2387. void
  2388. vty_init ()
  2389. {
  2390.   /* For further configuration read, preserve current directory. */
  2391.   vty_save_cwd ();
  2392.   vtyvec = vector_init (VECTOR_MIN_SIZE);
  2393.   /* Initilize server thread vector. */
  2394.   Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
  2395.   /* Install bgp top node. */
  2396.   install_node (&vty_node, vty_config_write);
  2397.   install_element (VIEW_NODE, &config_who_cmd);
  2398.   install_element (VIEW_NODE, &show_history_cmd);
  2399.   install_element (ENABLE_NODE, &config_who_cmd);
  2400.   install_element (CONFIG_NODE, &line_vty_cmd);
  2401.   install_element (CONFIG_NODE, &service_advanced_vty_cmd);
  2402.   install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
  2403.   install_element (CONFIG_NODE, &show_history_cmd);
  2404.   install_element (ENABLE_NODE, &terminal_monitor_cmd);
  2405.   install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
  2406.   install_element (ENABLE_NODE, &show_history_cmd);
  2407.   install_default (VTY_NODE);
  2408.   install_element (VTY_NODE, &exec_timeout_min_cmd);
  2409.   install_element (VTY_NODE, &exec_timeout_sec_cmd);
  2410.   install_element (VTY_NODE, &no_exec_timeout_cmd);
  2411.   install_element (VTY_NODE, &vty_access_class_cmd);
  2412.   install_element (VTY_NODE, &no_vty_access_class_cmd);
  2413.   install_element (VTY_NODE, &vty_login_cmd);
  2414.   install_element (VTY_NODE, &no_vty_login_cmd);
  2415. #ifdef HAVE_IPV6
  2416.   install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
  2417.   install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
  2418. #endif /* HAVE_IPV6 */
  2419. }