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