2 * Virtual terminal [aka TeletYpe] interface routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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
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.
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
29 #include "sockunion.h"
50 static void vty_event (enum event
, int, struct vty
*);
52 /* Extern host structure from command.c */
53 extern struct host host
;
55 /* Vector which store each vty structure. */
58 /* Vty timeout value. */
59 static unsigned long vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
61 /* Vty access-class command */
62 static char *vty_accesslist_name
= NULL
;
64 /* Vty access-calss for IPv6. */
65 static char *vty_ipv6_accesslist_name
= NULL
;
67 /* VTY server thread. */
68 vector Vvty_serv_thread
;
70 /* Current directory. */
74 static int vty_config
;
76 /* Login password check. */
77 static int no_password_check
= 0;
79 /* Integrated configuration file path */
80 char integrate_default
[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG
;
83 /* VTY standard output function. */
85 vty_out (struct vty
*vty
, const char *format
, ...)
93 va_start (args
, format
);
96 vprintf (format
, args
);
99 /* Try to write to initial buffer. */
100 len
= vsnprintf (buf
, sizeof buf
, format
, args
);
102 /* Initial buffer is not enough. */
103 if (len
< 0 || len
>= size
)
112 p
= XREALLOC (MTYPE_VTY_OUT_BUF
, p
, size
);
116 len
= vsnprintf (p
, size
, format
, args
);
118 if (len
> -1 && len
< size
)
123 /* When initial buffer is enough to store all output. */
127 /* Pointer p must point out buffer. */
128 if (vty_shell_serv (vty
))
129 write (vty
->fd
, (u_char
*) p
, len
);
131 buffer_write (vty
->obuf
, (u_char
*) p
, len
);
133 /* If p is not different with buf, it is allocated buffer. */
135 XFREE (MTYPE_VTY_OUT_BUF
, p
);
144 vty_log_out (struct vty
*vty
, const char *proto_str
, const char *format
,
150 snprintf (buf
, sizeof buf
, "%s: ", proto_str
);
151 write (vty
->fd
, buf
, strlen (proto_str
) + 2);
153 len
= vsnprintf (buf
, sizeof buf
, format
, va
);
156 write (vty
->fd
, (u_char
*)buf
, len
);
158 snprintf (buf
, sizeof buf
, "\r\n");
159 write (vty
->fd
, buf
, 2);
164 /* Output current time to the vty. */
166 vty_time_print (struct vty
*vty
, int cr
)
175 tm
= localtime (&clock
);
177 ret
= strftime (buf
, TIME_BUF
, "%Y/%m/%d %H:%M:%S", tm
);
180 zlog (NULL
, LOG_INFO
, "strftime error");
184 vty_out (vty
, "%s\n", buf
);
186 vty_out (vty
, "%s ", buf
);
191 /* Say hello to vty interface. */
193 vty_hello (struct vty
*vty
)
196 vty_out (vty
, host
.motd
);
199 /* Put out prompt and wait input from user. */
201 vty_prompt (struct vty
*vty
)
203 struct utsname names
;
206 if (vty
->type
== VTY_TERM
)
208 hostname
= host
.name
;
212 hostname
= names
.nodename
;
214 vty_out (vty
, cmd_prompt (vty
->node
), hostname
);
218 /* Send WILL TELOPT_ECHO to remote server. */
220 vty_will_echo (struct vty
*vty
)
222 char cmd
[] = { IAC
, WILL
, TELOPT_ECHO
, '\0' };
223 vty_out (vty
, "%s", cmd
);
226 /* Make suppress Go-Ahead telnet option. */
228 vty_will_suppress_go_ahead (struct vty
*vty
)
230 char cmd
[] = { IAC
, WILL
, TELOPT_SGA
, '\0' };
231 vty_out (vty
, "%s", cmd
);
234 /* Make don't use linemode over telnet. */
236 vty_dont_linemode (struct vty
*vty
)
238 char cmd
[] = { IAC
, DONT
, TELOPT_LINEMODE
, '\0' };
239 vty_out (vty
, "%s", cmd
);
242 /* Use window size. */
244 vty_do_window_size (struct vty
*vty
)
246 char cmd
[] = { IAC
, DO
, TELOPT_NAWS
, '\0' };
247 vty_out (vty
, "%s", cmd
);
250 #if 0 /* Currently not used. */
251 /* Make don't use lflow vty interface. */
253 vty_dont_lflow_ahead (struct vty
*vty
)
255 char cmd
[] = { IAC
, DONT
, TELOPT_LFLOW
, '\0' };
256 vty_out (vty
, "%s", cmd
);
260 /* Allocate new vty struct. */
264 struct vty
*new = XCALLOC (MTYPE_VTY
, sizeof (struct vty
));
266 new->obuf
= (struct buffer
*) buffer_new (100);
267 new->buf
= XCALLOC (MTYPE_VTY
, VTY_BUFSIZ
);
268 new->max
= VTY_BUFSIZ
;
269 new->sb_buffer
= NULL
;
274 /* Authentication of vty */
276 vty_auth (struct vty
*vty
, char *buf
)
279 enum node_type next_node
= 0;
281 char *crypt (const char *, const char *);
287 passwd
= host
.password_encrypt
;
289 passwd
= host
.password
;
291 next_node
= host
.enable
? VIEW_NODE
: ENABLE_NODE
;
293 next_node
= VIEW_NODE
;
295 case AUTH_ENABLE_NODE
:
297 passwd
= host
.enable_encrypt
;
299 passwd
= host
.enable
;
300 next_node
= ENABLE_NODE
;
307 fail
= strcmp (crypt(buf
, passwd
), passwd
);
309 fail
= strcmp (buf
, passwd
);
317 vty
->node
= next_node
; /* Success ! */
324 if (vty
->node
== AUTH_NODE
)
326 vty_out (vty
, "%% Bad passwords, too many failures!%s", VTY_NEWLINE
);
327 vty
->status
= VTY_CLOSE
;
331 /* AUTH_ENABLE_NODE */
333 vty_out (vty
, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE
);
334 vty
->node
= VIEW_NODE
;
340 /* Command execution over the vty interface. */
342 vty_command (struct vty
*vty
, char *buf
)
347 /* Split readline string up into the vector */
348 vline
= cmd_make_strvec (buf
);
353 ret
= cmd_execute_command (vline
, vty
, NULL
);
355 if (ret
!= CMD_SUCCESS
)
359 if (vty
->type
== VTY_FILE
)
360 vty_out (vty
, "Warning...%s", VTY_NEWLINE
);
362 case CMD_ERR_AMBIGUOUS
:
363 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
365 case CMD_ERR_NO_MATCH
:
366 vty_out (vty
, "%% Unknown command.%s", VTY_NEWLINE
);
368 case CMD_ERR_INCOMPLETE
:
369 vty_out (vty
, "%% Command incomplete.%s", VTY_NEWLINE
);
372 cmd_free_strvec (vline
);
377 char telnet_backward_char
= 0x08;
378 char telnet_space_char
= ' ';
380 /* Basic function to write buffer to vty. */
382 vty_write (struct vty
*vty
, char *buf
, size_t nbytes
)
384 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
387 /* Should we do buffering here ? And make vty_flush (vty) ? */
388 buffer_write (vty
->obuf
, (u_char
*)buf
, nbytes
);
391 /* Ensure length of input buffer. Is buffer is short, double it. */
393 vty_ensure (struct vty
*vty
, int length
)
395 if (vty
->max
<= length
)
398 vty
->buf
= XREALLOC (MTYPE_VTY
, vty
->buf
, vty
->max
);
402 /* Basic function to insert character into vty. */
404 vty_self_insert (struct vty
*vty
, char c
)
409 vty_ensure (vty
, vty
->length
+ 1);
410 length
= vty
->length
- vty
->cp
;
411 memmove (&vty
->buf
[vty
->cp
+ 1], &vty
->buf
[vty
->cp
], length
);
412 vty
->buf
[vty
->cp
] = c
;
414 vty_write (vty
, &vty
->buf
[vty
->cp
], length
+ 1);
415 for (i
= 0; i
< length
; i
++)
416 vty_write (vty
, &telnet_backward_char
, 1);
422 /* Self insert character 'c' in overwrite mode. */
424 vty_self_insert_overwrite (struct vty
*vty
, char c
)
426 vty_ensure (vty
, vty
->length
+ 1);
427 vty
->buf
[vty
->cp
++] = c
;
429 if (vty
->cp
> vty
->length
)
432 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
435 vty_write (vty
, &c
, 1);
438 /* Insert a word into vty interface with overwrite mode. */
440 vty_insert_word_overwrite (struct vty
*vty
, char *str
)
442 int len
= strlen (str
);
443 vty_write (vty
, str
, len
);
444 strcpy (&vty
->buf
[vty
->cp
], str
);
446 vty
->length
= vty
->cp
;
449 /* Forward character. */
451 vty_forward_char (struct vty
*vty
)
453 if (vty
->cp
< vty
->length
)
455 vty_write (vty
, &vty
->buf
[vty
->cp
], 1);
460 /* Backward character. */
462 vty_backward_char (struct vty
*vty
)
467 vty_write (vty
, &telnet_backward_char
, 1);
471 /* Move to the beginning of the line. */
473 vty_beginning_of_line (struct vty
*vty
)
476 vty_backward_char (vty
);
479 /* Move to the end of the line. */
481 vty_end_of_line (struct vty
*vty
)
483 while (vty
->cp
< vty
->length
)
484 vty_forward_char (vty
);
487 static void vty_kill_line_from_beginning (struct vty
*);
488 static void vty_redraw_line (struct vty
*);
490 /* Print command line history. This function is called from
491 vty_next_line and vty_previous_line. */
493 vty_history_print (struct vty
*vty
)
497 vty_kill_line_from_beginning (vty
);
499 /* Get previous line from history buffer */
500 length
= strlen (vty
->hist
[vty
->hp
]);
501 memcpy (vty
->buf
, vty
->hist
[vty
->hp
], length
);
502 vty
->cp
= vty
->length
= length
;
504 /* Redraw current line */
505 vty_redraw_line (vty
);
508 /* Show next command line history. */
510 vty_next_line (struct vty
*vty
)
514 if (vty
->hp
== vty
->hindex
)
517 /* Try is there history exist or not. */
519 if (try_index
== (VTY_MAXHIST
- 1))
524 /* If there is not history return. */
525 if (vty
->hist
[try_index
] == NULL
)
530 vty_history_print (vty
);
533 /* Show previous command line history. */
535 vty_previous_line (struct vty
*vty
)
541 try_index
= VTY_MAXHIST
- 1;
545 if (vty
->hist
[try_index
] == NULL
)
550 vty_history_print (vty
);
553 /* This function redraw all of the command line character. */
555 vty_redraw_line (struct vty
*vty
)
557 vty_write (vty
, vty
->buf
, vty
->length
);
558 vty
->cp
= vty
->length
;
563 vty_forward_word (struct vty
*vty
)
565 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
566 vty_forward_char (vty
);
568 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
569 vty_forward_char (vty
);
572 /* Backward word without skipping training space. */
574 vty_backward_pure_word (struct vty
*vty
)
576 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
577 vty_backward_char (vty
);
582 vty_backward_word (struct vty
*vty
)
584 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
585 vty_backward_char (vty
);
587 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
588 vty_backward_char (vty
);
591 /* When '^D' is typed at the beginning of the line we move to the down
594 vty_down_level (struct vty
*vty
)
596 vty_out (vty
, "%s", VTY_NEWLINE
);
597 config_exit (NULL
, vty
, 0, NULL
);
602 /* When '^Z' is received from vty, move down to the enable mode. */
604 vty_end_config (struct vty
*vty
)
606 vty_out (vty
, "%s", VTY_NEWLINE
);
628 case KEYCHAIN_KEY_NODE
:
631 vty_config_unlock (vty
);
632 vty
->node
= ENABLE_NODE
;
635 /* Unknown node, we have to ignore it. */
643 /* Delete a charcter at the current point. */
645 vty_delete_char (struct vty
*vty
)
650 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
653 if (vty
->length
== 0)
655 vty_down_level (vty
);
659 if (vty
->cp
== vty
->length
)
660 return; /* completion need here? */
662 size
= vty
->length
- vty
->cp
;
665 memmove (&vty
->buf
[vty
->cp
], &vty
->buf
[vty
->cp
+ 1], size
- 1);
666 vty
->buf
[vty
->length
] = '\0';
668 vty_write (vty
, &vty
->buf
[vty
->cp
], size
- 1);
669 vty_write (vty
, &telnet_space_char
, 1);
671 for (i
= 0; i
< size
; i
++)
672 vty_write (vty
, &telnet_backward_char
, 1);
675 /* Delete a character before the point. */
677 vty_delete_backward_char (struct vty
*vty
)
682 vty_backward_char (vty
);
683 vty_delete_char (vty
);
686 /* Kill rest of line from current point. */
688 vty_kill_line (struct vty
*vty
)
693 size
= vty
->length
- vty
->cp
;
698 for (i
= 0; i
< size
; i
++)
699 vty_write (vty
, &telnet_space_char
, 1);
700 for (i
= 0; i
< size
; i
++)
701 vty_write (vty
, &telnet_backward_char
, 1);
703 memset (&vty
->buf
[vty
->cp
], 0, size
);
704 vty
->length
= vty
->cp
;
707 /* Kill line from the beginning. */
709 vty_kill_line_from_beginning (struct vty
*vty
)
711 vty_beginning_of_line (vty
);
715 /* Delete a word before the point. */
717 vty_forward_kill_word (struct vty
*vty
)
719 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
720 vty_delete_char (vty
);
721 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
722 vty_delete_char (vty
);
725 /* Delete a word before the point. */
727 vty_backward_kill_word (struct vty
*vty
)
729 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
730 vty_delete_backward_char (vty
);
731 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
732 vty_delete_backward_char (vty
);
735 /* Transpose chars before or at the point. */
737 vty_transpose_chars (struct vty
*vty
)
741 /* If length is short or point is near by the beginning of line then
743 if (vty
->length
< 2 || vty
->cp
< 1)
746 /* In case of point is located at the end of the line. */
747 if (vty
->cp
== vty
->length
)
749 c1
= vty
->buf
[vty
->cp
- 1];
750 c2
= vty
->buf
[vty
->cp
- 2];
752 vty_backward_char (vty
);
753 vty_backward_char (vty
);
754 vty_self_insert_overwrite (vty
, c1
);
755 vty_self_insert_overwrite (vty
, c2
);
759 c1
= vty
->buf
[vty
->cp
];
760 c2
= vty
->buf
[vty
->cp
- 1];
762 vty_backward_char (vty
);
763 vty_self_insert_overwrite (vty
, c1
);
764 vty_self_insert_overwrite (vty
, c2
);
768 /* Do completion at vty interface. */
770 vty_complete_command (struct vty
*vty
)
774 char **matched
= NULL
;
777 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
780 vline
= cmd_make_strvec (vty
->buf
);
784 /* In case of 'help \t'. */
785 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
786 vector_set (vline
, '\0');
788 matched
= cmd_complete_command (vline
, vty
, &ret
);
790 cmd_free_strvec (vline
);
792 vty_out (vty
, "%s", VTY_NEWLINE
);
795 case CMD_ERR_AMBIGUOUS
:
796 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
798 vty_redraw_line (vty
);
800 case CMD_ERR_NO_MATCH
:
801 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
803 vty_redraw_line (vty
);
805 case CMD_COMPLETE_FULL_MATCH
:
807 vty_redraw_line (vty
);
808 vty_backward_pure_word (vty
);
809 vty_insert_word_overwrite (vty
, matched
[0]);
810 vty_self_insert (vty
, ' ');
811 XFREE (MTYPE_TMP
, matched
[0]);
813 case CMD_COMPLETE_MATCH
:
815 vty_redraw_line (vty
);
816 vty_backward_pure_word (vty
);
817 vty_insert_word_overwrite (vty
, matched
[0]);
818 XFREE (MTYPE_TMP
, matched
[0]);
819 vector_only_index_free (matched
);
822 case CMD_COMPLETE_LIST_MATCH
:
823 for (i
= 0; matched
[i
] != NULL
; i
++)
825 if (i
!= 0 && ((i
% 6) == 0))
826 vty_out (vty
, "%s", VTY_NEWLINE
);
827 vty_out (vty
, "%-10s ", matched
[i
]);
828 XFREE (MTYPE_TMP
, matched
[i
]);
830 vty_out (vty
, "%s", VTY_NEWLINE
);
833 vty_redraw_line (vty
);
835 case CMD_ERR_NOTHING_TODO
:
837 vty_redraw_line (vty
);
843 vector_only_index_free (matched
);
847 vty_describe_fold (struct vty
*vty
, int cmd_width
,
848 int desc_width
, struct desc
*desc
)
853 cmd
= desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
;
857 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, desc
->str
, VTY_NEWLINE
);
861 buf
= XCALLOC (MTYPE_TMP
, strlen (desc
->str
) + 1);
863 for (p
= desc
->str
; strlen (p
) > desc_width
; p
+= pos
+ 1)
865 for (pos
= desc_width
; pos
> 0; pos
--)
866 if (*(p
+ pos
) == ' ')
872 strncpy (buf
, p
, pos
);
874 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, buf
, VTY_NEWLINE
);
879 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, p
, VTY_NEWLINE
);
881 XFREE (MTYPE_TMP
, buf
);
884 /* Describe matched command function. */
886 vty_describe_command (struct vty
*vty
)
891 int i
, width
, desc_width
;
892 struct desc
*desc
, *desc_cr
= NULL
;
894 vline
= cmd_make_strvec (vty
->buf
);
896 /* In case of '> ?'. */
899 vline
= vector_init (1);
900 vector_set (vline
, '\0');
903 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
904 vector_set (vline
, '\0');
906 describe
= cmd_describe_command (vline
, vty
, &ret
);
908 vty_out (vty
, "%s", VTY_NEWLINE
);
910 /* Ambiguous error. */
913 case CMD_ERR_AMBIGUOUS
:
914 cmd_free_strvec (vline
);
915 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
917 vty_redraw_line (vty
);
920 case CMD_ERR_NO_MATCH
:
921 cmd_free_strvec (vline
);
922 vty_out (vty
, "%% There is no matched command.%s", VTY_NEWLINE
);
924 vty_redraw_line (vty
);
929 /* Get width of command string. */
931 for (i
= 0; i
< vector_max (describe
); i
++)
932 if ((desc
= vector_slot (describe
, i
)) != NULL
)
936 if (desc
->cmd
[0] == '\0')
939 len
= strlen (desc
->cmd
);
940 if (desc
->cmd
[0] == '.')
947 /* Get width of description string. */
948 desc_width
= vty
->width
- (width
+ 6);
950 /* Print out description. */
951 for (i
= 0; i
< vector_max (describe
); i
++)
952 if ((desc
= vector_slot (describe
, i
)) != NULL
)
954 if (desc
->cmd
[0] == '\0')
957 if (strcmp (desc
->cmd
, "<cr>") == 0)
964 vty_out (vty
, " %-s%s",
965 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
967 else if (desc_width
>= strlen (desc
->str
))
968 vty_out (vty
, " %-*s %s%s", width
,
969 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
970 desc
->str
, VTY_NEWLINE
);
972 vty_describe_fold (vty
, width
, desc_width
, desc
);
975 vty_out (vty
, " %-*s %s%s", width
976 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
977 desc
->str
? desc
->str
: "", VTY_NEWLINE
);
981 if ((desc
= desc_cr
))
984 vty_out (vty
, " %-s%s",
985 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
987 else if (desc_width
>= strlen (desc
->str
))
988 vty_out (vty
, " %-*s %s%s", width
,
989 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
990 desc
->str
, VTY_NEWLINE
);
992 vty_describe_fold (vty
, width
, desc_width
, desc
);
995 cmd_free_strvec (vline
);
996 vector_free (describe
);
999 vty_redraw_line (vty
);
1003 vty_clear_buf (struct vty
*vty
)
1005 memset (vty
->buf
, 0, vty
->max
);
1008 /* ^C stop current input and do not add command line to the history. */
1010 vty_stop_input (struct vty
*vty
)
1012 vty
->cp
= vty
->length
= 0;
1013 vty_clear_buf (vty
);
1014 vty_out (vty
, "%s", VTY_NEWLINE
);
1020 /* Nothing to do. */
1023 case INTERFACE_NODE
:
1032 case KEYCHAIN_KEY_NODE
:
1035 vty_config_unlock (vty
);
1036 vty
->node
= ENABLE_NODE
;
1039 /* Unknown node, we have to ignore it. */
1044 /* Set history pointer to the latest one. */
1045 vty
->hp
= vty
->hindex
;
1048 /* Add current command line to the history buffer. */
1050 vty_hist_add (struct vty
*vty
)
1054 if (vty
->length
== 0)
1057 index
= vty
->hindex
? vty
->hindex
- 1 : VTY_MAXHIST
- 1;
1059 /* Ignore the same string as previous one. */
1060 if (vty
->hist
[index
])
1061 if (strcmp (vty
->buf
, vty
->hist
[index
]) == 0)
1063 vty
->hp
= vty
->hindex
;
1067 /* Insert history entry. */
1068 if (vty
->hist
[vty
->hindex
])
1069 XFREE (MTYPE_VTY_HIST
, vty
->hist
[vty
->hindex
]);
1070 vty
->hist
[vty
->hindex
] = XSTRDUP (MTYPE_VTY_HIST
, vty
->buf
);
1072 /* History index rotation. */
1074 if (vty
->hindex
== VTY_MAXHIST
)
1077 vty
->hp
= vty
->hindex
;
1080 /* #define TELNET_OPTION_DEBUG */
1082 /* Get telnet window size. */
1084 vty_telnet_option (struct vty
*vty
, unsigned char *buf
, int nbytes
)
1086 #ifdef TELNET_OPTION_DEBUG
1089 for (i
= 0; i
< nbytes
; i
++)
1094 vty_out (vty
, "IAC ");
1097 vty_out (vty
, "WILL ");
1100 vty_out (vty
, "WONT ");
1103 vty_out (vty
, "DO ");
1106 vty_out (vty
, "DONT ");
1109 vty_out (vty
, "SB ");
1112 vty_out (vty
, "SE ");
1115 vty_out (vty
, "TELOPT_ECHO %s", VTY_NEWLINE
);
1118 vty_out (vty
, "TELOPT_SGA %s", VTY_NEWLINE
);
1121 vty_out (vty
, "TELOPT_NAWS %s", VTY_NEWLINE
);
1124 vty_out (vty
, "%x ", buf
[i
]);
1128 vty_out (vty
, "%s", VTY_NEWLINE
);
1130 #endif /* TELNET_OPTION_DEBUG */
1135 buffer_reset(vty
->sb_buffer
);
1136 vty
->iac_sb_in_progress
= 1;
1141 char *buffer
= (char *)vty
->sb_buffer
->head
->data
;
1142 int length
= vty
->sb_buffer
->length
;
1147 if (!vty
->iac_sb_in_progress
)
1150 if (buffer
[0] == '\0')
1152 vty
->iac_sb_in_progress
= 0;
1160 vty
->width
= buffer
[2];
1161 vty
->height
= vty
->lines
>= 0 ? vty
->lines
: buffer
[4];
1164 vty
->iac_sb_in_progress
= 0;
1174 /* Execute current command line. */
1176 vty_execute (struct vty
*vty
)
1185 case AUTH_ENABLE_NODE
:
1186 vty_auth (vty
, vty
->buf
);
1189 ret
= vty_command (vty
, vty
->buf
);
1190 if (vty
->type
== VTY_TERM
)
1195 /* Clear command line buffer. */
1196 vty
->cp
= vty
->length
= 0;
1197 vty_clear_buf (vty
);
1199 if (vty
->status
!= VTY_CLOSE
1200 && vty
->status
!= VTY_START
1201 && vty
->status
!= VTY_CONTINUE
)
1207 #define CONTROL(X) ((X) - '@')
1208 #define VTY_NORMAL 0
1209 #define VTY_PRE_ESCAPE 1
1210 #define VTY_ESCAPE 2
1212 /* Escape character command map. */
1214 vty_escape_map (unsigned char c
, struct vty
*vty
)
1219 vty_previous_line (vty
);
1222 vty_next_line (vty
);
1225 vty_forward_char (vty
);
1228 vty_backward_char (vty
);
1234 /* Go back to normal mode. */
1235 vty
->escape
= VTY_NORMAL
;
1238 /* Quit print out to the buffer. */
1240 vty_buffer_reset (struct vty
*vty
)
1242 buffer_reset (vty
->obuf
);
1244 vty_redraw_line (vty
);
1247 /* Read data via vty socket. */
1249 vty_read (struct thread
*thread
)
1254 unsigned char buf
[VTY_READ_BUFSIZ
];
1256 int vty_sock
= THREAD_FD (thread
);
1257 struct vty
*vty
= THREAD_ARG (thread
);
1260 /* Read raw data from socket */
1261 nbytes
= read (vty
->fd
, buf
, VTY_READ_BUFSIZ
);
1263 vty
->status
= VTY_CLOSE
;
1265 for (i
= 0; i
< nbytes
; i
++)
1280 if (vty
->iac_sb_in_progress
&& !vty
->iac
)
1282 buffer_putc(vty
->sb_buffer
, buf
[i
]);
1288 /* In case of telnet command */
1289 ret
= vty_telnet_option (vty
, buf
+ i
, nbytes
- i
);
1295 if (vty
->status
== VTY_MORE
)
1302 if (vty
->output_func
)
1303 (*vty
->output_func
) (vty
, 1);
1304 vty_buffer_reset (vty
);
1306 #if 0 /* More line does not work for "show ip bgp". */
1309 vty
->status
= VTY_MORELINE
;
1313 if (vty
->output_func
)
1314 (*vty
->output_func
) (vty
, 0);
1320 /* Escape character. */
1321 if (vty
->escape
== VTY_ESCAPE
)
1323 vty_escape_map (buf
[i
], vty
);
1327 /* Pre-escape status. */
1328 if (vty
->escape
== VTY_PRE_ESCAPE
)
1333 vty
->escape
= VTY_ESCAPE
;
1336 vty_backward_word (vty
);
1337 vty
->escape
= VTY_NORMAL
;
1340 vty_forward_word (vty
);
1341 vty
->escape
= VTY_NORMAL
;
1344 vty_forward_kill_word (vty
);
1345 vty
->escape
= VTY_NORMAL
;
1349 vty_backward_kill_word (vty
);
1350 vty
->escape
= VTY_NORMAL
;
1353 vty
->escape
= VTY_NORMAL
;
1362 vty_beginning_of_line (vty
);
1365 vty_backward_char (vty
);
1368 vty_stop_input (vty
);
1371 vty_delete_char (vty
);
1374 vty_end_of_line (vty
);
1377 vty_forward_char (vty
);
1381 vty_delete_backward_char (vty
);
1384 vty_kill_line (vty
);
1387 vty_next_line (vty
);
1390 vty_previous_line (vty
);
1393 vty_transpose_chars (vty
);
1396 vty_kill_line_from_beginning (vty
);
1399 vty_backward_kill_word (vty
);
1402 vty_end_config (vty
);
1406 vty_out (vty
, "%s", VTY_NEWLINE
);
1410 vty_complete_command (vty
);
1413 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
1414 vty_self_insert (vty
, buf
[i
]);
1416 vty_describe_command (vty
);
1419 if (i
+ 1 < nbytes
&& buf
[i
+ 1] == '[')
1421 vty
->escape
= VTY_ESCAPE
;
1425 vty
->escape
= VTY_PRE_ESCAPE
;
1428 if (buf
[i
] > 31 && buf
[i
] < 127)
1429 vty_self_insert (vty
, buf
[i
]);
1435 if (vty
->status
== VTY_CLOSE
)
1439 vty_event (VTY_WRITE
, vty_sock
, vty
);
1440 vty_event (VTY_READ
, vty_sock
, vty
);
1445 /* Flush buffer to the vty. */
1447 vty_flush (struct thread
*thread
)
1451 int vty_sock
= THREAD_FD (thread
);
1452 struct vty
*vty
= THREAD_ARG (thread
);
1453 vty
->t_write
= NULL
;
1455 /* Tempolary disable read thread. */
1456 if (vty
->lines
== 0)
1459 thread_cancel (vty
->t_read
);
1463 /* Function execution continue. */
1464 if (vty
->status
== VTY_START
|| vty
->status
== VTY_CONTINUE
)
1466 if (vty
->status
== VTY_CONTINUE
)
1471 if (vty
->output_func
== NULL
)
1476 if (vty
->lines
== 0)
1482 buffer_flush_vty_all (vty
->obuf
, vty
->fd
, erase
, dont_more
);
1484 if (vty
->status
== VTY_CLOSE
)
1490 if (vty
->output_func
== NULL
)
1492 vty
->status
= VTY_NORMAL
;
1494 vty_event (VTY_WRITE
, vty_sock
, vty
);
1497 vty
->status
= VTY_MORE
;
1499 if (vty
->lines
== 0)
1501 if (vty
->output_func
== NULL
)
1502 vty_event (VTY_READ
, vty_sock
, vty
);
1505 if (vty
->output_func
)
1506 (*vty
->output_func
) (vty
, 0);
1507 vty_event (VTY_WRITE
, vty_sock
, vty
);
1513 if (vty
->status
== VTY_MORE
|| vty
->status
== VTY_MORELINE
)
1518 if (vty
->lines
== 0)
1519 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 25, 0, 1);
1520 else if (vty
->status
== VTY_MORELINE
)
1521 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 1, erase
, 0);
1523 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
,
1524 vty
->lines
>= 0 ? vty
->lines
: vty
->height
,
1527 if (buffer_empty (vty
->obuf
))
1529 if (vty
->status
== VTY_CLOSE
)
1533 vty
->status
= VTY_NORMAL
;
1535 if (vty
->lines
== 0)
1536 vty_event (VTY_READ
, vty_sock
, vty
);
1541 vty
->status
= VTY_MORE
;
1543 if (vty
->lines
== 0)
1544 vty_event (VTY_WRITE
, vty_sock
, vty
);
1551 /* Create new vty structure. */
1553 vty_create (int vty_sock
, union sockunion
*su
)
1557 /* Allocate new vty structure and set up default values. */
1560 vty
->type
= VTY_TERM
;
1561 vty
->address
= sockunion_su2str (su
);
1562 if (no_password_check
)
1565 vty
->node
= ENABLE_NODE
;
1567 vty
->node
= VIEW_NODE
;
1570 vty
->node
= AUTH_NODE
;
1573 vty_clear_buf (vty
);
1575 memset (vty
->hist
, 0, sizeof (vty
->hist
));
1578 vector_set_index (vtyvec
, vty_sock
, vty
);
1579 vty
->status
= VTY_NORMAL
;
1580 vty
->v_timeout
= vty_timeout_val
;
1581 if (host
.lines
>= 0)
1582 vty
->lines
= host
.lines
;
1586 vty
->iac_sb_in_progress
= 0;
1587 vty
->sb_buffer
= buffer_new (1024);
1589 if (! no_password_check
)
1591 /* Vty is not available if password isn't set. */
1592 if (host
.password
== NULL
&& host
.password_encrypt
== NULL
)
1594 vty_out (vty
, "Vty password is not set.%s", VTY_NEWLINE
);
1595 vty
->status
= VTY_CLOSE
;
1601 /* Say hello to the world. */
1603 if (! no_password_check
)
1604 vty_out (vty
, "%sUser Access Verification%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1606 /* Setting up terminal. */
1607 vty_will_echo (vty
);
1608 vty_will_suppress_go_ahead (vty
);
1610 vty_dont_linemode (vty
);
1611 vty_do_window_size (vty
);
1612 /* vty_dont_lflow_ahead (vty); */
1616 /* Add read/write thread. */
1617 vty_event (VTY_WRITE
, vty_sock
, vty
);
1618 vty_event (VTY_READ
, vty_sock
, vty
);
1623 /* Accept connection from the network. */
1625 vty_accept (struct thread
*thread
)
1633 struct prefix
*p
= NULL
;
1634 struct access_list
*acl
= NULL
;
1636 accept_sock
= THREAD_FD (thread
);
1638 /* We continue hearing vty socket. */
1639 vty_event (VTY_SERV
, accept_sock
, NULL
);
1641 memset (&su
, 0, sizeof (union sockunion
));
1643 /* We can handle IPv4 or IPv6 socket. */
1644 vty_sock
= sockunion_accept (accept_sock
, &su
);
1647 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1651 p
= sockunion2hostprefix (&su
);
1653 /* VTY's accesslist apply. */
1654 if (p
->family
== AF_INET
&& vty_accesslist_name
)
1656 if ((acl
= access_list_lookup (AFI_IP
, vty_accesslist_name
)) &&
1657 (access_list_apply (acl
, p
) == FILTER_DENY
))
1660 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1661 (buf
= sockunion_su2str (&su
)));
1665 /* continue accepting connections */
1666 vty_event (VTY_SERV
, accept_sock
, NULL
);
1675 /* VTY's ipv6 accesslist apply. */
1676 if (p
->family
== AF_INET6
&& vty_ipv6_accesslist_name
)
1678 if ((acl
= access_list_lookup (AFI_IP6
, vty_ipv6_accesslist_name
)) &&
1679 (access_list_apply (acl
, p
) == FILTER_DENY
))
1682 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1683 (buf
= sockunion_su2str (&su
)));
1687 /* continue accepting connections */
1688 vty_event (VTY_SERV
, accept_sock
, NULL
);
1695 #endif /* HAVE_IPV6 */
1700 ret
= setsockopt (vty_sock
, IPPROTO_TCP
, TCP_NODELAY
,
1701 (char *) &on
, sizeof (on
));
1703 zlog (NULL
, LOG_INFO
, "can't set sockopt to vty_sock : %s",
1706 vty
= vty_create (vty_sock
, &su
);
1711 #if defined(HAVE_IPV6) && !defined(NRL)
1713 vty_serv_sock_addrinfo (const char *hostname
, unsigned short port
)
1716 struct addrinfo req
;
1717 struct addrinfo
*ainfo
;
1718 struct addrinfo
*ainfo_save
;
1720 char port_str
[BUFSIZ
];
1722 memset (&req
, 0, sizeof (struct addrinfo
));
1723 req
.ai_flags
= AI_PASSIVE
;
1724 req
.ai_family
= AF_UNSPEC
;
1725 req
.ai_socktype
= SOCK_STREAM
;
1726 sprintf (port_str
, "%d", port
);
1727 port_str
[sizeof (port_str
) - 1] = '\0';
1729 ret
= getaddrinfo (hostname
, port_str
, &req
, &ainfo
);
1733 fprintf (stderr
, "getaddrinfo failed: %s\n", gai_strerror (ret
));
1741 if (ainfo
->ai_family
!= AF_INET
1743 && ainfo
->ai_family
!= AF_INET6
1744 #endif /* HAVE_IPV6 */
1748 sock
= socket (ainfo
->ai_family
, ainfo
->ai_socktype
, ainfo
->ai_protocol
);
1752 sockopt_reuseaddr (sock
);
1753 sockopt_reuseport (sock
);
1755 ret
= bind (sock
, ainfo
->ai_addr
, ainfo
->ai_addrlen
);
1758 close (sock
); /* Avoid sd leak. */
1762 ret
= listen (sock
, 3);
1765 close (sock
); /* Avoid sd leak. */
1769 vty_event (VTY_SERV
, sock
, NULL
);
1771 while ((ainfo
= ainfo
->ai_next
) != NULL
);
1773 freeaddrinfo (ainfo_save
);
1775 #endif /* HAVE_IPV6 && ! NRL */
1777 /* Make vty server socket. */
1779 vty_serv_sock_family (const char* addr
, unsigned short port
, int family
)
1786 memset (&su
, 0, sizeof (union sockunion
));
1787 su
.sa
.sa_family
= family
;
1792 naddr
=&su
.sin
.sin_addr
;
1795 naddr
=&su
.sin6
.sin6_addr
;
1800 switch(inet_pton(family
,addr
,naddr
))
1803 zlog_err("bad address %s",addr
);
1807 zlog_err("error translating address %s: %s",addr
,strerror(errno
));
1811 /* Make new socket. */
1812 accept_sock
= sockunion_stream_socket (&su
);
1813 if (accept_sock
< 0)
1816 /* This is server, so reuse address. */
1817 sockopt_reuseaddr (accept_sock
);
1818 sockopt_reuseport (accept_sock
);
1820 /* Bind socket to universal address and given port. */
1821 ret
= sockunion_bind (accept_sock
, &su
, port
, naddr
);
1824 zlog_warn("can't bind socket");
1825 close (accept_sock
); /* Avoid sd leak. */
1829 /* Listen socket under queue 3. */
1830 ret
= listen (accept_sock
, 3);
1833 zlog (NULL
, LOG_WARNING
, "can't listen socket");
1834 close (accept_sock
); /* Avoid sd leak. */
1838 /* Add vty server event. */
1839 vty_event (VTY_SERV
, accept_sock
, NULL
);
1843 /* For sockaddr_un. */
1846 /* VTY shell UNIX domain socket. */
1848 vty_serv_un (char *path
)
1852 struct sockaddr_un serv
;
1855 /* First of all, unlink existing socket */
1859 old_mask
= umask (0007);
1861 /* Make UNIX domain socket. */
1862 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
1869 /* Make server socket. */
1870 memset (&serv
, 0, sizeof (struct sockaddr_un
));
1871 serv
.sun_family
= AF_UNIX
;
1872 strncpy (serv
.sun_path
, path
, strlen (path
));
1874 len
= serv
.sun_len
= SUN_LEN(&serv
);
1876 len
= sizeof (serv
.sun_family
) + strlen (serv
.sun_path
);
1877 #endif /* HAVE_SUN_LEN */
1879 ret
= bind (sock
, (struct sockaddr
*) &serv
, len
);
1883 close (sock
); /* Avoid sd leak. */
1887 ret
= listen (sock
, 5);
1891 close (sock
); /* Avoid sd leak. */
1897 vty_event (VTYSH_SERV
, sock
, NULL
);
1900 /* #define VTYSH_DEBUG 1 */
1903 vtysh_accept (struct thread
*thread
)
1908 struct sockaddr_un client
;
1911 accept_sock
= THREAD_FD (thread
);
1913 vty_event (VTYSH_SERV
, accept_sock
, NULL
);
1915 memset (&client
, 0, sizeof (struct sockaddr_un
));
1916 client_len
= sizeof (struct sockaddr_un
);
1918 sock
= accept (accept_sock
, (struct sockaddr
*) &client
, &client_len
);
1922 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1927 printf ("VTY shell accept\n");
1928 #endif /* VTYSH_DEBUG */
1932 vty
->type
= VTY_SHELL_SERV
;
1933 vty
->node
= VIEW_NODE
;
1935 vty_event (VTYSH_READ
, sock
, vty
);
1941 vtysh_read (struct thread
*thread
)
1947 unsigned char buf
[VTY_READ_BUFSIZ
];
1948 u_char header
[4] = {0, 0, 0, 0};
1950 sock
= THREAD_FD (thread
);
1951 vty
= THREAD_ARG (thread
);
1954 nbytes
= read (sock
, buf
, VTY_READ_BUFSIZ
);
1959 printf ("close vtysh\n");
1960 #endif /* VTYSH_DEBUG */
1965 printf ("line: %s\n", buf
);
1966 #endif /* VTYSH_DEBUG */
1968 vty_ensure (vty
, nbytes
);
1969 memcpy (vty
->buf
, buf
, nbytes
);
1971 /* Pass this line to parser. */
1972 ret
= vty_execute (vty
);
1974 vty_clear_buf (vty
);
1976 /* Return result. */
1978 printf ("result: %d\n", ret
);
1979 printf ("vtysh node: %d\n", vty
->node
);
1980 #endif /* VTYSH_DEBUG */
1983 write (vty
->fd
, header
, 4);
1985 vty_event (VTYSH_READ
, sock
, vty
);
1991 /* Determine address family to bind. */
1993 vty_serv_sock (const char *addr
, unsigned short port
, char *path
)
1995 /* If port is set to 0, do not listen on TCP/IP at all! */
2001 vty_serv_sock_family (addr
, port
, AF_INET
);
2002 vty_serv_sock_family (addr
, port
, AF_INET6
);
2004 vty_serv_sock_addrinfo (addr
, port
);
2006 #else /* ! HAVE_IPV6 */
2007 vty_serv_sock_family (addr
,port
, AF_INET
);
2008 #endif /* HAVE_IPV6 */
2016 /* Close vty interface. */
2018 vty_close (struct vty
*vty
)
2022 /* Cancel threads.*/
2024 thread_cancel (vty
->t_read
);
2026 thread_cancel (vty
->t_write
);
2028 thread_cancel (vty
->t_timeout
);
2030 thread_cancel (vty
->t_output
);
2033 if (! buffer_empty (vty
->obuf
))
2034 buffer_flush_all (vty
->obuf
, vty
->fd
);
2036 /* Free input buffer. */
2037 buffer_free (vty
->obuf
);
2039 /* Free SB buffer. */
2041 buffer_free (vty
->sb_buffer
);
2043 /* Free command history. */
2044 for (i
= 0; i
< VTY_MAXHIST
; i
++)
2046 XFREE (MTYPE_VTY_HIST
, vty
->hist
[i
]);
2049 vector_unset (vtyvec
, vty
->fd
);
2056 XFREE (0, vty
->address
);
2058 XFREE (MTYPE_VTY
, vty
->buf
);
2060 /* Check configure. */
2061 vty_config_unlock (vty
);
2064 XFREE (MTYPE_VTY
, vty
);
2067 /* When time out occur output message then close connection. */
2069 vty_timeout (struct thread
*thread
)
2073 vty
= THREAD_ARG (thread
);
2074 vty
->t_timeout
= NULL
;
2078 buffer_reset (vty
->obuf
);
2079 vty_out (vty
, "%sVty connection is timed out.%s", VTY_NEWLINE
, VTY_NEWLINE
);
2081 /* Close connection. */
2082 vty
->status
= VTY_CLOSE
;
2088 /* Read up configuration file from file_name. */
2090 vty_read_file (FILE *confp
)
2096 vty
->fd
= 0; /* stdout */
2097 vty
->type
= VTY_TERM
;
2098 vty
->node
= CONFIG_NODE
;
2100 /* Execute configuration file */
2101 ret
= config_from_file (vty
, confp
);
2103 if (ret
!= CMD_SUCCESS
)
2107 case CMD_ERR_AMBIGUOUS
:
2108 fprintf (stderr
, "Ambiguous command.\n");
2110 case CMD_ERR_NO_MATCH
:
2111 fprintf (stderr
, "There is no such command.\n");
2114 fprintf (stderr
, "Error occured during reading below line.\n%s\n",
2124 vty_use_backup_config (char *fullpath
)
2126 char *fullpath_sav
, *fullpath_tmp
;
2133 fullpath_sav
= malloc (strlen (fullpath
) + strlen (CONF_BACKUP_EXT
) + 1);
2134 strcpy (fullpath_sav
, fullpath
);
2135 strcat (fullpath_sav
, CONF_BACKUP_EXT
);
2136 if (stat (fullpath_sav
, &buf
) == -1)
2138 free (fullpath_sav
);
2142 fullpath_tmp
= malloc (strlen (fullpath
) + 8);
2143 sprintf (fullpath_tmp
, "%s.XXXXXX", fullpath
);
2145 /* Open file to configuration write. */
2146 tmp
= mkstemp (fullpath_tmp
);
2149 free (fullpath_sav
);
2150 free (fullpath_tmp
);
2154 sav
= open (fullpath_sav
, O_RDONLY
);
2157 free (fullpath_sav
);
2158 free (fullpath_tmp
);
2159 unlink (fullpath_tmp
);
2163 while((c
= read (sav
, buffer
, 512)) > 0)
2164 write (tmp
, buffer
, c
);
2169 if (link (fullpath_tmp
, fullpath
) == 0)
2170 ret
= fopen (fullpath
, "r");
2172 unlink (fullpath_tmp
);
2174 free (fullpath_sav
);
2175 free (fullpath_tmp
);
2176 return fopen (fullpath
, "r");
2179 /* Read up configuration file from file_name. */
2181 vty_read_config (char *config_file
,
2182 char *config_current_dir
,
2183 char *config_default_dir
)
2189 /* If -f flag specified. */
2190 if (config_file
!= NULL
)
2192 if (! IS_DIRECTORY_SEP (config_file
[0]))
2194 cwd
= getcwd (NULL
, MAXPATHLEN
);
2195 fullpath
= XMALLOC (MTYPE_TMP
,
2196 strlen (cwd
) + strlen (config_file
) + 2);
2197 sprintf (fullpath
, "%s/%s", cwd
, config_file
);
2200 fullpath
= config_file
;
2202 confp
= fopen (fullpath
, "r");
2206 confp
= vty_use_backup_config (fullpath
);
2208 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2211 fprintf (stderr
, "can't open configuration file [%s]\n",
2219 /* Relative path configuration file open. */
2220 if (config_current_dir
)
2222 confp
= fopen (config_current_dir
, "r");
2225 confp
= vty_use_backup_config (config_current_dir
);
2227 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2231 /* If there is no relative path exists, open system default file. */
2236 struct stat conf_stat
;
2238 /* !!!!PLEASE LEAVE!!!!
2239 This is NEEDED for use with vtysh -b, or else you can get
2240 a real configuration food fight with a lot garbage in the
2241 merged configuration file it creates coming from the per
2242 daemon configuration files. This also allows the daemons
2243 to start if there default configuration file is not
2244 present or ignore them, as needed when using vtysh -b to
2245 configure the daemons at boot - MAG */
2247 /* Stat for vtysh Zebra.conf, if found startup and wait for
2248 boot configuration */
2250 if ( strstr(config_default_dir
, "vtysh") == NULL
)
2252 ret
= stat (integrate_default
, &conf_stat
);
2260 confp
= fopen (config_default_dir
, "r");
2263 confp
= vty_use_backup_config (config_default_dir
);
2266 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2267 fullpath
= config_default_dir
;
2271 fprintf (stderr
, "can't open configuration file [%s]\n",
2272 config_default_dir
);
2277 fullpath
= config_default_dir
;
2281 /* Rleative path configuration file. */
2282 cwd
= getcwd (NULL
, MAXPATHLEN
);
2283 fullpath
= XMALLOC (MTYPE_TMP
,
2284 strlen (cwd
) + strlen (config_current_dir
) + 2);
2285 sprintf (fullpath
, "%s/%s", cwd
, config_current_dir
);
2288 vty_read_file (confp
);
2292 host_config_set (fullpath
);
2295 /* Small utility function which output log to the VTY. */
2297 vty_log (const char *proto_str
, const char *format
, va_list va
)
2302 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2303 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2305 vty_log_out (vty
, proto_str
, format
, va
);
2309 vty_config_lock (struct vty
*vty
)
2311 if (vty_config
== 0)
2320 vty_config_unlock (struct vty
*vty
)
2322 if (vty_config
== 1 && vty
->config
== 1)
2330 /* Master of the threads. */
2331 extern struct thread_master
*master
;
2332 /* struct thread_master *master; */
2335 vty_event (enum event event
, int sock
, struct vty
*vty
)
2337 struct thread
*vty_serv_thread
;
2342 vty_serv_thread
= thread_add_read (master
, vty_accept
, vty
, sock
);
2343 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2347 thread_add_read (master
, vtysh_accept
, vty
, sock
);
2350 thread_add_read (master
, vtysh_read
, vty
, sock
);
2354 vty
->t_read
= thread_add_read (master
, vty_read
, vty
, sock
);
2356 /* Time out treatment. */
2360 thread_cancel (vty
->t_timeout
);
2362 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2367 vty
->t_write
= thread_add_write (master
, vty_flush
, vty
, sock
);
2369 case VTY_TIMEOUT_RESET
:
2372 thread_cancel (vty
->t_timeout
);
2373 vty
->t_timeout
= NULL
;
2378 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2387 "Display who is on vty\n")
2392 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2393 if ((v
= vector_slot (vtyvec
, i
)) != NULL
)
2394 vty_out (vty
, "%svty[%d] connected from %s.%s",
2395 v
->config
? "*" : " ",
2396 i
, v
->address
, VTY_NEWLINE
);
2400 /* Move to vty configuration mode. */
2404 "Configure a terminal line\n"
2405 "Virtual terminal\n")
2407 vty
->node
= VTY_NODE
;
2411 /* Set time out value. */
2413 exec_timeout (struct vty
*vty
, char *min_str
, char *sec_str
)
2415 unsigned long timeout
= 0;
2417 /* min_str and sec_str are already checked by parser. So it must be
2418 all digit string. */
2421 timeout
= strtol (min_str
, NULL
, 10);
2425 timeout
+= strtol (sec_str
, NULL
, 10);
2427 vty_timeout_val
= timeout
;
2428 vty
->v_timeout
= timeout
;
2429 vty_event (VTY_TIMEOUT_RESET
, 0, vty
);
2435 DEFUN (exec_timeout_min
,
2436 exec_timeout_min_cmd
,
2437 "exec-timeout <0-35791>",
2438 "Set timeout value\n"
2439 "Timeout value in minutes\n")
2441 return exec_timeout (vty
, argv
[0], NULL
);
2444 DEFUN (exec_timeout_sec
,
2445 exec_timeout_sec_cmd
,
2446 "exec-timeout <0-35791> <0-2147483>",
2447 "Set the EXEC timeout\n"
2448 "Timeout in minutes\n"
2449 "Timeout in seconds\n")
2451 return exec_timeout (vty
, argv
[0], argv
[1]);
2454 DEFUN (no_exec_timeout
,
2455 no_exec_timeout_cmd
,
2458 "Set the EXEC timeout\n")
2460 return exec_timeout (vty
, NULL
, NULL
);
2463 /* Set vty access class. */
2464 DEFUN (vty_access_class
,
2465 vty_access_class_cmd
,
2466 "access-class WORD",
2467 "Filter connections based on an IP access list\n"
2470 if (vty_accesslist_name
)
2471 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2473 vty_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2478 /* Clear vty access class. */
2479 DEFUN (no_vty_access_class
,
2480 no_vty_access_class_cmd
,
2481 "no access-class [WORD]",
2483 "Filter connections based on an IP access list\n"
2486 if (! vty_accesslist_name
|| (argc
&& strcmp(vty_accesslist_name
, argv
[0])))
2488 vty_out (vty
, "Access-class is not currently applied to vty%s",
2493 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2495 vty_accesslist_name
= NULL
;
2501 /* Set vty access class. */
2502 DEFUN (vty_ipv6_access_class
,
2503 vty_ipv6_access_class_cmd
,
2504 "ipv6 access-class WORD",
2506 "Filter connections based on an IP access list\n"
2507 "IPv6 access list\n")
2509 if (vty_ipv6_accesslist_name
)
2510 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2512 vty_ipv6_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2517 /* Clear vty access class. */
2518 DEFUN (no_vty_ipv6_access_class
,
2519 no_vty_ipv6_access_class_cmd
,
2520 "no ipv6 access-class [WORD]",
2523 "Filter connections based on an IP access list\n"
2524 "IPv6 access list\n")
2526 if (! vty_ipv6_accesslist_name
||
2527 (argc
&& strcmp(vty_ipv6_accesslist_name
, argv
[0])))
2529 vty_out (vty
, "IPv6 access-class is not currently applied to vty%s",
2534 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2536 vty_ipv6_accesslist_name
= NULL
;
2540 #endif /* HAVE_IPV6 */
2546 "Enable password checking\n")
2548 no_password_check
= 0;
2552 DEFUN (no_vty_login
,
2556 "Enable password checking\n")
2558 no_password_check
= 1;
2562 DEFUN (service_advanced_vty
,
2563 service_advanced_vty_cmd
,
2564 "service advanced-vty",
2565 "Set up miscellaneous service\n"
2566 "Enable advanced mode vty interface\n")
2572 DEFUN (no_service_advanced_vty
,
2573 no_service_advanced_vty_cmd
,
2574 "no service advanced-vty",
2576 "Set up miscellaneous service\n"
2577 "Enable advanced mode vty interface\n")
2583 DEFUN (terminal_monitor
,
2584 terminal_monitor_cmd
,
2586 "Set terminal line parameters\n"
2587 "Copy debug output to the current terminal line\n")
2593 DEFUN (terminal_no_monitor
,
2594 terminal_no_monitor_cmd
,
2595 "terminal no monitor",
2596 "Set terminal line parameters\n"
2598 "Copy debug output to the current terminal line\n")
2604 DEFUN (show_history
,
2608 "Display the session command history\n")
2612 for (index
= vty
->hindex
+ 1; index
!= vty
->hindex
;)
2614 if (index
== VTY_MAXHIST
)
2620 if (vty
->hist
[index
] != NULL
)
2621 vty_out (vty
, " %s%s", vty
->hist
[index
], VTY_NEWLINE
);
2629 /* Display current configuration. */
2631 vty_config_write (struct vty
*vty
)
2633 vty_out (vty
, "line vty%s", VTY_NEWLINE
);
2635 if (vty_accesslist_name
)
2636 vty_out (vty
, " access-class %s%s",
2637 vty_accesslist_name
, VTY_NEWLINE
);
2639 if (vty_ipv6_accesslist_name
)
2640 vty_out (vty
, " ipv6 access-class %s%s",
2641 vty_ipv6_accesslist_name
, VTY_NEWLINE
);
2644 if (vty_timeout_val
!= VTY_TIMEOUT_DEFAULT
)
2645 vty_out (vty
, " exec-timeout %ld %ld%s",
2646 vty_timeout_val
/ 60,
2647 vty_timeout_val
% 60, VTY_NEWLINE
);
2650 if (no_password_check
)
2651 vty_out (vty
, " no login%s", VTY_NEWLINE
);
2653 vty_out (vty
, "!%s", VTY_NEWLINE
);
2658 struct cmd_node vty_node
=
2661 "%s(config-line)# ",
2664 /* Reset all VTY status. */
2670 struct thread
*vty_serv_thread
;
2672 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2673 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2675 buffer_reset (vty
->obuf
);
2676 vty
->status
= VTY_CLOSE
;
2680 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2681 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2683 thread_cancel (vty_serv_thread
);
2684 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2688 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2690 if (vty_accesslist_name
)
2692 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2693 vty_accesslist_name
= NULL
;
2696 if (vty_ipv6_accesslist_name
)
2698 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2699 vty_ipv6_accesslist_name
= NULL
;
2703 /* for ospf6d easy temprary reload function */
2704 /* vty_reset + close accept socket */
2710 struct thread
*vty_serv_thread
;
2712 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2713 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2715 buffer_reset (vty
->obuf
);
2716 vty
->status
= VTY_CLOSE
;
2720 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2721 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2723 thread_cancel (vty_serv_thread
);
2724 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2728 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2730 if (vty_accesslist_name
)
2732 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2733 vty_accesslist_name
= NULL
;
2736 if (vty_ipv6_accesslist_name
)
2738 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2739 vty_ipv6_accesslist_name
= NULL
;
2748 cwd
= getcwd (NULL
, MAXPATHLEN
);
2750 vty_cwd
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + 1);
2751 strcpy (vty_cwd
, cwd
);
2761 vty_shell (struct vty
*vty
)
2763 return vty
->type
== VTY_SHELL
? 1 : 0;
2767 vty_shell_serv (struct vty
*vty
)
2769 return vty
->type
== VTY_SHELL_SERV
? 1 : 0;
2775 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2778 /* Install vty's own commands like `who' command. */
2782 /* For further configuration read, preserve current directory. */
2785 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2787 /* Initilize server thread vector. */
2788 Vvty_serv_thread
= vector_init (VECTOR_MIN_SIZE
);
2790 /* Install bgp top node. */
2791 install_node (&vty_node
, vty_config_write
);
2793 install_element (VIEW_NODE
, &config_who_cmd
);
2794 install_element (VIEW_NODE
, &show_history_cmd
);
2795 install_element (ENABLE_NODE
, &config_who_cmd
);
2796 install_element (CONFIG_NODE
, &line_vty_cmd
);
2797 install_element (CONFIG_NODE
, &service_advanced_vty_cmd
);
2798 install_element (CONFIG_NODE
, &no_service_advanced_vty_cmd
);
2799 install_element (CONFIG_NODE
, &show_history_cmd
);
2800 install_element (ENABLE_NODE
, &terminal_monitor_cmd
);
2801 install_element (ENABLE_NODE
, &terminal_no_monitor_cmd
);
2802 install_element (ENABLE_NODE
, &show_history_cmd
);
2804 install_default (VTY_NODE
);
2805 install_element (VTY_NODE
, &exec_timeout_min_cmd
);
2806 install_element (VTY_NODE
, &exec_timeout_sec_cmd
);
2807 install_element (VTY_NODE
, &no_exec_timeout_cmd
);
2808 install_element (VTY_NODE
, &vty_access_class_cmd
);
2809 install_element (VTY_NODE
, &no_vty_access_class_cmd
);
2810 install_element (VTY_NODE
, &vty_login_cmd
);
2811 install_element (VTY_NODE
, &no_vty_login_cmd
);
2813 install_element (VTY_NODE
, &vty_ipv6_access_class_cmd
);
2814 install_element (VTY_NODE
, &no_vty_ipv6_access_class_cmd
);
2815 #endif /* HAVE_IPV6 */