]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - lib/vty.c
7ca8354367525ca2d8e14646ad862e659e7f51a8
[quagga-debian.git] / lib / vty.c
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
23 #include <zebra.h>
24
25 #include "linklist.h"
26 #include "thread.h"
27 #include "buffer.h"
28 #include <lib/version.h>
29 #include "command.h"
30 #include "sockunion.h"
31 #include "memory.h"
32 #include "str.h"
33 #include "log.h"
34 #include "prefix.h"
35 #include "filter.h"
36 #include "vty.h"
37 #include "privs.h"
38 #include "network.h"
39
40 #include <arpa/telnet.h>
41 #include <termios.h>
42
43 #define VTY_BUFSIZ 4096
44
45 /* Vty events */
46 enum event 
47 {
48   VTY_SERV,
49   VTY_READ,
50   VTY_WRITE,
51   VTY_TIMEOUT_RESET,
52 #ifdef VTYSH
53   VTYSH_SERV,
54   VTYSH_READ,
55   VTYSH_WRITE
56 #endif /* VTYSH */
57 };
58
59 static void vty_event (enum event, int, struct vty *);
60
61 /* Extern host structure from command.c */
62 extern struct host host;
63
64 /* Vector which store each vty structure. */
65 static vector vtyvec;
66
67 /* Vty timeout value. */
68 static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
69
70 /* Vty access-class command */
71 static char *vty_accesslist_name = NULL;
72
73 /* Vty access-calss for IPv6. */
74 static char *vty_ipv6_accesslist_name = NULL;
75
76 /* VTY server thread. */
77 static vector Vvty_serv_thread;
78
79 /* Current directory. */
80 char *vty_cwd = NULL;
81
82 /* Configure lock. */
83 static int vty_config;
84
85 /* Login password check. */
86 static int no_password_check = 0;
87
88 /* Restrict unauthenticated logins? */
89 static const u_char restricted_mode_default = 0;
90 static u_char restricted_mode = 0;
91
92 /* Integrated configuration file path */
93 char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
94
95 static int do_log_commands = 0;
96
97 static void
98 vty_buf_assert (struct vty *vty)
99 {
100   assert (vty->cp <= vty->length);
101   assert (vty->length < vty->max); 
102   assert (vty->buf[vty->length] == '\0');
103 }
104
105 /* Sanity/safety wrappers around access to vty->buf */
106 static void
107 vty_buf_put (struct vty *vty, char c)
108 {
109   vty_buf_assert (vty);
110   vty->buf[vty->cp] = c;
111   vty->buf[vty->max - 1] = '\0';
112 }
113
114 /* VTY standard output function. */
115 int
116 vty_out (struct vty *vty, const char *format, ...)
117 {
118   va_list args;
119   int len = 0;
120   int size = 1024;
121   char buf[1024];
122   char *p = NULL;
123
124   if (vty_shell (vty))
125     {
126       va_start (args, format);
127       vprintf (format, args);
128       va_end (args);
129     }
130   else
131     {
132       /* Try to write to initial buffer.  */
133       va_start (args, format);
134       len = vsnprintf (buf, sizeof(buf), format, args);
135       va_end (args);
136
137       /* Initial buffer is not enough.  */
138       if (len < 0 || len >= size)
139         {
140           while (1)
141             {
142               if (len > -1)
143                 size = len + 1;
144               else
145                 size = size * 2;
146
147               p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
148               if (! p)
149                 return -1;
150
151               va_start (args, format);
152               len = vsnprintf (p, size, format, args);
153               va_end (args);
154
155               if (len > -1 && len < size)
156                 break;
157             }
158         }
159
160       /* When initial buffer is enough to store all output.  */
161       if (! p)
162         p = buf;
163
164       /* Pointer p must point out buffer. */
165       buffer_put (vty->obuf, (u_char *) p, len);
166
167       /* If p is not different with buf, it is allocated buffer.  */
168       if (p != buf)
169         XFREE (MTYPE_VTY_OUT_BUF, p);
170     }
171
172   return len;
173 }
174
175 static int
176 vty_log_out (struct vty *vty, const char *level, const char *proto_str,
177              const char *format, struct timestamp_control *ctl, va_list va)
178 {
179   int ret;
180   int len;
181   char buf[1024];
182
183   if (!ctl->already_rendered)
184     {
185       ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
186       ctl->already_rendered = 1;
187     }
188   if (ctl->len+1 >= sizeof(buf))
189     return -1;
190   memcpy(buf, ctl->buf, len = ctl->len);
191   buf[len++] = ' ';
192   buf[len] = '\0';
193
194   if (level)
195     ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str);
196   else
197     ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str);
198   if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
199     return -1;
200
201   if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
202       ((size_t)((len += ret)+2) > sizeof(buf)))
203     return -1;
204
205   buf[len++] = '\r';
206   buf[len++] = '\n';
207
208   if (write(vty->wfd, buf, len) < 0)
209     {
210       if (ERRNO_IO_RETRY(errno))
211         /* Kernel buffer is full, probably too much debugging output, so just
212            drop the data and ignore. */
213         return -1;
214       /* Fatal I/O error. */
215       vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
216       zlog_warn("%s: write failed to vty client fd %d, closing: %s",
217                 __func__, vty->fd, safe_strerror(errno));
218       buffer_reset(vty->obuf);
219       /* cannot call vty_close, because a parent routine may still try
220          to access the vty struct */
221       vty->status = VTY_CLOSE;
222       shutdown(vty->fd, SHUT_RDWR);
223       return -1;
224     }
225   return 0;
226 }
227
228 /* Output current time to the vty. */
229 void
230 vty_time_print (struct vty *vty, int cr)
231 {
232   char buf[QUAGGA_TIMESTAMP_LEN];
233   
234   if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
235     {
236       zlog (NULL, LOG_INFO, "quagga_timestamp error");
237       return;
238     }
239   if (cr)
240     vty_out (vty, "%s\n", buf);
241   else
242     vty_out (vty, "%s ", buf);
243
244   return;
245 }
246
247 /* Say hello to vty interface. */
248 void
249 vty_hello (struct vty *vty)
250 {
251   if (host.motdfile)
252     {
253       FILE *f;
254       char buf[4096];
255
256       f = fopen (host.motdfile, "r");
257       if (f)
258         {
259           while (fgets (buf, sizeof (buf), f))
260             {
261               char *s;
262               /* work backwards to ignore trailling isspace() */
263               for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
264                    s--);
265               *s = '\0';
266               vty_out (vty, "%s%s", buf, VTY_NEWLINE);
267             }
268           fclose (f);
269         }
270       else
271         vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
272     }
273   else if (host.motd)
274     vty_out (vty, "%s", host.motd);
275 }
276
277 /* Put out prompt and wait input from user. */
278 static void
279 vty_prompt (struct vty *vty)
280 {
281   struct utsname names;
282   const char*hostname;
283
284   if (vty->type == VTY_TERM)
285     {
286       hostname = host.name;
287       if (!hostname)
288         {
289           uname (&names);
290           hostname = names.nodename;
291         }
292       vty_out (vty, cmd_prompt (vty->node), hostname);
293     }
294 }
295
296 /* Send WILL TELOPT_ECHO to remote server. */
297 static void
298 vty_will_echo (struct vty *vty)
299 {
300   unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
301   vty_out (vty, "%s", cmd);
302 }
303
304 /* Make suppress Go-Ahead telnet option. */
305 static void
306 vty_will_suppress_go_ahead (struct vty *vty)
307 {
308   unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
309   vty_out (vty, "%s", cmd);
310 }
311
312 /* Make don't use linemode over telnet. */
313 static void
314 vty_dont_linemode (struct vty *vty)
315 {
316   unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
317   vty_out (vty, "%s", cmd);
318 }
319
320 /* Use window size. */
321 static void
322 vty_do_window_size (struct vty *vty)
323 {
324   unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
325   vty_out (vty, "%s", cmd);
326 }
327
328 #if 0 /* Currently not used. */
329 /* Make don't use lflow vty interface. */
330 static void
331 vty_dont_lflow_ahead (struct vty *vty)
332 {
333   unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
334   vty_out (vty, "%s", cmd);
335 }
336 #endif /* 0 */
337
338 /* Allocate new vty struct. */
339 struct vty *
340 vty_new ()
341 {
342   struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
343
344   new->obuf = buffer_new(0);    /* Use default buffer size. */
345   new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
346   new->max = VTY_BUFSIZ;
347
348   return new;
349 }
350
351 /* Authentication of vty */
352 static void
353 vty_auth (struct vty *vty, char *buf)
354 {
355   char *passwd = NULL;
356   enum node_type next_node = 0;
357   int fail;
358   char *crypt (const char *, const char *);
359
360   switch (vty->node)
361     {
362     case AUTH_NODE:
363       if (host.encrypt)
364         passwd = host.password_encrypt;
365       else
366         passwd = host.password;
367       if (host.advanced)
368         next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
369       else
370         next_node = VIEW_NODE;
371       break;
372     case AUTH_ENABLE_NODE:
373       if (host.encrypt)
374         passwd = host.enable_encrypt;
375       else
376         passwd = host.enable;
377       next_node = ENABLE_NODE;
378       break;
379     }
380
381   if (passwd)
382     {
383       if (host.encrypt)
384         fail = strcmp (crypt(buf, passwd), passwd);
385       else
386         fail = strcmp (buf, passwd);
387     }
388   else
389     fail = 1;
390
391   if (! fail)
392     {
393       vty->fail = 0;
394       vty->node = next_node;    /* Success ! */
395     }
396   else
397     {
398       vty->fail++;
399       if (vty->fail >= 3)
400         {
401           if (vty->node == AUTH_NODE)
402             {
403               vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
404               vty->status = VTY_CLOSE;
405             }
406           else                  
407             {
408               /* AUTH_ENABLE_NODE */
409               vty->fail = 0;
410               vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
411               vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
412             }
413         }
414     }
415 }
416
417 /* Command execution over the vty interface. */
418 static int
419 vty_command (struct vty *vty, char *buf)
420 {
421   int ret;
422   vector vline;
423   const char *protocolname;
424   char *cp = NULL;
425
426   /*
427    * Log non empty command lines
428    */
429   if (do_log_commands)
430     cp = buf;
431   if (cp != NULL)
432     {
433       /* Skip white spaces. */
434       while (isspace ((int) *cp) && *cp != '\0')
435         cp++;
436     }
437   if (cp != NULL && *cp != '\0')
438     {
439       unsigned i;
440       char      vty_str[VTY_BUFSIZ];
441       char        prompt_str[VTY_BUFSIZ];
442
443       /* format the base vty info */
444       snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
445       if (vty)
446         for (i = 0; i < vector_active (vtyvec); i++)
447           if (vty == vector_slot (vtyvec, i))
448             {
449               snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
450                                                  i, vty->address);
451               break;
452             }
453
454       /* format the prompt */
455       snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str);
456
457       /* now log the command */
458       zlog(NULL, LOG_ERR, "%s%s", prompt_str, buf);
459     }
460   /* Split readline string up into the vector */
461   vline = cmd_make_strvec (buf);
462
463   if (vline == NULL)
464     return CMD_SUCCESS;
465
466 #ifdef CONSUMED_TIME_CHECK
467   {
468     RUSAGE_T before;
469     RUSAGE_T after;
470     unsigned long realtime, cputime;
471
472     GETRUSAGE(&before);
473 #endif /* CONSUMED_TIME_CHECK */
474
475   ret = cmd_execute_command (vline, vty, NULL, 0);
476
477   /* Get the name of the protocol if any */
478   if (zlog_default)
479       protocolname = zlog_proto_names[zlog_default->protocol];
480   else
481       protocolname = zlog_proto_names[ZLOG_NONE];
482                                                                            
483 #ifdef CONSUMED_TIME_CHECK
484     GETRUSAGE(&after);
485     if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
486         CONSUMED_TIME_CHECK)
487       /* Warn about CPU hog that must be fixed. */
488       zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
489                 realtime/1000, cputime/1000, buf);
490   }
491 #endif /* CONSUMED_TIME_CHECK */
492
493   if (ret != CMD_SUCCESS)
494     switch (ret)
495       {
496       case CMD_WARNING:
497         if (vty->type == VTY_FILE)
498           vty_out (vty, "Warning...%s", VTY_NEWLINE);
499         break;
500       case CMD_ERR_AMBIGUOUS:
501         vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
502         break;
503       case CMD_ERR_NO_MATCH:
504         vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
505         break;
506       case CMD_ERR_INCOMPLETE:
507         vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
508         break;
509       }
510   cmd_free_strvec (vline);
511
512   return ret;
513 }
514
515 static const char telnet_backward_char = 0x08;
516 static const char telnet_space_char = ' ';
517
518 /* Basic function to write buffer to vty. */
519 static void
520 vty_write (struct vty *vty, const char *buf, size_t nbytes)
521 {
522   if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
523     return;
524
525   /* Should we do buffering here ?  And make vty_flush (vty) ? */
526   buffer_put (vty->obuf, buf, nbytes);
527 }
528
529 /* Basic function to insert character into vty. */
530 static void
531 vty_self_insert (struct vty *vty, char c)
532 {
533   int i;
534   int length;
535   
536   vty_buf_assert (vty);
537   
538   /* length is sans nul, max is with */
539   if (vty->length + 1 >= vty->max)
540     return;
541
542   length = vty->length - vty->cp;
543   memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
544   vty->length++;
545   vty->buf[vty->length] = '\0';
546
547   vty_buf_put (vty, c);
548
549   vty_write (vty, &vty->buf[vty->cp], length + 1);
550   for (i = 0; i < length; i++)
551     vty_write (vty, &telnet_backward_char, 1);
552
553   vty->cp++;
554   
555   vty_buf_assert (vty);
556 }
557
558 /* Self insert character 'c' in overwrite mode. */
559 static void
560 vty_self_insert_overwrite (struct vty *vty, char c)
561 {
562   vty_buf_assert (vty);
563   
564   if (vty->cp == vty->length)
565     {
566       vty_self_insert (vty, c);
567       return;
568     }
569
570   vty_buf_put (vty, c);
571   vty->cp++;
572   
573   vty_buf_assert (vty);
574   
575   vty_write (vty, &c, 1);
576 }
577
578 /**
579  * Insert a string into vty->buf at the current cursor position.
580  *
581  * If the resultant string would be larger than VTY_BUFSIZ it is
582  * truncated to fit.
583  */
584 static void
585 vty_insert_word_overwrite (struct vty *vty, char *str)
586 {
587   vty_buf_assert (vty);
588   
589   size_t nwrite = MIN ((int) strlen (str), vty->max - vty->cp - 1);
590   memcpy (&vty->buf[vty->cp], str, nwrite);
591   vty->cp += nwrite;
592   vty->length = vty->cp;
593   vty->buf[vty->length] = '\0';
594   vty_buf_assert (vty);
595   
596   vty_write (vty, str, nwrite);
597 }
598
599 /* Forward character. */
600 static void
601 vty_forward_char (struct vty *vty)
602 {
603   vty_buf_assert (vty);
604   
605   if (vty->cp < vty->length)
606     {
607       vty_write (vty, &vty->buf[vty->cp], 1);
608       vty->cp++;
609     }
610   
611   vty_buf_assert (vty);
612 }
613
614 /* Backward character. */
615 static void
616 vty_backward_char (struct vty *vty)
617 {
618   vty_buf_assert (vty);
619   
620   if (vty->cp > 0)
621     {
622       vty->cp--;
623       vty_write (vty, &telnet_backward_char, 1);
624     }
625   
626   vty_buf_assert (vty);
627 }
628
629 /* Move to the beginning of the line. */
630 static void
631 vty_beginning_of_line (struct vty *vty)
632 {
633   while (vty->cp)
634     vty_backward_char (vty);
635 }
636
637 /* Move to the end of the line. */
638 static void
639 vty_end_of_line (struct vty *vty)
640 {
641   while (vty->cp < vty->length)
642     vty_forward_char (vty);
643 }
644
645 static void vty_kill_line_from_beginning (struct vty *);
646 static void vty_redraw_line (struct vty *);
647
648 /* Print command line history.  This function is called from
649    vty_next_line and vty_previous_line. */
650 static void
651 vty_history_print (struct vty *vty)
652 {
653   int length;
654
655   vty_kill_line_from_beginning (vty);
656
657   /* Get previous line from history buffer */
658   length = strlen (vty->hist[vty->hp]);
659   memcpy (vty->buf, vty->hist[vty->hp], length);
660   vty->cp = vty->length = length;
661   vty->buf[vty->length] = '\0';
662   vty_buf_assert (vty);
663   
664   /* Redraw current line */
665   vty_redraw_line (vty);
666 }
667
668 /* Show next command line history. */
669 static void
670 vty_next_line (struct vty *vty)
671 {
672   int try_index;
673
674   if (vty->hp == vty->hindex)
675     return;
676
677   /* Try is there history exist or not. */
678   try_index = vty->hp;
679   if (try_index == (VTY_MAXHIST - 1))
680     try_index = 0;
681   else
682     try_index++;
683
684   /* If there is not history return. */
685   if (vty->hist[try_index] == NULL)
686     return;
687   else
688     vty->hp = try_index;
689
690   vty_history_print (vty);
691 }
692
693 /* Show previous command line history. */
694 static void
695 vty_previous_line (struct vty *vty)
696 {
697   int try_index;
698
699   try_index = vty->hp;
700   if (try_index == 0)
701     try_index = VTY_MAXHIST - 1;
702   else
703     try_index--;
704
705   if (vty->hist[try_index] == NULL)
706     return;
707   else
708     vty->hp = try_index;
709
710   vty_history_print (vty);
711 }
712
713 /* This function redraw all of the command line character. */
714 static void
715 vty_redraw_line (struct vty *vty)
716 {
717   vty_write (vty, vty->buf, vty->length);
718   vty->cp = vty->length;
719   
720   vty_buf_assert (vty);
721 }
722
723 /* Forward word. */
724 static void
725 vty_forward_word (struct vty *vty)
726 {
727   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
728     vty_forward_char (vty);
729   
730   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
731     vty_forward_char (vty);
732 }
733
734 /* Backward word without skipping training space. */
735 static void
736 vty_backward_pure_word (struct vty *vty)
737 {
738   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
739     vty_backward_char (vty);
740 }
741
742 /* Backward word. */
743 static void
744 vty_backward_word (struct vty *vty)
745 {
746   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
747     vty_backward_char (vty);
748
749   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
750     vty_backward_char (vty);
751 }
752
753 /* When '^D' is typed at the beginning of the line we move to the down
754    level. */
755 static void
756 vty_down_level (struct vty *vty)
757 {
758   vty_out (vty, "%s", VTY_NEWLINE);
759   (*config_exit_cmd.func)(NULL, vty, 0, NULL);
760   vty_prompt (vty);
761   vty->cp = 0;
762 }
763
764 /* When '^Z' is received from vty, move down to the enable mode. */
765 static void
766 vty_end_config (struct vty *vty)
767 {
768   vty_out (vty, "%s", VTY_NEWLINE);
769
770   switch (vty->node)
771     {
772     case VIEW_NODE:
773     case ENABLE_NODE:
774     case RESTRICTED_NODE:
775       /* Nothing to do. */
776       break;
777     case CONFIG_NODE:
778     case INTERFACE_NODE:
779     case ZEBRA_NODE:
780     case RIP_NODE:
781     case RIPNG_NODE:
782     case BABEL_NODE:
783     case BGP_NODE:
784     case BGP_VPNV4_NODE:
785     case BGP_VPNV6_NODE:
786     case BGP_ENCAP_NODE:
787     case BGP_ENCAPV6_NODE:
788     case BGP_IPV4_NODE:
789     case BGP_IPV4M_NODE:
790     case BGP_IPV6_NODE:
791     case BGP_IPV6M_NODE:
792     case RMAP_NODE:
793     case OSPF_NODE:
794     case OSPF6_NODE:
795     case ISIS_NODE:
796     case KEYCHAIN_NODE:
797     case KEYCHAIN_KEY_NODE:
798     case MASC_NODE:
799     case PIM_NODE:
800     case VTY_NODE:
801       vty_config_unlock (vty);
802       vty->node = ENABLE_NODE;
803       break;
804     default:
805       /* Unknown node, we have to ignore it. */
806       break;
807     }
808
809   vty_prompt (vty);
810   vty->cp = 0;
811 }
812
813 /* Delete a charcter at the current point. */
814 static void
815 vty_delete_char (struct vty *vty)
816 {
817   int i;
818   int size;
819
820   if (vty->length == 0)
821     {
822       vty_down_level (vty);
823       return;
824     }
825   
826   if (vty->cp == vty->length)
827     return;                     /* completion need here? */
828
829   vty_buf_assert (vty);
830   
831   size = vty->length - vty->cp;
832
833   vty->length--;
834   memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
835   vty->buf[vty->length] = '\0';
836   
837   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
838     return;
839
840   vty_write (vty, &vty->buf[vty->cp], size - 1);
841   vty_write (vty, &telnet_space_char, 1);
842
843   for (i = 0; i < size; i++)
844     vty_write (vty, &telnet_backward_char, 1);
845 }
846
847 /* Delete a character before the point. */
848 static void
849 vty_delete_backward_char (struct vty *vty)
850 {
851   if (vty->cp == 0)
852     return;
853
854   vty_backward_char (vty);
855   vty_delete_char (vty);
856 }
857
858 /* Kill rest of line from current point. */
859 static void
860 vty_kill_line (struct vty *vty)
861 {
862   int i;
863   int size;
864
865   size = vty->length - vty->cp;
866   
867   if (size == 0)
868     return;
869
870   for (i = 0; i < size; i++)
871     vty_write (vty, &telnet_space_char, 1);
872   for (i = 0; i < size; i++)
873     vty_write (vty, &telnet_backward_char, 1);
874
875   memset (&vty->buf[vty->cp], 0, size);
876   vty->length = vty->cp;
877   vty_buf_assert (vty);
878 }
879
880 /* Kill line from the beginning. */
881 static void
882 vty_kill_line_from_beginning (struct vty *vty)
883 {
884   vty_beginning_of_line (vty);
885   vty_kill_line (vty);
886 }
887
888 /* Delete a word before the point. */
889 static void
890 vty_forward_kill_word (struct vty *vty)
891 {
892   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
893     vty_delete_char (vty);
894   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
895     vty_delete_char (vty);
896 }
897
898 /* Delete a word before the point. */
899 static void
900 vty_backward_kill_word (struct vty *vty)
901 {
902   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
903     vty_delete_backward_char (vty);
904   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
905     vty_delete_backward_char (vty);
906 }
907
908 /* Transpose chars before or at the point. */
909 static void
910 vty_transpose_chars (struct vty *vty)
911 {
912   char c1, c2;
913
914   /* If length is short or point is near by the beginning of line then
915      return. */
916   if (vty->length < 2 || vty->cp < 1)
917     return;
918
919   /* In case of point is located at the end of the line. */
920   if (vty->cp == vty->length)
921     {
922       c1 = vty->buf[vty->cp - 1];
923       c2 = vty->buf[vty->cp - 2];
924
925       vty_backward_char (vty);
926       vty_backward_char (vty);
927       vty_self_insert_overwrite (vty, c1);
928       vty_self_insert_overwrite (vty, c2);
929     }
930   else
931     {
932       c1 = vty->buf[vty->cp];
933       c2 = vty->buf[vty->cp - 1];
934
935       vty_backward_char (vty);
936       vty_self_insert_overwrite (vty, c1);
937       vty_self_insert_overwrite (vty, c2);
938     }
939 }
940
941 /* Do completion at vty interface. */
942 static void
943 vty_complete_command (struct vty *vty)
944 {
945   int i;
946   int ret;
947   char **matched = NULL;
948   vector vline;
949
950   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
951     return;
952
953   vline = cmd_make_strvec (vty->buf);
954   if (vline == NULL)
955     return;
956
957   /* In case of 'help \t'. */
958   if (isspace ((int) vty->buf[vty->length - 1]))
959     vector_set (vline, NULL);
960
961   matched = cmd_complete_command_lib (vline, vty, &ret, 1);
962   
963   cmd_free_strvec (vline);
964
965   vty_out (vty, "%s", VTY_NEWLINE);
966   switch (ret)
967     {
968     case CMD_ERR_AMBIGUOUS:
969       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
970       vty_prompt (vty);
971       vty_redraw_line (vty);
972       break;
973     case CMD_ERR_NO_MATCH:
974       /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
975       vty_prompt (vty);
976       vty_redraw_line (vty);
977       break;
978     case CMD_COMPLETE_FULL_MATCH:
979       vty_prompt (vty);
980       vty_redraw_line (vty);
981       vty_backward_pure_word (vty);
982       vty_insert_word_overwrite (vty, matched[0]);
983       vty_self_insert (vty, ' ');
984       XFREE (MTYPE_TMP, matched[0]);
985       break;
986     case CMD_COMPLETE_MATCH:
987       vty_prompt (vty);
988       vty_redraw_line (vty);
989       vty_backward_pure_word (vty);
990       vty_insert_word_overwrite (vty, matched[0]);
991       XFREE (MTYPE_TMP, matched[0]);
992       vector_only_index_free (matched);
993       return;
994       break;
995     case CMD_COMPLETE_LIST_MATCH:
996       for (i = 0; matched[i] != NULL; i++)
997         {
998           if (i != 0 && ((i % 6) == 0))
999             vty_out (vty, "%s", VTY_NEWLINE);
1000           vty_out (vty, "%-10s ", matched[i]);
1001           XFREE (MTYPE_TMP, matched[i]);
1002         }
1003       vty_out (vty, "%s", VTY_NEWLINE);
1004
1005       vty_prompt (vty);
1006       vty_redraw_line (vty);
1007       break;
1008     case CMD_ERR_NOTHING_TODO:
1009       vty_prompt (vty);
1010       vty_redraw_line (vty);
1011       break;
1012     default:
1013       break;
1014     }
1015   if (matched)
1016     vector_only_index_free (matched);
1017 }
1018
1019 static void
1020 vty_describe_fold (struct vty *vty, int cmd_width,
1021                    unsigned int desc_width, struct cmd_token *token)
1022 {
1023   char *buf;
1024   const char *cmd, *p;
1025   int pos;
1026
1027   cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
1028
1029   if (desc_width <= 0)
1030     {
1031       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
1032       return;
1033     }
1034
1035   buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
1036
1037   for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
1038     {
1039       for (pos = desc_width; pos > 0; pos--)
1040       if (*(p + pos) == ' ')
1041         break;
1042
1043       if (pos == 0)
1044       break;
1045
1046       strncpy (buf, p, pos);
1047       buf[pos] = '\0';
1048       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
1049
1050       cmd = "";
1051     }
1052
1053   vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
1054
1055   XFREE (MTYPE_TMP, buf);
1056 }
1057
1058 /* Describe matched command function. */
1059 static void
1060 vty_describe_command (struct vty *vty)
1061 {
1062   int ret;
1063   vector vline;
1064   vector describe;
1065   unsigned int i, width, desc_width;
1066   struct cmd_token *token, *token_cr = NULL;
1067
1068   vline = cmd_make_strvec (vty->buf);
1069
1070   /* In case of '> ?'. */
1071   if (vline == NULL)
1072     {
1073       vline = vector_init (1);
1074       vector_set (vline, NULL);
1075     }
1076   else 
1077     if (isspace ((int) vty->buf[vty->length - 1]))
1078       vector_set (vline, NULL);
1079
1080   describe = cmd_describe_command (vline, vty, &ret);
1081
1082   vty_out (vty, "%s", VTY_NEWLINE);
1083
1084   /* Ambiguous error. */
1085   switch (ret)
1086     {
1087     case CMD_ERR_AMBIGUOUS:
1088       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
1089       goto out;
1090       break;
1091     case CMD_ERR_NO_MATCH:
1092       vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
1093       goto out;
1094       break;
1095     }  
1096
1097   /* Get width of command string. */
1098   width = 0;
1099   for (i = 0; i < vector_active (describe); i++)
1100     if ((token = vector_slot (describe, i)) != NULL)
1101       {
1102         unsigned int len;
1103
1104         if (token->cmd[0] == '\0')
1105           continue;
1106
1107         len = strlen (token->cmd);
1108         if (token->cmd[0] == '.')
1109           len--;
1110
1111         if (width < len)
1112           width = len;
1113       }
1114
1115   /* Get width of description string. */
1116   desc_width = vty->width - (width + 6);
1117
1118   /* Print out description. */
1119   for (i = 0; i < vector_active (describe); i++)
1120     if ((token = vector_slot (describe, i)) != NULL)
1121       {
1122         if (token->cmd[0] == '\0')
1123           continue;
1124         
1125         if (strcmp (token->cmd, command_cr) == 0)
1126           {
1127             token_cr = token;
1128             continue;
1129           }
1130
1131         if (!token->desc)
1132           vty_out (vty, "  %-s%s",
1133                    token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1134                    VTY_NEWLINE);
1135         else if (desc_width >= strlen (token->desc))
1136           vty_out (vty, "  %-*s  %s%s", width,
1137                    token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1138                    token->desc, VTY_NEWLINE);
1139         else
1140           vty_describe_fold (vty, width, desc_width, token);
1141
1142 #if 0
1143         vty_out (vty, "  %-*s %s%s", width
1144                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1145                  desc->str ? desc->str : "", VTY_NEWLINE);
1146 #endif /* 0 */
1147       }
1148
1149   if ((token = token_cr))
1150     {
1151       if (!token->desc)
1152         vty_out (vty, "  %-s%s",
1153                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1154                  VTY_NEWLINE);
1155       else if (desc_width >= strlen (token->desc))
1156         vty_out (vty, "  %-*s  %s%s", width,
1157                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1158                  token->desc, VTY_NEWLINE);
1159       else
1160         vty_describe_fold (vty, width, desc_width, token);
1161     }
1162
1163 out:
1164   cmd_free_strvec (vline);
1165   if (describe)
1166     vector_free (describe);
1167
1168   vty_prompt (vty);
1169   vty_redraw_line (vty);
1170 }
1171
1172 static void
1173 vty_clear_buf (struct vty *vty)
1174 {
1175   memset (vty->buf, 0, vty->max);
1176 }
1177
1178 /* ^C stop current input and do not add command line to the history. */
1179 static void
1180 vty_stop_input (struct vty *vty)
1181 {
1182   vty->cp = vty->length = 0;
1183   vty_clear_buf (vty);
1184   vty_out (vty, "%s", VTY_NEWLINE);
1185
1186   switch (vty->node)
1187     {
1188     case VIEW_NODE:
1189     case ENABLE_NODE:
1190     case RESTRICTED_NODE:
1191       /* Nothing to do. */
1192       break;
1193     case CONFIG_NODE:
1194     case INTERFACE_NODE:
1195     case ZEBRA_NODE:
1196     case RIP_NODE:
1197     case RIPNG_NODE:
1198     case BABEL_NODE:
1199     case BGP_NODE:
1200     case RMAP_NODE:
1201     case OSPF_NODE:
1202     case OSPF6_NODE:
1203     case ISIS_NODE:
1204     case KEYCHAIN_NODE:
1205     case KEYCHAIN_KEY_NODE:
1206     case MASC_NODE:
1207     case PIM_NODE:
1208     case VTY_NODE:
1209       vty_config_unlock (vty);
1210       vty->node = ENABLE_NODE;
1211       break;
1212     default:
1213       /* Unknown node, we have to ignore it. */
1214       break;
1215     }
1216   vty_prompt (vty);
1217
1218   /* Set history pointer to the latest one. */
1219   vty->hp = vty->hindex;
1220 }
1221
1222 /* Add current command line to the history buffer. */
1223 static void
1224 vty_hist_add (struct vty *vty)
1225 {
1226   int index;
1227
1228   if (vty->length == 0)
1229     return;
1230
1231   index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1232
1233   /* Ignore the same string as previous one. */
1234   if (vty->hist[index])
1235     if (strcmp (vty->buf, vty->hist[index]) == 0)
1236       {
1237       vty->hp = vty->hindex;
1238       return;
1239       }
1240
1241   /* Insert history entry. */
1242   if (vty->hist[vty->hindex])
1243     XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1244   vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1245
1246   /* History index rotation. */
1247   vty->hindex++;
1248   if (vty->hindex == VTY_MAXHIST)
1249     vty->hindex = 0;
1250
1251   vty->hp = vty->hindex;
1252 }
1253
1254 /* #define TELNET_OPTION_DEBUG */
1255
1256 /* Get telnet window size. */
1257 static int
1258 vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1259 {
1260 #ifdef TELNET_OPTION_DEBUG
1261   int i;
1262
1263   for (i = 0; i < nbytes; i++)
1264     {
1265       switch (buf[i])
1266         {
1267         case IAC:
1268           vty_out (vty, "IAC ");
1269           break;
1270         case WILL:
1271           vty_out (vty, "WILL ");
1272           break;
1273         case WONT:
1274           vty_out (vty, "WONT ");
1275           break;
1276         case DO:
1277           vty_out (vty, "DO ");
1278           break;
1279         case DONT:
1280           vty_out (vty, "DONT ");
1281           break;
1282         case SB:
1283           vty_out (vty, "SB ");
1284           break;
1285         case SE:
1286           vty_out (vty, "SE ");
1287           break;
1288         case TELOPT_ECHO:
1289           vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1290           break;
1291         case TELOPT_SGA:
1292           vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1293           break;
1294         case TELOPT_NAWS:
1295           vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1296           break;
1297         default:
1298           vty_out (vty, "%x ", buf[i]);
1299           break;
1300         }
1301     }
1302   vty_out (vty, "%s", VTY_NEWLINE);
1303
1304 #endif /* TELNET_OPTION_DEBUG */
1305
1306   switch (buf[0])
1307     {
1308     case SB:
1309       vty->sb_len = 0;
1310       vty->iac_sb_in_progress = 1;
1311       return 0;
1312       break;
1313     case SE: 
1314       {
1315         if (!vty->iac_sb_in_progress)
1316           return 0;
1317
1318         if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
1319           {
1320             vty->iac_sb_in_progress = 0;
1321             return 0;
1322           }
1323         switch (vty->sb_buf[0])
1324           {
1325           case TELOPT_NAWS:
1326             if (vty->sb_len != TELNET_NAWS_SB_LEN)
1327               zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1328                         "should send %d characters, but we received %lu",
1329                         TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1330             else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1331               zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1332                        "too small to handle the telnet NAWS option",
1333                        (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1334             else
1335               {
1336                 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1337                 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1338 #ifdef TELNET_OPTION_DEBUG
1339                 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1340                               "width %d, height %d%s",
1341                         vty->width, vty->height, VTY_NEWLINE);
1342 #endif
1343               }
1344             break;
1345           }
1346         vty->iac_sb_in_progress = 0;
1347         return 0;
1348         break;
1349       }
1350     default:
1351       break;
1352     }
1353   return 1;
1354 }
1355
1356 /* Execute current command line. */
1357 static int
1358 vty_execute (struct vty *vty)
1359 {
1360   int ret;
1361
1362   ret = CMD_SUCCESS;
1363
1364   switch (vty->node)
1365     {
1366     case AUTH_NODE:
1367     case AUTH_ENABLE_NODE:
1368       vty_auth (vty, vty->buf);
1369       break;
1370     default:
1371       ret = vty_command (vty, vty->buf);
1372       if (vty->type == VTY_TERM)
1373         vty_hist_add (vty);
1374       break;
1375     }
1376
1377   /* Clear command line buffer. */
1378   vty->cp = vty->length = 0;
1379   vty_clear_buf (vty);
1380
1381   if (vty->status != VTY_CLOSE )
1382     vty_prompt (vty);
1383
1384   return ret;
1385 }
1386
1387 #define CONTROL(X)  ((X) - '@')
1388 #define VTY_NORMAL     0
1389 #define VTY_PRE_ESCAPE 1  /* Esc seen */
1390 #define VTY_ESCAPE     2  /* ANSI terminal escape (Esc-[) seen */
1391 #define VTY_LITERAL    3  /* Next char taken as literal */
1392
1393 /* Escape character command map. */
1394 static void
1395 vty_escape_map (unsigned char c, struct vty *vty)
1396 {
1397   switch (c)
1398     {
1399     case ('A'):
1400       vty_previous_line (vty);
1401       break;
1402     case ('B'):
1403       vty_next_line (vty);
1404       break;
1405     case ('C'):
1406       vty_forward_char (vty);
1407       break;
1408     case ('D'):
1409       vty_backward_char (vty);
1410       break;
1411     default:
1412       break;
1413     }
1414
1415   /* Go back to normal mode. */
1416   vty->escape = VTY_NORMAL;
1417 }
1418
1419 /* Quit print out to the buffer. */
1420 static void
1421 vty_buffer_reset (struct vty *vty)
1422 {
1423   buffer_reset (vty->obuf);
1424   vty_prompt (vty);
1425   vty_redraw_line (vty);
1426 }
1427
1428 /* Read data via vty socket. */
1429 static int
1430 vty_read (struct thread *thread)
1431 {
1432   int i;
1433   int nbytes;
1434   unsigned char buf[VTY_READ_BUFSIZ];
1435
1436   int vty_sock = THREAD_FD (thread);
1437   struct vty *vty = THREAD_ARG (thread);
1438   vty->t_read = NULL;
1439
1440   /* Read raw data from socket */
1441   if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1442     {
1443       if (nbytes < 0)
1444         {
1445           if (ERRNO_IO_RETRY(errno))
1446             {
1447               vty_event (VTY_READ, vty_sock, vty);
1448               return 0;
1449             }
1450           vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
1451           zlog_warn("%s: read error on vty client fd %d, closing: %s",
1452                     __func__, vty->fd, safe_strerror(errno));
1453           buffer_reset(vty->obuf);
1454         }
1455       vty->status = VTY_CLOSE;
1456     }
1457
1458   for (i = 0; i < nbytes; i++) 
1459     {
1460       if (buf[i] == IAC)
1461         {
1462           if (!vty->iac)
1463             {
1464               vty->iac = 1;
1465               continue;
1466             }
1467           else
1468             {
1469               vty->iac = 0;
1470             }
1471         }
1472       
1473       if (vty->iac_sb_in_progress && !vty->iac)
1474         {
1475             if (vty->sb_len < sizeof(vty->sb_buf))
1476               vty->sb_buf[vty->sb_len] = buf[i];
1477             vty->sb_len++;
1478             continue;
1479         }
1480
1481       if (vty->iac)
1482         {
1483           /* In case of telnet command */
1484           int ret = 0;
1485           ret = vty_telnet_option (vty, buf + i, nbytes - i);
1486           vty->iac = 0;
1487           i += ret;
1488           continue;
1489         }
1490                 
1491
1492       if (vty->status == VTY_MORE)
1493         {
1494           switch (buf[i])
1495             {
1496             case CONTROL('C'):
1497             case 'q':
1498             case 'Q':
1499               vty_buffer_reset (vty);
1500               break;
1501 #if 0 /* More line does not work for "show ip bgp".  */
1502             case '\n':
1503             case '\r':
1504               vty->status = VTY_MORELINE;
1505               break;
1506 #endif
1507             default:
1508               break;
1509             }
1510           continue;
1511         }
1512
1513       /* Escape character. */
1514       if (vty->escape == VTY_ESCAPE)
1515         {
1516           vty_escape_map (buf[i], vty);
1517           continue;
1518         }
1519       
1520       if (vty->escape == VTY_LITERAL)
1521         {
1522           vty_self_insert (vty, buf[i]);
1523           vty->escape = VTY_NORMAL;
1524           continue;
1525         }
1526       
1527       /* Pre-escape status. */
1528       if (vty->escape == VTY_PRE_ESCAPE)
1529         {
1530           switch (buf[i])
1531             {
1532             case '[':
1533               vty->escape = VTY_ESCAPE;
1534               break;
1535             case 'b':
1536               vty_backward_word (vty);
1537               vty->escape = VTY_NORMAL;
1538               break;
1539             case 'f':
1540               vty_forward_word (vty);
1541               vty->escape = VTY_NORMAL;
1542               break;
1543             case 'd':
1544               vty_forward_kill_word (vty);
1545               vty->escape = VTY_NORMAL;
1546               break;
1547             case CONTROL('H'):
1548             case 0x7f:
1549               vty_backward_kill_word (vty);
1550               vty->escape = VTY_NORMAL;
1551               break;
1552             default:
1553               vty->escape = VTY_NORMAL;
1554               break;
1555             }
1556           continue;
1557         }
1558
1559       switch (buf[i])
1560         {
1561         case CONTROL('A'):
1562           vty_beginning_of_line (vty);
1563           break;
1564         case CONTROL('B'):
1565           vty_backward_char (vty);
1566           break;
1567         case CONTROL('C'):
1568           vty_stop_input (vty);
1569           break;
1570         case CONTROL('D'):
1571           vty_delete_char (vty);
1572           break;
1573         case CONTROL('E'):
1574           vty_end_of_line (vty);
1575           break;
1576         case CONTROL('F'):
1577           vty_forward_char (vty);
1578           break;
1579         case CONTROL('H'):
1580         case 0x7f:
1581           vty_delete_backward_char (vty);
1582           break;
1583         case CONTROL('K'):
1584           vty_kill_line (vty);
1585           break;
1586         case CONTROL('N'):
1587           vty_next_line (vty);
1588           break;
1589         case CONTROL('P'):
1590           vty_previous_line (vty);
1591           break;
1592         case CONTROL('T'):
1593           vty_transpose_chars (vty);
1594           break;
1595         case CONTROL('U'):
1596           vty_kill_line_from_beginning (vty);
1597           break;
1598         case CONTROL('V'):
1599           vty->escape = VTY_LITERAL;
1600           break;
1601         case CONTROL('W'):
1602           vty_backward_kill_word (vty);
1603           break;
1604         case CONTROL('Z'):
1605           vty_end_config (vty);
1606           break;
1607         case '\n':
1608         case '\r':
1609           vty_out (vty, "%s", VTY_NEWLINE);
1610           vty_execute (vty);
1611           break;
1612         case '\t':
1613           vty_complete_command (vty);
1614           break;
1615         case '?':
1616           if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1617             vty_self_insert (vty, buf[i]);
1618           else
1619             vty_describe_command (vty);
1620           break;
1621         case '\033':
1622           if (i + 1 < nbytes && buf[i + 1] == '[')
1623             {
1624               vty->escape = VTY_ESCAPE;
1625               i++;
1626             }
1627           else
1628             vty->escape = VTY_PRE_ESCAPE;
1629           break;
1630         default:
1631           if (buf[i] > 31 && buf[i] < 127)
1632             vty_self_insert (vty, buf[i]);
1633           break;
1634         }
1635     }
1636
1637   /* Check status. */
1638   if (vty->status == VTY_CLOSE)
1639     vty_close (vty);
1640   else
1641     {
1642       vty_event (VTY_WRITE, vty->wfd, vty);
1643       vty_event (VTY_READ, vty_sock, vty);
1644     }
1645   return 0;
1646 }
1647
1648 /* Flush buffer to the vty. */
1649 static int
1650 vty_flush (struct thread *thread)
1651 {
1652   int erase;
1653   buffer_status_t flushrc;
1654   int vty_sock = THREAD_FD (thread);
1655   struct vty *vty = THREAD_ARG (thread);
1656
1657   vty->t_write = NULL;
1658
1659   /* Tempolary disable read thread. */
1660   if ((vty->lines == 0) && vty->t_read)
1661     {
1662       thread_cancel (vty->t_read);
1663       vty->t_read = NULL;
1664     }
1665
1666   /* Function execution continue. */
1667   erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
1668
1669   /* N.B. if width is 0, that means we don't know the window size. */
1670   if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0))
1671     flushrc = buffer_flush_available(vty->obuf, vty_sock);
1672   else if (vty->status == VTY_MORELINE)
1673     flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
1674                                   1, erase, 0);
1675   else
1676     flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
1677                                   vty->lines >= 0 ? vty->lines :
1678                                                     vty->height,
1679                                   erase, 0);
1680   switch (flushrc)
1681     {
1682     case BUFFER_ERROR:
1683       vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
1684       zlog_warn("buffer_flush failed on vty client fd %d, closing",
1685                 vty->fd);
1686       buffer_reset(vty->obuf);
1687       vty_close(vty);
1688       return 0;
1689     case BUFFER_EMPTY:
1690       if (vty->status == VTY_CLOSE)
1691         vty_close (vty);
1692       else
1693         {
1694           vty->status = VTY_NORMAL;
1695           if (vty->lines == 0)
1696             vty_event (VTY_READ, vty_sock, vty);
1697         }
1698       break;
1699     case BUFFER_PENDING:
1700       /* There is more data waiting to be written. */
1701       vty->status = VTY_MORE;
1702       if (vty->lines == 0)
1703         vty_event (VTY_WRITE, vty_sock, vty);
1704       break;
1705     }
1706
1707   return 0;
1708 }
1709
1710 /* allocate and initialise vty */
1711 static struct vty *
1712 vty_new_init (int vty_sock)
1713 {
1714   struct vty *vty;
1715
1716   vty = vty_new ();
1717   vty->fd = vty_sock;
1718   vty->wfd = vty_sock;
1719   vty->type = VTY_TERM;
1720   vty->node = AUTH_NODE;
1721   vty->fail = 0;
1722   vty->cp = 0;
1723   vty_clear_buf (vty);
1724   vty->length = 0;
1725   memset (vty->hist, 0, sizeof (vty->hist));
1726   vty->hp = 0;
1727   vty->hindex = 0;
1728   vector_set_index (vtyvec, vty_sock, vty);
1729   vty->status = VTY_NORMAL;
1730   vty->lines = -1;
1731   vty->iac = 0;
1732   vty->iac_sb_in_progress = 0;
1733   vty->sb_len = 0;
1734
1735   return vty;
1736 }
1737
1738 /* Create new vty structure. */
1739 static struct vty *
1740 vty_create (int vty_sock, union sockunion *su)
1741 {
1742   char buf[SU_ADDRSTRLEN];
1743   struct vty *vty;
1744
1745   sockunion2str(su, buf, SU_ADDRSTRLEN);
1746
1747   /* Allocate new vty structure and set up default values. */
1748   vty = vty_new_init (vty_sock);
1749
1750   /* configurable parameters not part of basic init */
1751   vty->v_timeout = vty_timeout_val;
1752   strcpy (vty->address, buf);
1753   if (no_password_check)
1754     {
1755       if (restricted_mode)
1756         vty->node = RESTRICTED_NODE;
1757       else if (host.advanced)
1758         vty->node = ENABLE_NODE;
1759       else
1760         vty->node = VIEW_NODE;
1761     }
1762   if (host.lines >= 0)
1763     vty->lines = host.lines;
1764
1765   if (! no_password_check)
1766     {
1767       /* Vty is not available if password isn't set. */
1768       if (host.password == NULL && host.password_encrypt == NULL)
1769         {
1770           vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1771           vty->status = VTY_CLOSE;
1772           vty_close (vty);
1773           return NULL;
1774         }
1775     }
1776
1777   /* Say hello to the world. */
1778   vty_hello (vty);
1779   if (! no_password_check)
1780     vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1781
1782   /* Setting up terminal. */
1783   vty_will_echo (vty);
1784   vty_will_suppress_go_ahead (vty);
1785
1786   vty_dont_linemode (vty);
1787   vty_do_window_size (vty);
1788   /* vty_dont_lflow_ahead (vty); */
1789
1790   vty_prompt (vty);
1791
1792   /* Add read/write thread. */
1793   vty_event (VTY_WRITE, vty_sock, vty);
1794   vty_event (VTY_READ, vty_sock, vty);
1795
1796   return vty;
1797 }
1798
1799 /* create vty for stdio */
1800 static struct termios stdio_orig_termios;
1801 static struct vty *stdio_vty = NULL;
1802 static void (*stdio_vty_atclose)(void);
1803
1804 static void
1805 vty_stdio_reset (void)
1806 {
1807   if (stdio_vty)
1808     {
1809       tcsetattr (0, TCSANOW, &stdio_orig_termios);
1810       stdio_vty = NULL;
1811
1812       if (stdio_vty_atclose)
1813         stdio_vty_atclose ();
1814       stdio_vty_atclose = NULL;
1815     }
1816 }
1817
1818 struct vty *
1819 vty_stdio (void (*atclose)())
1820 {
1821   struct vty *vty;
1822   struct termios termios;
1823
1824   /* refuse creating two vtys on stdio */
1825   if (stdio_vty)
1826     return NULL;
1827
1828   vty = stdio_vty = vty_new_init (0);
1829   stdio_vty_atclose = atclose;
1830   vty->wfd = 1;
1831
1832   /* always have stdio vty in a known _unchangeable_ state, don't want config
1833    * to have any effect here to make sure scripting this works as intended */
1834   vty->node = ENABLE_NODE;
1835   vty->v_timeout = 0;
1836   strcpy (vty->address, "console");
1837
1838   if (!tcgetattr (0, &stdio_orig_termios))
1839     {
1840       termios = stdio_orig_termios;
1841       termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
1842                            | INLCR | IGNCR | ICRNL | IXON);
1843       termios.c_oflag &= ~OPOST;
1844       termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1845       termios.c_cflag &= ~(CSIZE | PARENB);
1846       termios.c_cflag |= CS8;
1847       tcsetattr (0, TCSANOW, &termios);
1848     }
1849
1850   vty_prompt (vty);
1851
1852   /* Add read/write thread. */
1853   vty_event (VTY_WRITE, 1, vty);
1854   vty_event (VTY_READ, 0, vty);
1855
1856   return vty;
1857 }
1858
1859 /* Accept connection from the network. */
1860 static int
1861 vty_accept (struct thread *thread)
1862 {
1863   int vty_sock;
1864   union sockunion su;
1865   int ret;
1866   unsigned int on;
1867   int accept_sock;
1868   struct prefix p;
1869   struct access_list *acl = NULL;
1870   char buf[SU_ADDRSTRLEN];
1871
1872   accept_sock = THREAD_FD (thread);
1873
1874   /* We continue hearing vty socket. */
1875   vty_event (VTY_SERV, accept_sock, NULL);
1876
1877   memset (&su, 0, sizeof (union sockunion));
1878
1879   /* We can handle IPv4 or IPv6 socket. */
1880   vty_sock = sockunion_accept (accept_sock, &su);
1881   if (vty_sock < 0)
1882     {
1883       zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
1884       return -1;
1885     }
1886   set_nonblocking(vty_sock);
1887
1888   sockunion2hostprefix (&su, &p);
1889
1890   /* VTY's accesslist apply. */
1891   if (p.family == AF_INET && vty_accesslist_name)
1892     {
1893       if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1894           (access_list_apply (acl, &p) == FILTER_DENY))
1895         {
1896           zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1897                 sockunion2str (&su, buf, SU_ADDRSTRLEN));
1898           close (vty_sock);
1899           
1900           /* continue accepting connections */
1901           vty_event (VTY_SERV, accept_sock, NULL);
1902           
1903           return 0;
1904         }
1905     }
1906
1907 #ifdef HAVE_IPV6
1908   /* VTY's ipv6 accesslist apply. */
1909   if (p.family == AF_INET6 && vty_ipv6_accesslist_name)
1910     {
1911       if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1912           (access_list_apply (acl, &p) == FILTER_DENY))
1913         {
1914           zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1915                 sockunion2str (&su, buf, SU_ADDRSTRLEN));
1916           close (vty_sock);
1917           
1918           /* continue accepting connections */
1919           vty_event (VTY_SERV, accept_sock, NULL);
1920           
1921           return 0;
1922         }
1923     }
1924 #endif /* HAVE_IPV6 */
1925   
1926   on = 1;
1927   ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
1928                     (char *) &on, sizeof (on));
1929   if (ret < 0)
1930     zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
1931           safe_strerror (errno));
1932
1933   zlog (NULL, LOG_INFO, "Vty connection from %s",
1934         sockunion2str (&su, buf, SU_ADDRSTRLEN));
1935
1936   vty_create (vty_sock, &su);
1937
1938   return 0;
1939 }
1940
1941 #ifdef HAVE_IPV6
1942 static void
1943 vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1944 {
1945   int ret;
1946   struct addrinfo req;
1947   struct addrinfo *ainfo;
1948   struct addrinfo *ainfo_save;
1949   int sock;
1950   char port_str[BUFSIZ];
1951
1952   memset (&req, 0, sizeof (struct addrinfo));
1953   req.ai_flags = AI_PASSIVE;
1954   req.ai_family = AF_UNSPEC;
1955   req.ai_socktype = SOCK_STREAM;
1956   sprintf (port_str, "%d", port);
1957   port_str[sizeof (port_str) - 1] = '\0';
1958
1959   ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1960
1961   if (ret != 0)
1962     {
1963       fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1964       exit (1);
1965     }
1966
1967   ainfo_save = ainfo;
1968
1969   do
1970     {
1971       if (ainfo->ai_family != AF_INET
1972 #ifdef HAVE_IPV6
1973           && ainfo->ai_family != AF_INET6
1974 #endif /* HAVE_IPV6 */
1975           )
1976         continue;
1977
1978       sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1979       if (sock < 0)
1980         continue;
1981
1982       sockopt_v6only (ainfo->ai_family, sock);
1983       sockopt_reuseaddr (sock);
1984       sockopt_reuseport (sock);
1985
1986       ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1987       if (ret < 0)
1988         {
1989           close (sock); /* Avoid sd leak. */
1990         continue;
1991         }
1992
1993       ret = listen (sock, 3);
1994       if (ret < 0) 
1995         {
1996           close (sock); /* Avoid sd leak. */
1997         continue;
1998         }
1999
2000       vty_event (VTY_SERV, sock, NULL);
2001     }
2002   while ((ainfo = ainfo->ai_next) != NULL);
2003
2004   freeaddrinfo (ainfo_save);
2005 }
2006 #else /* HAVE_IPV6 */
2007
2008 /* Make vty server socket. */
2009 static void
2010 vty_serv_sock_family (const char* addr, unsigned short port, int family)
2011 {
2012   int ret;
2013   union sockunion su;
2014   int accept_sock;
2015   void* naddr=NULL;
2016
2017   memset (&su, 0, sizeof (union sockunion));
2018   su.sa.sa_family = family;
2019   if(addr)
2020     switch(family)
2021     {
2022       case AF_INET:
2023         naddr=&su.sin.sin_addr;
2024         break;
2025 #ifdef HAVE_IPV6
2026       case AF_INET6:
2027         naddr=&su.sin6.sin6_addr;
2028         break;
2029 #endif  
2030     }
2031
2032   if(naddr)
2033     switch(inet_pton(family,addr,naddr))
2034     {
2035       case -1:
2036         zlog_err("bad address %s",addr);
2037         naddr=NULL;
2038         break;
2039       case 0:
2040         zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
2041         naddr=NULL;
2042     }
2043
2044   /* Make new socket. */
2045   accept_sock = sockunion_stream_socket (&su);
2046   if (accept_sock < 0)
2047     return;
2048
2049   /* This is server, so reuse address. */
2050   sockopt_reuseaddr (accept_sock);
2051   sockopt_reuseport (accept_sock);
2052
2053   /* Bind socket to universal address and given port. */
2054   ret = sockunion_bind (accept_sock, &su, port, naddr);
2055   if (ret < 0)
2056     {
2057       zlog_warn("can't bind socket");
2058       close (accept_sock);      /* Avoid sd leak. */
2059       return;
2060     }
2061
2062   /* Listen socket under queue 3. */
2063   ret = listen (accept_sock, 3);
2064   if (ret < 0) 
2065     {
2066       zlog (NULL, LOG_WARNING, "can't listen socket");
2067       close (accept_sock);      /* Avoid sd leak. */
2068       return;
2069     }
2070
2071   /* Add vty server event. */
2072   vty_event (VTY_SERV, accept_sock, NULL);
2073 }
2074 #endif /* HAVE_IPV6 */
2075
2076 #ifdef VTYSH
2077 /* For sockaddr_un. */
2078 #include <sys/un.h>
2079
2080 /* VTY shell UNIX domain socket. */
2081 static void
2082 vty_serv_un (const char *path)
2083 {
2084   int ret;
2085   int sock, len;
2086   struct sockaddr_un serv;
2087   mode_t old_mask;
2088   struct zprivs_ids_t ids;
2089   
2090   /* First of all, unlink existing socket */
2091   unlink (path);
2092
2093   /* Set umask */
2094   old_mask = umask (0007);
2095
2096   /* Make UNIX domain socket. */
2097   sock = socket (AF_UNIX, SOCK_STREAM, 0);
2098   if (sock < 0)
2099     {
2100       zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
2101       return;
2102     }
2103
2104   /* Make server socket. */
2105   memset (&serv, 0, sizeof (struct sockaddr_un));
2106   serv.sun_family = AF_UNIX;
2107   strncpy (serv.sun_path, path, strlen (path));
2108 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
2109   len = serv.sun_len = SUN_LEN(&serv);
2110 #else
2111   len = sizeof (serv.sun_family) + strlen (serv.sun_path);
2112 #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
2113
2114   ret = bind (sock, (struct sockaddr *) &serv, len);
2115   if (ret < 0)
2116     {
2117       zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
2118       close (sock);     /* Avoid sd leak. */
2119       return;
2120     }
2121
2122   ret = listen (sock, 5);
2123   if (ret < 0)
2124     {
2125       zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
2126       close (sock);     /* Avoid sd leak. */
2127       return;
2128     }
2129
2130   umask (old_mask);
2131
2132   zprivs_get_ids(&ids);
2133   
2134   if (ids.gid_vty > 0)
2135     {
2136       /* set group of socket */
2137       if ( chown (path, -1, ids.gid_vty) )
2138         {
2139           zlog_err ("vty_serv_un: could chown socket, %s",
2140                      safe_strerror (errno) );
2141         }
2142     }
2143
2144   vty_event (VTYSH_SERV, sock, NULL);
2145 }
2146
2147 /* #define VTYSH_DEBUG 1 */
2148
2149 static int
2150 vtysh_accept (struct thread *thread)
2151 {
2152   int accept_sock;
2153   int sock;
2154   int client_len;
2155   struct sockaddr_un client;
2156   struct vty *vty;
2157   
2158   accept_sock = THREAD_FD (thread);
2159
2160   vty_event (VTYSH_SERV, accept_sock, NULL);
2161
2162   memset (&client, 0, sizeof (struct sockaddr_un));
2163   client_len = sizeof (struct sockaddr_un);
2164
2165   sock = accept (accept_sock, (struct sockaddr *) &client,
2166                  (socklen_t *) &client_len);
2167
2168   if (sock < 0)
2169     {
2170       zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
2171       return -1;
2172     }
2173
2174   if (set_nonblocking(sock) < 0)
2175     {
2176       zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
2177                  " %s, closing", sock, safe_strerror (errno));
2178       close (sock);
2179       return -1;
2180     }
2181   
2182 #ifdef VTYSH_DEBUG
2183   printf ("VTY shell accept\n");
2184 #endif /* VTYSH_DEBUG */
2185
2186   vty = vty_new ();
2187   vty->fd = sock;
2188   vty->wfd = sock;
2189   vty->type = VTY_SHELL_SERV;
2190   vty->node = VIEW_NODE;
2191
2192   vty_event (VTYSH_READ, sock, vty);
2193
2194   return 0;
2195 }
2196
2197 static int
2198 vtysh_flush(struct vty *vty)
2199 {
2200   switch (buffer_flush_available(vty->obuf, vty->wfd))
2201     {
2202     case BUFFER_PENDING:
2203       vty_event(VTYSH_WRITE, vty->wfd, vty);
2204       break;
2205     case BUFFER_ERROR:
2206       vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
2207       zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2208       buffer_reset(vty->obuf);
2209       vty_close(vty);
2210       return -1;
2211       break;
2212     case BUFFER_EMPTY:
2213       break;
2214     }
2215   return 0;
2216 }
2217
2218 static int
2219 vtysh_read (struct thread *thread)
2220 {
2221   int ret;
2222   int sock;
2223   int nbytes;
2224   struct vty *vty;
2225   unsigned char buf[VTY_READ_BUFSIZ];
2226   unsigned char *p;
2227   u_char header[4] = {0, 0, 0, 0};
2228
2229   sock = THREAD_FD (thread);
2230   vty = THREAD_ARG (thread);
2231   vty->t_read = NULL;
2232
2233   if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
2234     {
2235       if (nbytes < 0)
2236         {
2237           if (ERRNO_IO_RETRY(errno))
2238             {
2239               vty_event (VTYSH_READ, sock, vty);
2240               return 0;
2241             }
2242           vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
2243           zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2244                     __func__, sock, safe_strerror(errno));
2245         }
2246       buffer_reset(vty->obuf);
2247       vty_close (vty);
2248 #ifdef VTYSH_DEBUG
2249       printf ("close vtysh\n");
2250 #endif /* VTYSH_DEBUG */
2251       return 0;
2252     }
2253
2254 #ifdef VTYSH_DEBUG
2255   printf ("line: %.*s\n", nbytes, buf);
2256 #endif /* VTYSH_DEBUG */
2257
2258   if (vty->length + nbytes >= vty->max)
2259     {
2260       /* Clear command line buffer. */
2261       vty->cp = vty->length = 0;
2262       vty_clear_buf (vty);
2263       vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE);
2264       goto out;
2265     }
2266   
2267   for (p = buf; p < buf+nbytes; p++)
2268     {
2269       vty->buf[vty->length++] = *p;
2270       if (*p == '\0')
2271         {
2272           
2273           /* Pass this line to parser. */
2274           ret = vty_execute (vty);
2275           /* Note that vty_execute clears the command buffer and resets
2276              vty->length to 0. */
2277
2278           /* Return result. */
2279 #ifdef VTYSH_DEBUG
2280           printf ("result: %d\n", ret);
2281           printf ("vtysh node: %d\n", vty->node);
2282 #endif /* VTYSH_DEBUG */
2283
2284           header[3] = ret;
2285           buffer_put(vty->obuf, header, 4);
2286
2287           if (!vty->t_write && (vtysh_flush(vty) < 0))
2288             /* Try to flush results; exit if a write error occurs. */
2289             return 0;
2290         }
2291     }
2292
2293 out:
2294   vty_event (VTYSH_READ, sock, vty);
2295
2296   return 0;
2297 }
2298
2299 static int
2300 vtysh_write (struct thread *thread)
2301 {
2302   struct vty *vty = THREAD_ARG (thread);
2303
2304   vty->t_write = NULL;
2305   vtysh_flush(vty);
2306   return 0;
2307 }
2308
2309 #endif /* VTYSH */
2310
2311 /* Determine address family to bind. */
2312 void
2313 vty_serv_sock (const char *addr, unsigned short port, const char *path)
2314 {
2315   /* If port is set to 0, do not listen on TCP/IP at all! */
2316   if (port)
2317     {
2318
2319 #ifdef HAVE_IPV6
2320       vty_serv_sock_addrinfo (addr, port);
2321 #else /* ! HAVE_IPV6 */
2322       vty_serv_sock_family (addr,port, AF_INET);
2323 #endif /* HAVE_IPV6 */
2324     }
2325
2326 #ifdef VTYSH
2327   vty_serv_un (path);
2328 #endif /* VTYSH */
2329 }
2330
2331 /* Close vty interface.  Warning: call this only from functions that
2332    will be careful not to access the vty afterwards (since it has
2333    now been freed).  This is safest from top-level functions (called
2334    directly by the thread dispatcher). */
2335 void
2336 vty_close (struct vty *vty)
2337 {
2338   int i;
2339
2340   /* Cancel threads.*/
2341   if (vty->t_read)
2342     thread_cancel (vty->t_read);
2343   if (vty->t_write)
2344     thread_cancel (vty->t_write);
2345   if (vty->t_timeout)
2346     thread_cancel (vty->t_timeout);
2347
2348   /* Flush buffer. */
2349   buffer_flush_all (vty->obuf, vty->wfd);
2350
2351   /* Free input buffer. */
2352   buffer_free (vty->obuf);
2353
2354   /* Free command history. */
2355   for (i = 0; i < VTY_MAXHIST; i++)
2356     if (vty->hist[i])
2357       XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2358
2359   /* Unset vector. */
2360   vector_unset (vtyvec, vty->fd);
2361
2362   /* Close socket. */
2363   if (vty->fd > 0)
2364     close (vty->fd);
2365   else
2366     vty_stdio_reset ();
2367
2368   if (vty->buf)
2369     XFREE (MTYPE_VTY, vty->buf);
2370
2371   /* Check configure. */
2372   vty_config_unlock (vty);
2373
2374   /* OK free vty. */
2375   XFREE (MTYPE_VTY, vty);
2376 }
2377
2378 /* When time out occur output message then close connection. */
2379 static int
2380 vty_timeout (struct thread *thread)
2381 {
2382   struct vty *vty;
2383
2384   vty = THREAD_ARG (thread);
2385   vty->t_timeout = NULL;
2386   vty->v_timeout = 0;
2387
2388   /* Clear buffer*/
2389   buffer_reset (vty->obuf);
2390   vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2391
2392   /* Close connection. */
2393   vty->status = VTY_CLOSE;
2394   vty_close (vty);
2395
2396   return 0;
2397 }
2398
2399 /* Read up configuration file from file_name. */
2400 static void
2401 vty_read_file (FILE *confp)
2402 {
2403   int ret;
2404   struct vty *vty;
2405   unsigned int line_num = 0;
2406
2407   vty = vty_new ();
2408   vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */
2409   if (vty->wfd < 0)
2410   {
2411     /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
2412     vty->wfd = STDOUT_FILENO;
2413   }
2414   vty->fd = STDIN_FILENO;
2415   vty->type = VTY_FILE;
2416   vty->node = CONFIG_NODE;
2417   
2418   /* Execute configuration file */
2419   ret = config_from_file (vty, confp, &line_num);
2420
2421   /* Flush any previous errors before printing messages below */
2422   buffer_flush_all (vty->obuf, vty->fd);
2423
2424   if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) 
2425     {
2426       switch (ret)
2427        {
2428          case CMD_ERR_AMBIGUOUS:
2429            fprintf (stderr, "*** Error reading config: Ambiguous command.\n");
2430            break;
2431          case CMD_ERR_NO_MATCH:
2432            fprintf (stderr, "*** Error reading config: There is no such command.\n");
2433            break;
2434        }
2435       fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
2436                        line_num, vty->buf);
2437       vty_close (vty);
2438       exit (1);
2439     }
2440
2441   vty_close (vty);
2442 }
2443
2444 static FILE *
2445 vty_use_backup_config (char *fullpath)
2446 {
2447   char *fullpath_sav, *fullpath_tmp;
2448   FILE *ret = NULL;
2449   struct stat buf;
2450   int tmp, sav;
2451   int c;
2452   char buffer[512];
2453   
2454   fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2455   strcpy (fullpath_sav, fullpath);
2456   strcat (fullpath_sav, CONF_BACKUP_EXT);
2457   if (stat (fullpath_sav, &buf) == -1)
2458     {
2459       free (fullpath_sav);
2460       return NULL;
2461     }
2462
2463   fullpath_tmp = malloc (strlen (fullpath) + 8);
2464   sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2465   
2466   /* Open file to configuration write. */
2467   tmp = mkstemp (fullpath_tmp);
2468   if (tmp < 0)
2469     {
2470       free (fullpath_sav);
2471       free (fullpath_tmp);
2472       return NULL;
2473     }
2474
2475   sav = open (fullpath_sav, O_RDONLY);
2476   if (sav < 0)
2477     {
2478       unlink (fullpath_tmp);
2479       free (fullpath_sav);
2480       free (fullpath_tmp);
2481       return NULL;
2482     }
2483   
2484   while((c = read (sav, buffer, 512)) > 0)
2485     write (tmp, buffer, c);
2486   
2487   close (sav);
2488   close (tmp);
2489   
2490   if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2491     {
2492       unlink (fullpath_tmp);
2493       free (fullpath_sav);
2494       free (fullpath_tmp);
2495       return NULL;
2496     }
2497   
2498   if (link (fullpath_tmp, fullpath) == 0)
2499     ret = fopen (fullpath, "r");
2500
2501   unlink (fullpath_tmp);
2502   
2503   free (fullpath_sav);
2504   free (fullpath_tmp);
2505   return ret;
2506 }
2507
2508 /* Read up configuration file from file_name. */
2509 void
2510 vty_read_config (char *config_file,
2511                  char *config_default_dir)
2512 {
2513   char cwd[MAXPATHLEN];
2514   FILE *confp = NULL;
2515   char *fullpath;
2516   char *tmp = NULL;
2517
2518   /* If -f flag specified. */
2519   if (config_file != NULL)
2520     {
2521       if (! IS_DIRECTORY_SEP (config_file[0]))
2522         {
2523           getcwd (cwd, MAXPATHLEN);
2524           tmp = XMALLOC (MTYPE_TMP, 
2525                               strlen (cwd) + strlen (config_file) + 2);
2526           sprintf (tmp, "%s/%s", cwd, config_file);
2527           fullpath = tmp;
2528         }
2529       else
2530         fullpath = config_file;
2531
2532       confp = fopen (fullpath, "r");
2533
2534       if (confp == NULL)
2535         {
2536           fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2537                    __func__, fullpath, safe_strerror (errno));
2538           
2539           confp = vty_use_backup_config (fullpath);
2540           if (confp)
2541             fprintf (stderr, "WARNING: using backup configuration file!\n");
2542           else
2543             {
2544               fprintf (stderr, "can't open configuration file [%s]\n", 
2545                        config_file);
2546               exit(1);
2547             }
2548         }
2549     }
2550   else
2551     {
2552 #ifdef VTYSH
2553       int ret;
2554       struct stat conf_stat;
2555
2556       /* !!!!PLEASE LEAVE!!!!
2557        * This is NEEDED for use with vtysh -b, or else you can get
2558        * a real configuration food fight with a lot garbage in the
2559        * merged configuration file it creates coming from the per
2560        * daemon configuration files.  This also allows the daemons
2561        * to start if there default configuration file is not
2562        * present or ignore them, as needed when using vtysh -b to
2563        * configure the daemons at boot - MAG
2564        */
2565
2566       /* Stat for vtysh Zebra.conf, if found startup and wait for
2567        * boot configuration
2568        */
2569
2570       if ( strstr(config_default_dir, "vtysh") == NULL)
2571         {
2572           ret = stat (integrate_default, &conf_stat);
2573           if (ret >= 0)
2574             return;
2575         }
2576 #endif /* VTYSH */
2577
2578       confp = fopen (config_default_dir, "r");
2579       if (confp == NULL)
2580         {
2581           fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2582                    __func__, config_default_dir, safe_strerror (errno));
2583           
2584           confp = vty_use_backup_config (config_default_dir);
2585           if (confp)
2586             {
2587               fprintf (stderr, "WARNING: using backup configuration file!\n");
2588               fullpath = config_default_dir;
2589             }
2590           else
2591             {
2592               fprintf (stderr, "can't open configuration file [%s]\n",
2593                                  config_default_dir);
2594                   exit (1);
2595             }
2596         }      
2597       else
2598         fullpath = config_default_dir;
2599     }
2600
2601   vty_read_file (confp);
2602
2603   fclose (confp);
2604
2605   host_config_set (fullpath);
2606   
2607   if (tmp)
2608     XFREE (MTYPE_TMP, fullpath);
2609 }
2610
2611 /* Small utility function which output log to the VTY. */
2612 void
2613 vty_log (const char *level, const char *proto_str,
2614          const char *format, struct timestamp_control *ctl, va_list va)
2615 {
2616   unsigned int i;
2617   struct vty *vty;
2618   
2619   if (!vtyvec)
2620     return;
2621
2622   for (i = 0; i < vector_active (vtyvec); i++)
2623     if ((vty = vector_slot (vtyvec, i)) != NULL)
2624       if (vty->monitor)
2625         {
2626           va_list ac;
2627           va_copy(ac, va);
2628           vty_log_out (vty, level, proto_str, format, ctl, ac);
2629           va_end(ac);
2630         }
2631 }
2632
2633 /* Async-signal-safe version of vty_log for fixed strings. */
2634 void
2635 vty_log_fixed (char *buf, size_t len)
2636 {
2637   unsigned int i;
2638   struct iovec iov[2];
2639
2640   /* vty may not have been initialised */
2641   if (!vtyvec)
2642     return;
2643   
2644   iov[0].iov_base = buf;
2645   iov[0].iov_len = len;
2646   iov[1].iov_base = (void *)"\r\n";
2647   iov[1].iov_len = 2;
2648
2649   for (i = 0; i < vector_active (vtyvec); i++)
2650     {
2651       struct vty *vty;
2652       if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2653         /* N.B. We don't care about the return code, since process is
2654            most likely just about to die anyway. */
2655         writev(vty->wfd, iov, 2);
2656     }
2657 }
2658
2659 int
2660 vty_config_lock (struct vty *vty)
2661 {
2662   if (vty_config == 0)
2663     {
2664       vty->config = 1;
2665       vty_config = 1;
2666     }
2667   return vty->config;
2668 }
2669
2670 int
2671 vty_config_unlock (struct vty *vty)
2672 {
2673   if (vty_config == 1 && vty->config == 1)
2674     {
2675       vty->config = 0;
2676       vty_config = 0;
2677     }
2678   return vty->config;
2679 }
2680
2681 /* Master of the threads. */
2682 static struct thread_master *vty_master;
2683
2684 static void
2685 vty_event (enum event event, int sock, struct vty *vty)
2686 {
2687   struct thread *vty_serv_thread;
2688
2689   switch (event)
2690     {
2691     case VTY_SERV:
2692       vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
2693       vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2694       break;
2695 #ifdef VTYSH
2696     case VTYSH_SERV:
2697       vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
2698       vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2699       break;
2700     case VTYSH_READ:
2701       vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
2702       break;
2703     case VTYSH_WRITE:
2704       vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
2705       break;
2706 #endif /* VTYSH */
2707     case VTY_READ:
2708       vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
2709
2710       /* Time out treatment. */
2711       if (vty->v_timeout)
2712         {
2713           if (vty->t_timeout)
2714             thread_cancel (vty->t_timeout);
2715           vty->t_timeout = 
2716             thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
2717         }
2718       break;
2719     case VTY_WRITE:
2720       if (! vty->t_write)
2721         vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
2722       break;
2723     case VTY_TIMEOUT_RESET:
2724       if (vty->t_timeout)
2725         {
2726           thread_cancel (vty->t_timeout);
2727           vty->t_timeout = NULL;
2728         }
2729       if (vty->v_timeout)
2730         {
2731           vty->t_timeout = 
2732             thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
2733         }
2734       break;
2735     }
2736 }
2737
2738 DEFUN (who,
2739        who_cmd,
2740        "who",
2741        "Display who is on vty\n")
2742 {
2743   unsigned int i;
2744   struct vty *v;
2745
2746   for (i = 0; i < vector_active (vtyvec); i++)
2747     if ((v = vector_slot (vtyvec, i)) != NULL)
2748       vty_out (vty, "%svty[%d] connected from %s.%s",
2749                v->config ? "*" : " ",
2750                i, v->address, VTY_NEWLINE);
2751   return CMD_SUCCESS;
2752 }
2753
2754 /* Move to vty configuration mode. */
2755 DEFUN (line_vty,
2756        line_vty_cmd,
2757        "line vty",
2758        "Configure a terminal line\n"
2759        "Virtual terminal\n")
2760 {
2761   vty->node = VTY_NODE;
2762   return CMD_SUCCESS;
2763 }
2764
2765 /* Set time out value. */
2766 static int
2767 exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
2768 {
2769   unsigned long timeout = 0;
2770
2771   /* min_str and sec_str are already checked by parser.  So it must be
2772      all digit string. */
2773   if (min_str)
2774     {
2775       timeout = strtol (min_str, NULL, 10);
2776       timeout *= 60;
2777     }
2778   if (sec_str)
2779     timeout += strtol (sec_str, NULL, 10);
2780
2781   vty_timeout_val = timeout;
2782   vty->v_timeout = timeout;
2783   vty_event (VTY_TIMEOUT_RESET, 0, vty);
2784
2785
2786   return CMD_SUCCESS;
2787 }
2788
2789 DEFUN (exec_timeout_min,
2790        exec_timeout_min_cmd,
2791        "exec-timeout <0-35791>",
2792        "Set timeout value\n"
2793        "Timeout value in minutes\n")
2794 {
2795   return exec_timeout (vty, argv[0], NULL);
2796 }
2797
2798 DEFUN (exec_timeout_sec,
2799        exec_timeout_sec_cmd,
2800        "exec-timeout <0-35791> <0-2147483>",
2801        "Set the EXEC timeout\n"
2802        "Timeout in minutes\n"
2803        "Timeout in seconds\n")
2804 {
2805   return exec_timeout (vty, argv[0], argv[1]);
2806 }
2807
2808 DEFUN (no_exec_timeout,
2809        no_exec_timeout_cmd,
2810        "no exec-timeout",
2811        NO_STR
2812        "Set the EXEC timeout\n")
2813 {
2814   return exec_timeout (vty, NULL, NULL);
2815 }
2816
2817 /* Set vty access class. */
2818 DEFUN (vty_access_class,
2819        vty_access_class_cmd,
2820        "access-class WORD",
2821        "Filter connections based on an IP access list\n"
2822        "IP access list\n")
2823 {
2824   if (vty_accesslist_name)
2825     XFREE(MTYPE_VTY, vty_accesslist_name);
2826
2827   vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2828
2829   return CMD_SUCCESS;
2830 }
2831
2832 /* Clear vty access class. */
2833 DEFUN (no_vty_access_class,
2834        no_vty_access_class_cmd,
2835        "no access-class [WORD]",
2836        NO_STR
2837        "Filter connections based on an IP access list\n"
2838        "IP access list\n")
2839 {
2840   if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2841     {
2842       vty_out (vty, "Access-class is not currently applied to vty%s",
2843                VTY_NEWLINE);
2844       return CMD_WARNING;
2845     }
2846
2847   XFREE(MTYPE_VTY, vty_accesslist_name);
2848
2849   vty_accesslist_name = NULL;
2850
2851   return CMD_SUCCESS;
2852 }
2853
2854 #ifdef HAVE_IPV6
2855 /* Set vty access class. */
2856 DEFUN (vty_ipv6_access_class,
2857        vty_ipv6_access_class_cmd,
2858        "ipv6 access-class WORD",
2859        IPV6_STR
2860        "Filter connections based on an IP access list\n"
2861        "IPv6 access list\n")
2862 {
2863   if (vty_ipv6_accesslist_name)
2864     XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2865
2866   vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2867
2868   return CMD_SUCCESS;
2869 }
2870
2871 /* Clear vty access class. */
2872 DEFUN (no_vty_ipv6_access_class,
2873        no_vty_ipv6_access_class_cmd,
2874        "no ipv6 access-class [WORD]",
2875        NO_STR
2876        IPV6_STR
2877        "Filter connections based on an IP access list\n"
2878        "IPv6 access list\n")
2879 {
2880   if (! vty_ipv6_accesslist_name ||
2881       (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2882     {
2883       vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2884                VTY_NEWLINE);
2885       return CMD_WARNING;
2886     }
2887
2888   XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2889
2890   vty_ipv6_accesslist_name = NULL;
2891
2892   return CMD_SUCCESS;
2893 }
2894 #endif /* HAVE_IPV6 */
2895
2896 /* vty login. */
2897 DEFUN (vty_login,
2898        vty_login_cmd,
2899        "login",
2900        "Enable password checking\n")
2901 {
2902   no_password_check = 0;
2903   return CMD_SUCCESS;
2904 }
2905
2906 DEFUN (no_vty_login,
2907        no_vty_login_cmd,
2908        "no login",
2909        NO_STR
2910        "Enable password checking\n")
2911 {
2912   no_password_check = 1;
2913   return CMD_SUCCESS;
2914 }
2915
2916 /* initial mode. */
2917 DEFUN (vty_restricted_mode,
2918        vty_restricted_mode_cmd,
2919        "anonymous restricted",
2920        "Restrict view commands available in anonymous, unauthenticated vty\n")
2921 {
2922   restricted_mode = 1;
2923   return CMD_SUCCESS;
2924 }
2925
2926 DEFUN (vty_no_restricted_mode,
2927        vty_no_restricted_mode_cmd,
2928        "no anonymous restricted",
2929        NO_STR
2930        "Enable password checking\n")
2931 {
2932   restricted_mode = 0;
2933   return CMD_SUCCESS;
2934 }
2935
2936 DEFUN (service_advanced_vty,
2937        service_advanced_vty_cmd,
2938        "service advanced-vty",
2939        "Set up miscellaneous service\n"
2940        "Enable advanced mode vty interface\n")
2941 {
2942   host.advanced = 1;
2943   return CMD_SUCCESS;
2944 }
2945
2946 DEFUN (no_service_advanced_vty,
2947        no_service_advanced_vty_cmd,
2948        "no service advanced-vty",
2949        NO_STR
2950        "Set up miscellaneous service\n"
2951        "Enable advanced mode vty interface\n")
2952 {
2953   host.advanced = 0;
2954   return CMD_SUCCESS;
2955 }
2956
2957 DEFUN (terminal_monitor,
2958        terminal_monitor_cmd,
2959        "terminal monitor",
2960        "Set terminal line parameters\n"
2961        "Copy debug output to the current terminal line\n")
2962 {
2963   vty->monitor = 1;
2964   return CMD_SUCCESS;
2965 }
2966
2967 DEFUN (terminal_no_monitor,
2968        terminal_no_monitor_cmd,
2969        "terminal no monitor",
2970        "Set terminal line parameters\n"
2971        NO_STR
2972        "Copy debug output to the current terminal line\n")
2973 {
2974   vty->monitor = 0;
2975   return CMD_SUCCESS;
2976 }
2977
2978 ALIAS (terminal_no_monitor,
2979        no_terminal_monitor_cmd,
2980        "no terminal monitor",
2981        NO_STR
2982        "Set terminal line parameters\n"
2983        "Copy debug output to the current terminal line\n")
2984
2985 DEFUN (show_history,
2986        show_history_cmd,
2987        "show history",
2988        SHOW_STR
2989        "Display the session command history\n")
2990 {
2991   int index;
2992
2993   for (index = vty->hindex + 1; index != vty->hindex;)
2994     {
2995       if (index == VTY_MAXHIST)
2996         {
2997           index = 0;
2998           continue;
2999         }
3000
3001       if (vty->hist[index] != NULL)
3002         vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
3003
3004       index++;
3005     }
3006
3007   return CMD_SUCCESS;
3008 }
3009
3010 /* vty login. */
3011 DEFUN (log_commands,
3012        log_commands_cmd,
3013        "log commands",
3014        "Logging control\n"
3015        "Log all commands (can't be unset without restart)\n")
3016 {
3017   do_log_commands = 1;
3018   return CMD_SUCCESS;
3019 }
3020
3021 /* Display current configuration. */
3022 static int
3023 vty_config_write (struct vty *vty)
3024 {
3025   vty_out (vty, "line vty%s", VTY_NEWLINE);
3026
3027   if (vty_accesslist_name)
3028     vty_out (vty, " access-class %s%s",
3029              vty_accesslist_name, VTY_NEWLINE);
3030
3031   if (vty_ipv6_accesslist_name)
3032     vty_out (vty, " ipv6 access-class %s%s",
3033              vty_ipv6_accesslist_name, VTY_NEWLINE);
3034
3035   /* exec-timeout */
3036   if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
3037     vty_out (vty, " exec-timeout %ld %ld%s", 
3038              vty_timeout_val / 60,
3039              vty_timeout_val % 60, VTY_NEWLINE);
3040
3041   /* login */
3042   if (no_password_check)
3043     vty_out (vty, " no login%s", VTY_NEWLINE);
3044     
3045   if (restricted_mode != restricted_mode_default)
3046     {
3047       if (restricted_mode_default)
3048         vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
3049       else
3050         vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
3051     }
3052   
3053   if (do_log_commands)
3054     vty_out (vty, "log commands%s", VTY_NEWLINE);
3055      
3056   vty_out (vty, "!%s", VTY_NEWLINE);
3057
3058   return CMD_SUCCESS;
3059 }
3060
3061 struct cmd_node vty_node =
3062 {
3063   VTY_NODE,
3064   "%s(config-line)# ",
3065   1,
3066 };
3067
3068 /* Reset all VTY status. */
3069 void
3070 vty_reset ()
3071 {
3072   unsigned int i;
3073   struct vty *vty;
3074   struct thread *vty_serv_thread;
3075
3076   for (i = 0; i < vector_active (vtyvec); i++)
3077     if ((vty = vector_slot (vtyvec, i)) != NULL)
3078       {
3079         buffer_reset (vty->obuf);
3080         vty->status = VTY_CLOSE;
3081         vty_close (vty);
3082       }
3083
3084   for (i = 0; i < vector_active (Vvty_serv_thread); i++)
3085     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
3086       {
3087         thread_cancel (vty_serv_thread);
3088         vector_slot (Vvty_serv_thread, i) = NULL;
3089         close (i);
3090       }
3091
3092   vty_timeout_val = VTY_TIMEOUT_DEFAULT;
3093
3094   if (vty_accesslist_name)
3095     {
3096       XFREE(MTYPE_VTY, vty_accesslist_name);
3097       vty_accesslist_name = NULL;
3098     }
3099
3100   if (vty_ipv6_accesslist_name)
3101     {
3102       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
3103       vty_ipv6_accesslist_name = NULL;
3104     }
3105 }
3106
3107 static void
3108 vty_save_cwd (void)
3109 {
3110   char cwd[MAXPATHLEN];
3111   char *c;
3112
3113   c = getcwd (cwd, MAXPATHLEN);
3114
3115   if (!c)
3116     {
3117       chdir (SYSCONFDIR);
3118       getcwd (cwd, MAXPATHLEN);
3119     }
3120
3121   vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
3122   strcpy (vty_cwd, cwd);
3123 }
3124
3125 char *
3126 vty_get_cwd ()
3127 {
3128   return vty_cwd;
3129 }
3130
3131 int
3132 vty_shell (struct vty *vty)
3133 {
3134   return vty->type == VTY_SHELL ? 1 : 0;
3135 }
3136
3137 int
3138 vty_shell_serv (struct vty *vty)
3139 {
3140   return vty->type == VTY_SHELL_SERV ? 1 : 0;
3141 }
3142
3143 void
3144 vty_init_vtysh ()
3145 {
3146   vtyvec = vector_init (VECTOR_MIN_SIZE);
3147 }
3148
3149 /* Install vty's own commands like `who' command. */
3150 void
3151 vty_init (struct thread_master *master_thread)
3152 {
3153   /* For further configuration read, preserve current directory. */
3154   vty_save_cwd ();
3155
3156   vtyvec = vector_init (VECTOR_MIN_SIZE);
3157
3158   vty_master = master_thread;
3159
3160   atexit (vty_stdio_reset);
3161
3162   /* Initilize server thread vector. */
3163   Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
3164
3165   /* Install bgp top node. */
3166   install_node (&vty_node, vty_config_write);
3167
3168   install_element (RESTRICTED_NODE, &who_cmd);
3169   install_element (RESTRICTED_NODE, &show_history_cmd);
3170   install_element (VIEW_NODE, &who_cmd);
3171   install_element (VIEW_NODE, &show_history_cmd);
3172   install_element (CONFIG_NODE, &line_vty_cmd);
3173   install_element (CONFIG_NODE, &service_advanced_vty_cmd);
3174   install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
3175   install_element (CONFIG_NODE, &show_history_cmd);
3176   install_element (CONFIG_NODE, &log_commands_cmd);
3177   install_element (ENABLE_NODE, &terminal_monitor_cmd);
3178   install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
3179   install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
3180
3181   install_default (VTY_NODE);
3182   install_element (VTY_NODE, &exec_timeout_min_cmd);
3183   install_element (VTY_NODE, &exec_timeout_sec_cmd);
3184   install_element (VTY_NODE, &no_exec_timeout_cmd);
3185   install_element (VTY_NODE, &vty_access_class_cmd);
3186   install_element (VTY_NODE, &no_vty_access_class_cmd);
3187   install_element (VTY_NODE, &vty_login_cmd);
3188   install_element (VTY_NODE, &no_vty_login_cmd);
3189   install_element (VTY_NODE, &vty_restricted_mode_cmd);
3190   install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
3191 #ifdef HAVE_IPV6
3192   install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
3193   install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
3194 #endif /* HAVE_IPV6 */
3195 }
3196
3197 void
3198 vty_terminate (void)
3199 {
3200   if (vty_cwd)
3201     XFREE (MTYPE_TMP, vty_cwd);
3202
3203   if (vtyvec && Vvty_serv_thread)
3204     {
3205       vty_reset ();
3206       vector_free (vtyvec);
3207       vector_free (Vvty_serv_thread);
3208     }
3209 }