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
28 #include <lib/version.h>
30 #include "sockunion.h"
52 static void vty_event (enum event
, int, struct vty
*);
54 /* Extern host structure from command.c */
55 extern struct host host
;
57 /* Vector which store each vty structure. */
60 /* Vty timeout value. */
61 static unsigned long vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
63 /* Vty access-class command */
64 static char *vty_accesslist_name
= NULL
;
66 /* Vty access-calss for IPv6. */
67 static char *vty_ipv6_accesslist_name
= NULL
;
69 /* VTY server thread. */
70 vector Vvty_serv_thread
;
72 /* Current directory. */
76 static int vty_config
;
78 /* Login password check. */
79 static int no_password_check
= 0;
81 /* Integrated configuration file path */
82 char integrate_default
[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG
;
85 /* VTY standard output function. */
87 vty_out (struct vty
*vty
, const char *format
, ...)
95 va_start (args
, format
);
98 vprintf (format
, args
);
101 /* Try to write to initial buffer. */
102 len
= vsnprintf (buf
, sizeof buf
, format
, args
);
104 /* Initial buffer is not enough. */
105 if (len
< 0 || len
>= size
)
114 p
= XREALLOC (MTYPE_VTY_OUT_BUF
, p
, size
);
118 len
= vsnprintf (p
, size
, format
, args
);
120 if (len
> -1 && len
< size
)
125 /* When initial buffer is enough to store all output. */
129 /* Pointer p must point out buffer. */
130 if (vty_shell_serv (vty
))
131 write (vty
->fd
, (u_char
*) p
, len
);
133 buffer_write (vty
->obuf
, (u_char
*) p
, len
);
135 /* If p is not different with buf, it is allocated buffer. */
137 XFREE (MTYPE_VTY_OUT_BUF
, p
);
146 vty_log_out (struct vty
*vty
, const char *proto_str
, const char *format
,
152 snprintf (buf
, sizeof buf
, "%s: ", proto_str
);
153 write (vty
->fd
, buf
, strlen (proto_str
) + 2);
155 len
= vsnprintf (buf
, sizeof buf
, format
, va
);
158 write (vty
->fd
, (u_char
*)buf
, len
);
160 snprintf (buf
, sizeof buf
, "\r\n");
161 write (vty
->fd
, buf
, 2);
166 /* Output current time to the vty. */
168 vty_time_print (struct vty
*vty
, int cr
)
177 tm
= localtime (&clock
);
179 ret
= strftime (buf
, TIME_BUF
, "%Y/%m/%d %H:%M:%S", tm
);
182 zlog (NULL
, LOG_INFO
, "strftime error");
186 vty_out (vty
, "%s\n", buf
);
188 vty_out (vty
, "%s ", buf
);
193 /* Say hello to vty interface. */
195 vty_hello (struct vty
*vty
)
198 vty_out (vty
, host
.motd
);
201 /* Put out prompt and wait input from user. */
203 vty_prompt (struct vty
*vty
)
205 struct utsname names
;
208 if (vty
->type
== VTY_TERM
)
210 hostname
= host
.name
;
214 hostname
= names
.nodename
;
216 vty_out (vty
, cmd_prompt (vty
->node
), hostname
);
220 /* Send WILL TELOPT_ECHO to remote server. */
222 vty_will_echo (struct vty
*vty
)
224 char cmd
[] = { IAC
, WILL
, TELOPT_ECHO
, '\0' };
225 vty_out (vty
, "%s", cmd
);
228 /* Make suppress Go-Ahead telnet option. */
230 vty_will_suppress_go_ahead (struct vty
*vty
)
232 char cmd
[] = { IAC
, WILL
, TELOPT_SGA
, '\0' };
233 vty_out (vty
, "%s", cmd
);
236 /* Make don't use linemode over telnet. */
238 vty_dont_linemode (struct vty
*vty
)
240 char cmd
[] = { IAC
, DONT
, TELOPT_LINEMODE
, '\0' };
241 vty_out (vty
, "%s", cmd
);
244 /* Use window size. */
246 vty_do_window_size (struct vty
*vty
)
248 char cmd
[] = { IAC
, DO
, TELOPT_NAWS
, '\0' };
249 vty_out (vty
, "%s", cmd
);
252 #if 0 /* Currently not used. */
253 /* Make don't use lflow vty interface. */
255 vty_dont_lflow_ahead (struct vty
*vty
)
257 char cmd
[] = { IAC
, DONT
, TELOPT_LFLOW
, '\0' };
258 vty_out (vty
, "%s", cmd
);
262 /* Allocate new vty struct. */
266 struct vty
*new = XCALLOC (MTYPE_VTY
, sizeof (struct vty
));
268 new->obuf
= (struct buffer
*) buffer_new (100);
269 new->buf
= XCALLOC (MTYPE_VTY
, VTY_BUFSIZ
);
270 new->max
= VTY_BUFSIZ
;
271 new->sb_buffer
= NULL
;
276 /* Authentication of vty */
278 vty_auth (struct vty
*vty
, char *buf
)
281 enum node_type next_node
= 0;
283 char *crypt (const char *, const char *);
289 passwd
= host
.password_encrypt
;
291 passwd
= host
.password
;
293 next_node
= host
.enable
? VIEW_NODE
: ENABLE_NODE
;
295 next_node
= VIEW_NODE
;
297 case AUTH_ENABLE_NODE
:
299 passwd
= host
.enable_encrypt
;
301 passwd
= host
.enable
;
302 next_node
= ENABLE_NODE
;
309 fail
= strcmp (crypt(buf
, passwd
), passwd
);
311 fail
= strcmp (buf
, passwd
);
319 vty
->node
= next_node
; /* Success ! */
326 if (vty
->node
== AUTH_NODE
)
328 vty_out (vty
, "%% Bad passwords, too many failures!%s", VTY_NEWLINE
);
329 vty
->status
= VTY_CLOSE
;
333 /* AUTH_ENABLE_NODE */
335 vty_out (vty
, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE
);
336 vty
->node
= VIEW_NODE
;
342 /* Command execution over the vty interface. */
344 vty_command (struct vty
*vty
, char *buf
)
349 /* Split readline string up into the vector */
350 vline
= cmd_make_strvec (buf
);
355 ret
= cmd_execute_command (vline
, vty
, NULL
);
357 if (ret
!= CMD_SUCCESS
)
361 if (vty
->type
== VTY_FILE
)
362 vty_out (vty
, "Warning...%s", VTY_NEWLINE
);
364 case CMD_ERR_AMBIGUOUS
:
365 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
367 case CMD_ERR_NO_MATCH
:
368 vty_out (vty
, "%% Unknown command.%s", VTY_NEWLINE
);
370 case CMD_ERR_INCOMPLETE
:
371 vty_out (vty
, "%% Command incomplete.%s", VTY_NEWLINE
);
374 cmd_free_strvec (vline
);
379 char telnet_backward_char
= 0x08;
380 char telnet_space_char
= ' ';
382 /* Basic function to write buffer to vty. */
384 vty_write (struct vty
*vty
, char *buf
, size_t nbytes
)
386 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
389 /* Should we do buffering here ? And make vty_flush (vty) ? */
390 buffer_write (vty
->obuf
, (u_char
*)buf
, nbytes
);
393 /* Ensure length of input buffer. Is buffer is short, double it. */
395 vty_ensure (struct vty
*vty
, int length
)
397 if (vty
->max
<= length
)
400 vty
->buf
= XREALLOC (MTYPE_VTY
, vty
->buf
, vty
->max
);
404 /* Basic function to insert character into vty. */
406 vty_self_insert (struct vty
*vty
, char c
)
411 vty_ensure (vty
, vty
->length
+ 1);
412 length
= vty
->length
- vty
->cp
;
413 memmove (&vty
->buf
[vty
->cp
+ 1], &vty
->buf
[vty
->cp
], length
);
414 vty
->buf
[vty
->cp
] = c
;
416 vty_write (vty
, &vty
->buf
[vty
->cp
], length
+ 1);
417 for (i
= 0; i
< length
; i
++)
418 vty_write (vty
, &telnet_backward_char
, 1);
424 /* Self insert character 'c' in overwrite mode. */
426 vty_self_insert_overwrite (struct vty
*vty
, char c
)
428 vty_ensure (vty
, vty
->length
+ 1);
429 vty
->buf
[vty
->cp
++] = c
;
431 if (vty
->cp
> vty
->length
)
434 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
437 vty_write (vty
, &c
, 1);
440 /* Insert a word into vty interface with overwrite mode. */
442 vty_insert_word_overwrite (struct vty
*vty
, char *str
)
444 int len
= strlen (str
);
445 vty_write (vty
, str
, len
);
446 strcpy (&vty
->buf
[vty
->cp
], str
);
448 vty
->length
= vty
->cp
;
451 /* Forward character. */
453 vty_forward_char (struct vty
*vty
)
455 if (vty
->cp
< vty
->length
)
457 vty_write (vty
, &vty
->buf
[vty
->cp
], 1);
462 /* Backward character. */
464 vty_backward_char (struct vty
*vty
)
469 vty_write (vty
, &telnet_backward_char
, 1);
473 /* Move to the beginning of the line. */
475 vty_beginning_of_line (struct vty
*vty
)
478 vty_backward_char (vty
);
481 /* Move to the end of the line. */
483 vty_end_of_line (struct vty
*vty
)
485 while (vty
->cp
< vty
->length
)
486 vty_forward_char (vty
);
489 static void vty_kill_line_from_beginning (struct vty
*);
490 static void vty_redraw_line (struct vty
*);
492 /* Print command line history. This function is called from
493 vty_next_line and vty_previous_line. */
495 vty_history_print (struct vty
*vty
)
499 vty_kill_line_from_beginning (vty
);
501 /* Get previous line from history buffer */
502 length
= strlen (vty
->hist
[vty
->hp
]);
503 memcpy (vty
->buf
, vty
->hist
[vty
->hp
], length
);
504 vty
->cp
= vty
->length
= length
;
506 /* Redraw current line */
507 vty_redraw_line (vty
);
510 /* Show next command line history. */
512 vty_next_line (struct vty
*vty
)
516 if (vty
->hp
== vty
->hindex
)
519 /* Try is there history exist or not. */
521 if (try_index
== (VTY_MAXHIST
- 1))
526 /* If there is not history return. */
527 if (vty
->hist
[try_index
] == NULL
)
532 vty_history_print (vty
);
535 /* Show previous command line history. */
537 vty_previous_line (struct vty
*vty
)
543 try_index
= VTY_MAXHIST
- 1;
547 if (vty
->hist
[try_index
] == NULL
)
552 vty_history_print (vty
);
555 /* This function redraw all of the command line character. */
557 vty_redraw_line (struct vty
*vty
)
559 vty_write (vty
, vty
->buf
, vty
->length
);
560 vty
->cp
= vty
->length
;
565 vty_forward_word (struct vty
*vty
)
567 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
568 vty_forward_char (vty
);
570 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
571 vty_forward_char (vty
);
574 /* Backward word without skipping training space. */
576 vty_backward_pure_word (struct vty
*vty
)
578 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
579 vty_backward_char (vty
);
584 vty_backward_word (struct vty
*vty
)
586 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
587 vty_backward_char (vty
);
589 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
590 vty_backward_char (vty
);
593 /* When '^D' is typed at the beginning of the line we move to the down
596 vty_down_level (struct vty
*vty
)
598 vty_out (vty
, "%s", VTY_NEWLINE
);
599 config_exit (NULL
, vty
, 0, NULL
);
604 /* When '^Z' is received from vty, move down to the enable mode. */
606 vty_end_config (struct vty
*vty
)
608 vty_out (vty
, "%s", VTY_NEWLINE
);
631 case KEYCHAIN_KEY_NODE
:
634 vty_config_unlock (vty
);
635 vty
->node
= ENABLE_NODE
;
638 /* Unknown node, we have to ignore it. */
646 /* Delete a charcter at the current point. */
648 vty_delete_char (struct vty
*vty
)
653 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
656 if (vty
->length
== 0)
658 vty_down_level (vty
);
662 if (vty
->cp
== vty
->length
)
663 return; /* completion need here? */
665 size
= vty
->length
- vty
->cp
;
668 memmove (&vty
->buf
[vty
->cp
], &vty
->buf
[vty
->cp
+ 1], size
- 1);
669 vty
->buf
[vty
->length
] = '\0';
671 vty_write (vty
, &vty
->buf
[vty
->cp
], size
- 1);
672 vty_write (vty
, &telnet_space_char
, 1);
674 for (i
= 0; i
< size
; i
++)
675 vty_write (vty
, &telnet_backward_char
, 1);
678 /* Delete a character before the point. */
680 vty_delete_backward_char (struct vty
*vty
)
685 vty_backward_char (vty
);
686 vty_delete_char (vty
);
689 /* Kill rest of line from current point. */
691 vty_kill_line (struct vty
*vty
)
696 size
= vty
->length
- vty
->cp
;
701 for (i
= 0; i
< size
; i
++)
702 vty_write (vty
, &telnet_space_char
, 1);
703 for (i
= 0; i
< size
; i
++)
704 vty_write (vty
, &telnet_backward_char
, 1);
706 memset (&vty
->buf
[vty
->cp
], 0, size
);
707 vty
->length
= vty
->cp
;
710 /* Kill line from the beginning. */
712 vty_kill_line_from_beginning (struct vty
*vty
)
714 vty_beginning_of_line (vty
);
718 /* Delete a word before the point. */
720 vty_forward_kill_word (struct vty
*vty
)
722 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
723 vty_delete_char (vty
);
724 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
725 vty_delete_char (vty
);
728 /* Delete a word before the point. */
730 vty_backward_kill_word (struct vty
*vty
)
732 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
733 vty_delete_backward_char (vty
);
734 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
735 vty_delete_backward_char (vty
);
738 /* Transpose chars before or at the point. */
740 vty_transpose_chars (struct vty
*vty
)
744 /* If length is short or point is near by the beginning of line then
746 if (vty
->length
< 2 || vty
->cp
< 1)
749 /* In case of point is located at the end of the line. */
750 if (vty
->cp
== vty
->length
)
752 c1
= vty
->buf
[vty
->cp
- 1];
753 c2
= vty
->buf
[vty
->cp
- 2];
755 vty_backward_char (vty
);
756 vty_backward_char (vty
);
757 vty_self_insert_overwrite (vty
, c1
);
758 vty_self_insert_overwrite (vty
, c2
);
762 c1
= vty
->buf
[vty
->cp
];
763 c2
= vty
->buf
[vty
->cp
- 1];
765 vty_backward_char (vty
);
766 vty_self_insert_overwrite (vty
, c1
);
767 vty_self_insert_overwrite (vty
, c2
);
771 /* Do completion at vty interface. */
773 vty_complete_command (struct vty
*vty
)
777 char **matched
= NULL
;
780 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
783 vline
= cmd_make_strvec (vty
->buf
);
787 /* In case of 'help \t'. */
788 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
789 vector_set (vline
, '\0');
791 matched
= cmd_complete_command (vline
, vty
, &ret
);
793 cmd_free_strvec (vline
);
795 vty_out (vty
, "%s", VTY_NEWLINE
);
798 case CMD_ERR_AMBIGUOUS
:
799 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
801 vty_redraw_line (vty
);
803 case CMD_ERR_NO_MATCH
:
804 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
806 vty_redraw_line (vty
);
808 case CMD_COMPLETE_FULL_MATCH
:
810 vty_redraw_line (vty
);
811 vty_backward_pure_word (vty
);
812 vty_insert_word_overwrite (vty
, matched
[0]);
813 vty_self_insert (vty
, ' ');
814 XFREE (MTYPE_TMP
, matched
[0]);
816 case CMD_COMPLETE_MATCH
:
818 vty_redraw_line (vty
);
819 vty_backward_pure_word (vty
);
820 vty_insert_word_overwrite (vty
, matched
[0]);
821 XFREE (MTYPE_TMP
, matched
[0]);
822 vector_only_index_free (matched
);
825 case CMD_COMPLETE_LIST_MATCH
:
826 for (i
= 0; matched
[i
] != NULL
; i
++)
828 if (i
!= 0 && ((i
% 6) == 0))
829 vty_out (vty
, "%s", VTY_NEWLINE
);
830 vty_out (vty
, "%-10s ", matched
[i
]);
831 XFREE (MTYPE_TMP
, matched
[i
]);
833 vty_out (vty
, "%s", VTY_NEWLINE
);
836 vty_redraw_line (vty
);
838 case CMD_ERR_NOTHING_TODO
:
840 vty_redraw_line (vty
);
846 vector_only_index_free (matched
);
850 vty_describe_fold (struct vty
*vty
, int cmd_width
,
851 int desc_width
, struct desc
*desc
)
856 cmd
= desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
;
860 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, desc
->str
, VTY_NEWLINE
);
864 buf
= XCALLOC (MTYPE_TMP
, strlen (desc
->str
) + 1);
866 for (p
= desc
->str
; strlen (p
) > desc_width
; p
+= pos
+ 1)
868 for (pos
= desc_width
; pos
> 0; pos
--)
869 if (*(p
+ pos
) == ' ')
875 strncpy (buf
, p
, pos
);
877 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, buf
, VTY_NEWLINE
);
882 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, p
, VTY_NEWLINE
);
884 XFREE (MTYPE_TMP
, buf
);
887 /* Describe matched command function. */
889 vty_describe_command (struct vty
*vty
)
894 int i
, width
, desc_width
;
895 struct desc
*desc
, *desc_cr
= NULL
;
897 vline
= cmd_make_strvec (vty
->buf
);
899 /* In case of '> ?'. */
902 vline
= vector_init (1);
903 vector_set (vline
, '\0');
906 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
907 vector_set (vline
, '\0');
909 describe
= cmd_describe_command (vline
, vty
, &ret
);
911 vty_out (vty
, "%s", VTY_NEWLINE
);
913 /* Ambiguous error. */
916 case CMD_ERR_AMBIGUOUS
:
917 cmd_free_strvec (vline
);
918 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
920 vty_redraw_line (vty
);
923 case CMD_ERR_NO_MATCH
:
924 cmd_free_strvec (vline
);
925 vty_out (vty
, "%% There is no matched command.%s", VTY_NEWLINE
);
927 vty_redraw_line (vty
);
932 /* Get width of command string. */
934 for (i
= 0; i
< vector_max (describe
); i
++)
935 if ((desc
= vector_slot (describe
, i
)) != NULL
)
939 if (desc
->cmd
[0] == '\0')
942 len
= strlen (desc
->cmd
);
943 if (desc
->cmd
[0] == '.')
950 /* Get width of description string. */
951 desc_width
= vty
->width
- (width
+ 6);
953 /* Print out description. */
954 for (i
= 0; i
< vector_max (describe
); i
++)
955 if ((desc
= vector_slot (describe
, i
)) != NULL
)
957 if (desc
->cmd
[0] == '\0')
960 if (strcmp (desc
->cmd
, "<cr>") == 0)
967 vty_out (vty
, " %-s%s",
968 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
970 else if (desc_width
>= strlen (desc
->str
))
971 vty_out (vty
, " %-*s %s%s", width
,
972 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
973 desc
->str
, VTY_NEWLINE
);
975 vty_describe_fold (vty
, width
, desc_width
, desc
);
978 vty_out (vty
, " %-*s %s%s", width
979 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
980 desc
->str
? desc
->str
: "", VTY_NEWLINE
);
984 if ((desc
= desc_cr
))
987 vty_out (vty
, " %-s%s",
988 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
990 else if (desc_width
>= strlen (desc
->str
))
991 vty_out (vty
, " %-*s %s%s", width
,
992 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
993 desc
->str
, VTY_NEWLINE
);
995 vty_describe_fold (vty
, width
, desc_width
, desc
);
998 cmd_free_strvec (vline
);
999 vector_free (describe
);
1002 vty_redraw_line (vty
);
1006 vty_clear_buf (struct vty
*vty
)
1008 memset (vty
->buf
, 0, vty
->max
);
1011 /* ^C stop current input and do not add command line to the history. */
1013 vty_stop_input (struct vty
*vty
)
1015 vty
->cp
= vty
->length
= 0;
1016 vty_clear_buf (vty
);
1017 vty_out (vty
, "%s", VTY_NEWLINE
);
1023 /* Nothing to do. */
1026 case INTERFACE_NODE
:
1036 case KEYCHAIN_KEY_NODE
:
1039 vty_config_unlock (vty
);
1040 vty
->node
= ENABLE_NODE
;
1043 /* Unknown node, we have to ignore it. */
1048 /* Set history pointer to the latest one. */
1049 vty
->hp
= vty
->hindex
;
1052 /* Add current command line to the history buffer. */
1054 vty_hist_add (struct vty
*vty
)
1058 if (vty
->length
== 0)
1061 index
= vty
->hindex
? vty
->hindex
- 1 : VTY_MAXHIST
- 1;
1063 /* Ignore the same string as previous one. */
1064 if (vty
->hist
[index
])
1065 if (strcmp (vty
->buf
, vty
->hist
[index
]) == 0)
1067 vty
->hp
= vty
->hindex
;
1071 /* Insert history entry. */
1072 if (vty
->hist
[vty
->hindex
])
1073 XFREE (MTYPE_VTY_HIST
, vty
->hist
[vty
->hindex
]);
1074 vty
->hist
[vty
->hindex
] = XSTRDUP (MTYPE_VTY_HIST
, vty
->buf
);
1076 /* History index rotation. */
1078 if (vty
->hindex
== VTY_MAXHIST
)
1081 vty
->hp
= vty
->hindex
;
1084 /* #define TELNET_OPTION_DEBUG */
1086 /* Get telnet window size. */
1088 vty_telnet_option (struct vty
*vty
, unsigned char *buf
, int nbytes
)
1090 #ifdef TELNET_OPTION_DEBUG
1093 for (i
= 0; i
< nbytes
; i
++)
1098 vty_out (vty
, "IAC ");
1101 vty_out (vty
, "WILL ");
1104 vty_out (vty
, "WONT ");
1107 vty_out (vty
, "DO ");
1110 vty_out (vty
, "DONT ");
1113 vty_out (vty
, "SB ");
1116 vty_out (vty
, "SE ");
1119 vty_out (vty
, "TELOPT_ECHO %s", VTY_NEWLINE
);
1122 vty_out (vty
, "TELOPT_SGA %s", VTY_NEWLINE
);
1125 vty_out (vty
, "TELOPT_NAWS %s", VTY_NEWLINE
);
1128 vty_out (vty
, "%x ", buf
[i
]);
1132 vty_out (vty
, "%s", VTY_NEWLINE
);
1134 #endif /* TELNET_OPTION_DEBUG */
1139 buffer_reset(vty
->sb_buffer
);
1140 vty
->iac_sb_in_progress
= 1;
1148 if (!vty
->iac_sb_in_progress
)
1151 buffer
= (char *)vty
->sb_buffer
->head
->data
;
1152 length
= vty
->sb_buffer
->length
;
1157 if (buffer
[0] == '\0')
1159 vty
->iac_sb_in_progress
= 0;
1167 vty
->width
= buffer
[2];
1168 vty
->height
= vty
->lines
>= 0 ? vty
->lines
: buffer
[4];
1171 vty
->iac_sb_in_progress
= 0;
1181 /* Execute current command line. */
1183 vty_execute (struct vty
*vty
)
1192 case AUTH_ENABLE_NODE
:
1193 vty_auth (vty
, vty
->buf
);
1196 ret
= vty_command (vty
, vty
->buf
);
1197 if (vty
->type
== VTY_TERM
)
1202 /* Clear command line buffer. */
1203 vty
->cp
= vty
->length
= 0;
1204 vty_clear_buf (vty
);
1206 if (vty
->status
!= VTY_CLOSE
1207 && vty
->status
!= VTY_START
1208 && vty
->status
!= VTY_CONTINUE
)
1214 #define CONTROL(X) ((X) - '@')
1215 #define VTY_NORMAL 0
1216 #define VTY_PRE_ESCAPE 1
1217 #define VTY_ESCAPE 2
1219 /* Escape character command map. */
1221 vty_escape_map (unsigned char c
, struct vty
*vty
)
1226 vty_previous_line (vty
);
1229 vty_next_line (vty
);
1232 vty_forward_char (vty
);
1235 vty_backward_char (vty
);
1241 /* Go back to normal mode. */
1242 vty
->escape
= VTY_NORMAL
;
1245 /* Quit print out to the buffer. */
1247 vty_buffer_reset (struct vty
*vty
)
1249 buffer_reset (vty
->obuf
);
1251 vty_redraw_line (vty
);
1254 /* Read data via vty socket. */
1256 vty_read (struct thread
*thread
)
1260 unsigned char buf
[VTY_READ_BUFSIZ
];
1262 int vty_sock
= THREAD_FD (thread
);
1263 struct vty
*vty
= THREAD_ARG (thread
);
1266 /* Read raw data from socket */
1267 nbytes
= read (vty
->fd
, buf
, VTY_READ_BUFSIZ
);
1269 vty
->status
= VTY_CLOSE
;
1271 for (i
= 0; i
< nbytes
; i
++)
1286 if (vty
->iac_sb_in_progress
&& !vty
->iac
)
1288 buffer_putc(vty
->sb_buffer
, buf
[i
]);
1294 /* In case of telnet command */
1296 ret
= vty_telnet_option (vty
, buf
+ i
, nbytes
- i
);
1303 if (vty
->status
== VTY_MORE
)
1310 if (vty
->output_func
)
1311 (*vty
->output_func
) (vty
, 1);
1312 vty_buffer_reset (vty
);
1314 #if 0 /* More line does not work for "show ip bgp". */
1317 vty
->status
= VTY_MORELINE
;
1321 if (vty
->output_func
)
1322 (*vty
->output_func
) (vty
, 0);
1328 /* Escape character. */
1329 if (vty
->escape
== VTY_ESCAPE
)
1331 vty_escape_map (buf
[i
], vty
);
1335 /* Pre-escape status. */
1336 if (vty
->escape
== VTY_PRE_ESCAPE
)
1341 vty
->escape
= VTY_ESCAPE
;
1344 vty_backward_word (vty
);
1345 vty
->escape
= VTY_NORMAL
;
1348 vty_forward_word (vty
);
1349 vty
->escape
= VTY_NORMAL
;
1352 vty_forward_kill_word (vty
);
1353 vty
->escape
= VTY_NORMAL
;
1357 vty_backward_kill_word (vty
);
1358 vty
->escape
= VTY_NORMAL
;
1361 vty
->escape
= VTY_NORMAL
;
1370 vty_beginning_of_line (vty
);
1373 vty_backward_char (vty
);
1376 vty_stop_input (vty
);
1379 vty_delete_char (vty
);
1382 vty_end_of_line (vty
);
1385 vty_forward_char (vty
);
1389 vty_delete_backward_char (vty
);
1392 vty_kill_line (vty
);
1395 vty_next_line (vty
);
1398 vty_previous_line (vty
);
1401 vty_transpose_chars (vty
);
1404 vty_kill_line_from_beginning (vty
);
1407 vty_backward_kill_word (vty
);
1410 vty_end_config (vty
);
1414 vty_out (vty
, "%s", VTY_NEWLINE
);
1418 vty_complete_command (vty
);
1421 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
1422 vty_self_insert (vty
, buf
[i
]);
1424 vty_describe_command (vty
);
1427 if (i
+ 1 < nbytes
&& buf
[i
+ 1] == '[')
1429 vty
->escape
= VTY_ESCAPE
;
1433 vty
->escape
= VTY_PRE_ESCAPE
;
1436 if (buf
[i
] > 31 && buf
[i
] < 127)
1437 vty_self_insert (vty
, buf
[i
]);
1443 if (vty
->status
== VTY_CLOSE
)
1447 vty_event (VTY_WRITE
, vty_sock
, vty
);
1448 vty_event (VTY_READ
, vty_sock
, vty
);
1453 /* Flush buffer to the vty. */
1455 vty_flush (struct thread
*thread
)
1459 int vty_sock
= THREAD_FD (thread
);
1460 struct vty
*vty
= THREAD_ARG (thread
);
1461 vty
->t_write
= NULL
;
1463 /* Tempolary disable read thread. */
1464 if (vty
->lines
== 0)
1467 thread_cancel (vty
->t_read
);
1471 /* Function execution continue. */
1472 if (vty
->status
== VTY_START
|| vty
->status
== VTY_CONTINUE
)
1474 if (vty
->status
== VTY_CONTINUE
)
1479 if (vty
->output_func
== NULL
)
1484 if (vty
->lines
== 0)
1490 buffer_flush_vty_all (vty
->obuf
, vty
->fd
, erase
, dont_more
);
1492 if (vty
->status
== VTY_CLOSE
)
1498 if (vty
->output_func
== NULL
)
1500 vty
->status
= VTY_NORMAL
;
1502 vty_event (VTY_WRITE
, vty_sock
, vty
);
1505 vty
->status
= VTY_MORE
;
1507 if (vty
->lines
== 0)
1509 if (vty
->output_func
== NULL
)
1510 vty_event (VTY_READ
, vty_sock
, vty
);
1513 if (vty
->output_func
)
1514 (*vty
->output_func
) (vty
, 0);
1515 vty_event (VTY_WRITE
, vty_sock
, vty
);
1521 if (vty
->status
== VTY_MORE
|| vty
->status
== VTY_MORELINE
)
1526 if (vty
->lines
== 0)
1527 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 25, 0, 1);
1528 else if (vty
->status
== VTY_MORELINE
)
1529 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 1, erase
, 0);
1531 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
,
1532 vty
->lines
>= 0 ? vty
->lines
: vty
->height
,
1535 if (buffer_empty (vty
->obuf
))
1537 if (vty
->status
== VTY_CLOSE
)
1541 vty
->status
= VTY_NORMAL
;
1543 if (vty
->lines
== 0)
1544 vty_event (VTY_READ
, vty_sock
, vty
);
1549 vty
->status
= VTY_MORE
;
1551 if (vty
->lines
== 0)
1552 vty_event (VTY_WRITE
, vty_sock
, vty
);
1559 /* Create new vty structure. */
1561 vty_create (int vty_sock
, union sockunion
*su
)
1565 /* Allocate new vty structure and set up default values. */
1568 vty
->type
= VTY_TERM
;
1569 vty
->address
= sockunion_su2str (su
);
1570 if (no_password_check
)
1573 vty
->node
= ENABLE_NODE
;
1575 vty
->node
= VIEW_NODE
;
1578 vty
->node
= AUTH_NODE
;
1581 vty_clear_buf (vty
);
1583 memset (vty
->hist
, 0, sizeof (vty
->hist
));
1586 vector_set_index (vtyvec
, vty_sock
, vty
);
1587 vty
->status
= VTY_NORMAL
;
1588 vty
->v_timeout
= vty_timeout_val
;
1589 if (host
.lines
>= 0)
1590 vty
->lines
= host
.lines
;
1594 vty
->iac_sb_in_progress
= 0;
1595 vty
->sb_buffer
= buffer_new (1024);
1597 if (! no_password_check
)
1599 /* Vty is not available if password isn't set. */
1600 if (host
.password
== NULL
&& host
.password_encrypt
== NULL
)
1602 vty_out (vty
, "Vty password is not set.%s", VTY_NEWLINE
);
1603 vty
->status
= VTY_CLOSE
;
1609 /* Say hello to the world. */
1611 if (! no_password_check
)
1612 vty_out (vty
, "%sUser Access Verification%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1614 /* Setting up terminal. */
1615 vty_will_echo (vty
);
1616 vty_will_suppress_go_ahead (vty
);
1618 vty_dont_linemode (vty
);
1619 vty_do_window_size (vty
);
1620 /* vty_dont_lflow_ahead (vty); */
1624 /* Add read/write thread. */
1625 vty_event (VTY_WRITE
, vty_sock
, vty
);
1626 vty_event (VTY_READ
, vty_sock
, vty
);
1631 /* Accept connection from the network. */
1633 vty_accept (struct thread
*thread
)
1641 struct prefix
*p
= NULL
;
1642 struct access_list
*acl
= NULL
;
1644 accept_sock
= THREAD_FD (thread
);
1646 /* We continue hearing vty socket. */
1647 vty_event (VTY_SERV
, accept_sock
, NULL
);
1649 memset (&su
, 0, sizeof (union sockunion
));
1651 /* We can handle IPv4 or IPv6 socket. */
1652 vty_sock
= sockunion_accept (accept_sock
, &su
);
1655 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1659 p
= sockunion2hostprefix (&su
);
1661 /* VTY's accesslist apply. */
1662 if (p
->family
== AF_INET
&& vty_accesslist_name
)
1664 if ((acl
= access_list_lookup (AFI_IP
, vty_accesslist_name
)) &&
1665 (access_list_apply (acl
, p
) == FILTER_DENY
))
1668 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1669 (buf
= sockunion_su2str (&su
)));
1673 /* continue accepting connections */
1674 vty_event (VTY_SERV
, accept_sock
, NULL
);
1683 /* VTY's ipv6 accesslist apply. */
1684 if (p
->family
== AF_INET6
&& vty_ipv6_accesslist_name
)
1686 if ((acl
= access_list_lookup (AFI_IP6
, vty_ipv6_accesslist_name
)) &&
1687 (access_list_apply (acl
, p
) == FILTER_DENY
))
1690 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1691 (buf
= sockunion_su2str (&su
)));
1695 /* continue accepting connections */
1696 vty_event (VTY_SERV
, accept_sock
, NULL
);
1703 #endif /* HAVE_IPV6 */
1708 ret
= setsockopt (vty_sock
, IPPROTO_TCP
, TCP_NODELAY
,
1709 (char *) &on
, sizeof (on
));
1711 zlog (NULL
, LOG_INFO
, "can't set sockopt to vty_sock : %s",
1714 vty
= vty_create (vty_sock
, &su
);
1719 #if defined(HAVE_IPV6) && !defined(NRL)
1721 vty_serv_sock_addrinfo (const char *hostname
, unsigned short port
)
1724 struct addrinfo req
;
1725 struct addrinfo
*ainfo
;
1726 struct addrinfo
*ainfo_save
;
1728 char port_str
[BUFSIZ
];
1730 memset (&req
, 0, sizeof (struct addrinfo
));
1731 req
.ai_flags
= AI_PASSIVE
;
1732 req
.ai_family
= AF_UNSPEC
;
1733 req
.ai_socktype
= SOCK_STREAM
;
1734 sprintf (port_str
, "%d", port
);
1735 port_str
[sizeof (port_str
) - 1] = '\0';
1737 ret
= getaddrinfo (hostname
, port_str
, &req
, &ainfo
);
1741 fprintf (stderr
, "getaddrinfo failed: %s\n", gai_strerror (ret
));
1749 if (ainfo
->ai_family
!= AF_INET
1751 && ainfo
->ai_family
!= AF_INET6
1752 #endif /* HAVE_IPV6 */
1756 sock
= socket (ainfo
->ai_family
, ainfo
->ai_socktype
, ainfo
->ai_protocol
);
1760 sockopt_reuseaddr (sock
);
1761 sockopt_reuseport (sock
);
1763 ret
= bind (sock
, ainfo
->ai_addr
, ainfo
->ai_addrlen
);
1766 close (sock
); /* Avoid sd leak. */
1770 ret
= listen (sock
, 3);
1773 close (sock
); /* Avoid sd leak. */
1777 vty_event (VTY_SERV
, sock
, NULL
);
1779 while ((ainfo
= ainfo
->ai_next
) != NULL
);
1781 freeaddrinfo (ainfo_save
);
1783 #endif /* HAVE_IPV6 && ! NRL */
1785 /* Make vty server socket. */
1787 vty_serv_sock_family (const char* addr
, unsigned short port
, int family
)
1794 memset (&su
, 0, sizeof (union sockunion
));
1795 su
.sa
.sa_family
= family
;
1800 naddr
=&su
.sin
.sin_addr
;
1803 naddr
=&su
.sin6
.sin6_addr
;
1808 switch(inet_pton(family
,addr
,naddr
))
1811 zlog_err("bad address %s",addr
);
1815 zlog_err("error translating address %s: %s",addr
,strerror(errno
));
1819 /* Make new socket. */
1820 accept_sock
= sockunion_stream_socket (&su
);
1821 if (accept_sock
< 0)
1824 /* This is server, so reuse address. */
1825 sockopt_reuseaddr (accept_sock
);
1826 sockopt_reuseport (accept_sock
);
1828 /* Bind socket to universal address and given port. */
1829 ret
= sockunion_bind (accept_sock
, &su
, port
, naddr
);
1832 zlog_warn("can't bind socket");
1833 close (accept_sock
); /* Avoid sd leak. */
1837 /* Listen socket under queue 3. */
1838 ret
= listen (accept_sock
, 3);
1841 zlog (NULL
, LOG_WARNING
, "can't listen socket");
1842 close (accept_sock
); /* Avoid sd leak. */
1846 /* Add vty server event. */
1847 vty_event (VTY_SERV
, accept_sock
, NULL
);
1851 /* For sockaddr_un. */
1854 /* VTY shell UNIX domain socket. */
1856 vty_serv_un (char *path
)
1860 struct sockaddr_un serv
;
1862 struct zprivs_ids_t ids
;
1864 /* First of all, unlink existing socket */
1868 old_mask
= umask (0007);
1870 /* Make UNIX domain socket. */
1871 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
1878 /* Make server socket. */
1879 memset (&serv
, 0, sizeof (struct sockaddr_un
));
1880 serv
.sun_family
= AF_UNIX
;
1881 strncpy (serv
.sun_path
, path
, strlen (path
));
1883 len
= serv
.sun_len
= SUN_LEN(&serv
);
1885 len
= sizeof (serv
.sun_family
) + strlen (serv
.sun_path
);
1886 #endif /* HAVE_SUN_LEN */
1888 ret
= bind (sock
, (struct sockaddr
*) &serv
, len
);
1892 close (sock
); /* Avoid sd leak. */
1896 ret
= listen (sock
, 5);
1900 close (sock
); /* Avoid sd leak. */
1906 zprivs_get_ids(&ids
);
1908 if (ids
.gid_vty
> 0)
1910 /* set group of socket */
1911 if ( chown (path
, -1, ids
.gid_vty
) )
1913 zlog_err ("vty_serv_un: could chown socket, %s",
1918 vty_event (VTYSH_SERV
, sock
, NULL
);
1921 /* #define VTYSH_DEBUG 1 */
1924 vtysh_accept (struct thread
*thread
)
1929 struct sockaddr_un client
;
1932 accept_sock
= THREAD_FD (thread
);
1934 vty_event (VTYSH_SERV
, accept_sock
, NULL
);
1936 memset (&client
, 0, sizeof (struct sockaddr_un
));
1937 client_len
= sizeof (struct sockaddr_un
);
1939 sock
= accept (accept_sock
, (struct sockaddr
*) &client
, &client_len
);
1943 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1948 printf ("VTY shell accept\n");
1949 #endif /* VTYSH_DEBUG */
1953 vty
->type
= VTY_SHELL_SERV
;
1954 vty
->node
= VIEW_NODE
;
1956 vty_event (VTYSH_READ
, sock
, vty
);
1962 vtysh_read (struct thread
*thread
)
1968 unsigned char buf
[VTY_READ_BUFSIZ
];
1969 u_char header
[4] = {0, 0, 0, 0};
1971 sock
= THREAD_FD (thread
);
1972 vty
= THREAD_ARG (thread
);
1975 nbytes
= read (sock
, buf
, VTY_READ_BUFSIZ
);
1980 printf ("close vtysh\n");
1981 #endif /* VTYSH_DEBUG */
1986 printf ("line: %s\n", buf
);
1987 #endif /* VTYSH_DEBUG */
1989 vty_ensure (vty
, nbytes
);
1990 memcpy (vty
->buf
, buf
, nbytes
);
1992 /* Pass this line to parser. */
1993 ret
= vty_execute (vty
);
1995 vty_clear_buf (vty
);
1997 /* Return result. */
1999 printf ("result: %d\n", ret
);
2000 printf ("vtysh node: %d\n", vty
->node
);
2001 #endif /* VTYSH_DEBUG */
2004 write (vty
->fd
, header
, 4);
2006 vty_event (VTYSH_READ
, sock
, vty
);
2012 /* Determine address family to bind. */
2014 vty_serv_sock (const char *addr
, unsigned short port
, char *path
)
2016 /* If port is set to 0, do not listen on TCP/IP at all! */
2022 vty_serv_sock_family (addr
, port
, AF_INET
);
2023 vty_serv_sock_family (addr
, port
, AF_INET6
);
2025 vty_serv_sock_addrinfo (addr
, port
);
2027 #else /* ! HAVE_IPV6 */
2028 vty_serv_sock_family (addr
,port
, AF_INET
);
2029 #endif /* HAVE_IPV6 */
2037 /* Close vty interface. */
2039 vty_close (struct vty
*vty
)
2043 /* Cancel threads.*/
2045 thread_cancel (vty
->t_read
);
2047 thread_cancel (vty
->t_write
);
2049 thread_cancel (vty
->t_timeout
);
2051 thread_cancel (vty
->t_output
);
2054 if (! buffer_empty (vty
->obuf
))
2055 buffer_flush_all (vty
->obuf
, vty
->fd
);
2057 /* Free input buffer. */
2058 buffer_free (vty
->obuf
);
2060 /* Free SB buffer. */
2062 buffer_free (vty
->sb_buffer
);
2064 /* Free command history. */
2065 for (i
= 0; i
< VTY_MAXHIST
; i
++)
2067 XFREE (MTYPE_VTY_HIST
, vty
->hist
[i
]);
2070 vector_unset (vtyvec
, vty
->fd
);
2077 XFREE (0, vty
->address
);
2079 XFREE (MTYPE_VTY
, vty
->buf
);
2081 /* Check configure. */
2082 vty_config_unlock (vty
);
2085 XFREE (MTYPE_VTY
, vty
);
2088 /* When time out occur output message then close connection. */
2090 vty_timeout (struct thread
*thread
)
2094 vty
= THREAD_ARG (thread
);
2095 vty
->t_timeout
= NULL
;
2099 buffer_reset (vty
->obuf
);
2100 vty_out (vty
, "%sVty connection is timed out.%s", VTY_NEWLINE
, VTY_NEWLINE
);
2102 /* Close connection. */
2103 vty
->status
= VTY_CLOSE
;
2109 /* Read up configuration file from file_name. */
2111 vty_read_file (FILE *confp
)
2117 vty
->fd
= 0; /* stdout */
2118 vty
->type
= VTY_TERM
;
2119 vty
->node
= CONFIG_NODE
;
2121 /* Execute configuration file */
2122 ret
= config_from_file (vty
, confp
);
2124 if ( !((ret
== CMD_SUCCESS
) || (ret
== CMD_ERR_NOTHING_TODO
)) )
2128 case CMD_ERR_AMBIGUOUS
:
2129 fprintf (stderr
, "Ambiguous command.\n");
2131 case CMD_ERR_NO_MATCH
:
2132 fprintf (stderr
, "There is no such command.\n");
2135 fprintf (stderr
, "Error occured during reading below line.\n%s\n",
2145 vty_use_backup_config (char *fullpath
)
2147 char *fullpath_sav
, *fullpath_tmp
;
2154 fullpath_sav
= malloc (strlen (fullpath
) + strlen (CONF_BACKUP_EXT
) + 1);
2155 strcpy (fullpath_sav
, fullpath
);
2156 strcat (fullpath_sav
, CONF_BACKUP_EXT
);
2157 if (stat (fullpath_sav
, &buf
) == -1)
2159 free (fullpath_sav
);
2163 fullpath_tmp
= malloc (strlen (fullpath
) + 8);
2164 sprintf (fullpath_tmp
, "%s.XXXXXX", fullpath
);
2166 /* Open file to configuration write. */
2167 tmp
= mkstemp (fullpath_tmp
);
2170 free (fullpath_sav
);
2171 free (fullpath_tmp
);
2175 sav
= open (fullpath_sav
, O_RDONLY
);
2178 unlink (fullpath_tmp
);
2179 free (fullpath_sav
);
2180 free (fullpath_tmp
);
2184 while((c
= read (sav
, buffer
, 512)) > 0)
2185 write (tmp
, buffer
, c
);
2190 if (chmod(fullpath_tmp
, CONFIGFILE_MASK
) != 0)
2192 unlink (fullpath_tmp
);
2193 free (fullpath_sav
);
2194 free (fullpath_tmp
);
2198 if (link (fullpath_tmp
, fullpath
) == 0)
2199 ret
= fopen (fullpath
, "r");
2201 unlink (fullpath_tmp
);
2203 free (fullpath_sav
);
2204 free (fullpath_tmp
);
2205 return fopen (fullpath
, "r");
2208 /* Read up configuration file from file_name. */
2210 vty_read_config (char *config_file
,
2211 char *config_current_dir
,
2212 char *config_default_dir
)
2214 char cwd
[MAXPATHLEN
];
2218 /* If -f flag specified. */
2219 if (config_file
!= NULL
)
2221 if (! IS_DIRECTORY_SEP (config_file
[0]))
2223 getcwd (cwd
, MAXPATHLEN
);
2224 fullpath
= XMALLOC (MTYPE_TMP
,
2225 strlen (cwd
) + strlen (config_file
) + 2);
2226 sprintf (fullpath
, "%s/%s", cwd
, config_file
);
2229 fullpath
= config_file
;
2231 confp
= fopen (fullpath
, "r");
2235 confp
= vty_use_backup_config (fullpath
);
2237 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2240 fprintf (stderr
, "can't open configuration file [%s]\n",
2248 /* Relative path configuration file open. */
2249 if (config_current_dir
)
2251 confp
= fopen (config_current_dir
, "r");
2254 confp
= vty_use_backup_config (config_current_dir
);
2256 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2260 /* If there is no relative path exists, open system default file. */
2265 struct stat conf_stat
;
2267 /* !!!!PLEASE LEAVE!!!!
2268 This is NEEDED for use with vtysh -b, or else you can get
2269 a real configuration food fight with a lot garbage in the
2270 merged configuration file it creates coming from the per
2271 daemon configuration files. This also allows the daemons
2272 to start if there default configuration file is not
2273 present or ignore them, as needed when using vtysh -b to
2274 configure the daemons at boot - MAG */
2276 /* Stat for vtysh Zebra.conf, if found startup and wait for
2277 boot configuration */
2279 if ( strstr(config_default_dir
, "vtysh") == NULL
)
2281 ret
= stat (integrate_default
, &conf_stat
);
2289 confp
= fopen (config_default_dir
, "r");
2292 confp
= vty_use_backup_config (config_default_dir
);
2295 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2296 fullpath
= config_default_dir
;
2300 fprintf (stderr
, "can't open configuration file [%s]\n",
2301 config_default_dir
);
2306 fullpath
= config_default_dir
;
2310 /* Rleative path configuration file. */
2311 getcwd (cwd
, MAXPATHLEN
);
2312 fullpath
= XMALLOC (MTYPE_TMP
,
2313 strlen (cwd
) + strlen (config_current_dir
) + 2);
2314 sprintf (fullpath
, "%s/%s", cwd
, config_current_dir
);
2317 vty_read_file (confp
);
2321 host_config_set (fullpath
);
2324 /* Small utility function which output log to the VTY. */
2326 vty_log (const char *proto_str
, const char *format
, va_list va
)
2331 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2332 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2334 vty_log_out (vty
, proto_str
, format
, va
);
2338 vty_config_lock (struct vty
*vty
)
2340 if (vty_config
== 0)
2349 vty_config_unlock (struct vty
*vty
)
2351 if (vty_config
== 1 && vty
->config
== 1)
2359 /* Master of the threads. */
2360 static struct thread_master
*master
;
2363 vty_event (enum event event
, int sock
, struct vty
*vty
)
2365 struct thread
*vty_serv_thread
;
2370 vty_serv_thread
= thread_add_read (master
, vty_accept
, vty
, sock
);
2371 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2375 thread_add_read (master
, vtysh_accept
, vty
, sock
);
2378 thread_add_read (master
, vtysh_read
, vty
, sock
);
2382 vty
->t_read
= thread_add_read (master
, vty_read
, vty
, sock
);
2384 /* Time out treatment. */
2388 thread_cancel (vty
->t_timeout
);
2390 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2395 vty
->t_write
= thread_add_write (master
, vty_flush
, vty
, sock
);
2397 case VTY_TIMEOUT_RESET
:
2400 thread_cancel (vty
->t_timeout
);
2401 vty
->t_timeout
= NULL
;
2406 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2415 "Display who is on vty\n")
2420 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2421 if ((v
= vector_slot (vtyvec
, i
)) != NULL
)
2422 vty_out (vty
, "%svty[%d] connected from %s.%s",
2423 v
->config
? "*" : " ",
2424 i
, v
->address
, VTY_NEWLINE
);
2428 /* Move to vty configuration mode. */
2432 "Configure a terminal line\n"
2433 "Virtual terminal\n")
2435 vty
->node
= VTY_NODE
;
2439 /* Set time out value. */
2441 exec_timeout (struct vty
*vty
, char *min_str
, char *sec_str
)
2443 unsigned long timeout
= 0;
2445 /* min_str and sec_str are already checked by parser. So it must be
2446 all digit string. */
2449 timeout
= strtol (min_str
, NULL
, 10);
2453 timeout
+= strtol (sec_str
, NULL
, 10);
2455 vty_timeout_val
= timeout
;
2456 vty
->v_timeout
= timeout
;
2457 vty_event (VTY_TIMEOUT_RESET
, 0, vty
);
2463 DEFUN (exec_timeout_min
,
2464 exec_timeout_min_cmd
,
2465 "exec-timeout <0-35791>",
2466 "Set timeout value\n"
2467 "Timeout value in minutes\n")
2469 return exec_timeout (vty
, argv
[0], NULL
);
2472 DEFUN (exec_timeout_sec
,
2473 exec_timeout_sec_cmd
,
2474 "exec-timeout <0-35791> <0-2147483>",
2475 "Set the EXEC timeout\n"
2476 "Timeout in minutes\n"
2477 "Timeout in seconds\n")
2479 return exec_timeout (vty
, argv
[0], argv
[1]);
2482 DEFUN (no_exec_timeout
,
2483 no_exec_timeout_cmd
,
2486 "Set the EXEC timeout\n")
2488 return exec_timeout (vty
, NULL
, NULL
);
2491 /* Set vty access class. */
2492 DEFUN (vty_access_class
,
2493 vty_access_class_cmd
,
2494 "access-class WORD",
2495 "Filter connections based on an IP access list\n"
2498 if (vty_accesslist_name
)
2499 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2501 vty_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2506 /* Clear vty access class. */
2507 DEFUN (no_vty_access_class
,
2508 no_vty_access_class_cmd
,
2509 "no access-class [WORD]",
2511 "Filter connections based on an IP access list\n"
2514 if (! vty_accesslist_name
|| (argc
&& strcmp(vty_accesslist_name
, argv
[0])))
2516 vty_out (vty
, "Access-class is not currently applied to vty%s",
2521 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2523 vty_accesslist_name
= NULL
;
2529 /* Set vty access class. */
2530 DEFUN (vty_ipv6_access_class
,
2531 vty_ipv6_access_class_cmd
,
2532 "ipv6 access-class WORD",
2534 "Filter connections based on an IP access list\n"
2535 "IPv6 access list\n")
2537 if (vty_ipv6_accesslist_name
)
2538 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2540 vty_ipv6_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2545 /* Clear vty access class. */
2546 DEFUN (no_vty_ipv6_access_class
,
2547 no_vty_ipv6_access_class_cmd
,
2548 "no ipv6 access-class [WORD]",
2551 "Filter connections based on an IP access list\n"
2552 "IPv6 access list\n")
2554 if (! vty_ipv6_accesslist_name
||
2555 (argc
&& strcmp(vty_ipv6_accesslist_name
, argv
[0])))
2557 vty_out (vty
, "IPv6 access-class is not currently applied to vty%s",
2562 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2564 vty_ipv6_accesslist_name
= NULL
;
2568 #endif /* HAVE_IPV6 */
2574 "Enable password checking\n")
2576 no_password_check
= 0;
2580 DEFUN (no_vty_login
,
2584 "Enable password checking\n")
2586 no_password_check
= 1;
2590 DEFUN (service_advanced_vty
,
2591 service_advanced_vty_cmd
,
2592 "service advanced-vty",
2593 "Set up miscellaneous service\n"
2594 "Enable advanced mode vty interface\n")
2600 DEFUN (no_service_advanced_vty
,
2601 no_service_advanced_vty_cmd
,
2602 "no service advanced-vty",
2604 "Set up miscellaneous service\n"
2605 "Enable advanced mode vty interface\n")
2611 DEFUN (terminal_monitor
,
2612 terminal_monitor_cmd
,
2614 "Set terminal line parameters\n"
2615 "Copy debug output to the current terminal line\n")
2621 DEFUN (terminal_no_monitor
,
2622 terminal_no_monitor_cmd
,
2623 "terminal no monitor",
2624 "Set terminal line parameters\n"
2626 "Copy debug output to the current terminal line\n")
2632 DEFUN (show_history
,
2636 "Display the session command history\n")
2640 for (index
= vty
->hindex
+ 1; index
!= vty
->hindex
;)
2642 if (index
== VTY_MAXHIST
)
2648 if (vty
->hist
[index
] != NULL
)
2649 vty_out (vty
, " %s%s", vty
->hist
[index
], VTY_NEWLINE
);
2657 /* Display current configuration. */
2659 vty_config_write (struct vty
*vty
)
2661 vty_out (vty
, "line vty%s", VTY_NEWLINE
);
2663 if (vty_accesslist_name
)
2664 vty_out (vty
, " access-class %s%s",
2665 vty_accesslist_name
, VTY_NEWLINE
);
2667 if (vty_ipv6_accesslist_name
)
2668 vty_out (vty
, " ipv6 access-class %s%s",
2669 vty_ipv6_accesslist_name
, VTY_NEWLINE
);
2672 if (vty_timeout_val
!= VTY_TIMEOUT_DEFAULT
)
2673 vty_out (vty
, " exec-timeout %ld %ld%s",
2674 vty_timeout_val
/ 60,
2675 vty_timeout_val
% 60, VTY_NEWLINE
);
2678 if (no_password_check
)
2679 vty_out (vty
, " no login%s", VTY_NEWLINE
);
2681 vty_out (vty
, "!%s", VTY_NEWLINE
);
2686 struct cmd_node vty_node
=
2689 "%s(config-line)# ",
2692 /* Reset all VTY status. */
2698 struct thread
*vty_serv_thread
;
2700 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2701 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2703 buffer_reset (vty
->obuf
);
2704 vty
->status
= VTY_CLOSE
;
2708 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2709 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2711 thread_cancel (vty_serv_thread
);
2712 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2716 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2718 if (vty_accesslist_name
)
2720 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2721 vty_accesslist_name
= NULL
;
2724 if (vty_ipv6_accesslist_name
)
2726 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2727 vty_ipv6_accesslist_name
= NULL
;
2731 /* for ospf6d easy temprary reload function */
2732 /* vty_reset + close accept socket */
2738 struct thread
*vty_serv_thread
;
2740 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2741 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2743 buffer_reset (vty
->obuf
);
2744 vty
->status
= VTY_CLOSE
;
2748 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2749 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2751 thread_cancel (vty_serv_thread
);
2752 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2756 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2758 if (vty_accesslist_name
)
2760 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2761 vty_accesslist_name
= NULL
;
2764 if (vty_ipv6_accesslist_name
)
2766 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2767 vty_ipv6_accesslist_name
= NULL
;
2774 char cwd
[MAXPATHLEN
];
2777 c
= getcwd (cwd
, MAXPATHLEN
);
2782 getcwd (cwd
, MAXPATHLEN
);
2785 vty_cwd
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + 1);
2786 strcpy (vty_cwd
, cwd
);
2796 vty_shell (struct vty
*vty
)
2798 return vty
->type
== VTY_SHELL
? 1 : 0;
2802 vty_shell_serv (struct vty
*vty
)
2804 return vty
->type
== VTY_SHELL_SERV
? 1 : 0;
2810 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2813 /* Install vty's own commands like `who' command. */
2815 vty_init (struct thread_master
*master_thread
)
2817 /* For further configuration read, preserve current directory. */
2820 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2822 master
= master_thread
;
2824 /* Initilize server thread vector. */
2825 Vvty_serv_thread
= vector_init (VECTOR_MIN_SIZE
);
2827 /* Install bgp top node. */
2828 install_node (&vty_node
, vty_config_write
);
2830 install_element (VIEW_NODE
, &config_who_cmd
);
2831 install_element (VIEW_NODE
, &show_history_cmd
);
2832 install_element (ENABLE_NODE
, &config_who_cmd
);
2833 install_element (CONFIG_NODE
, &line_vty_cmd
);
2834 install_element (CONFIG_NODE
, &service_advanced_vty_cmd
);
2835 install_element (CONFIG_NODE
, &no_service_advanced_vty_cmd
);
2836 install_element (CONFIG_NODE
, &show_history_cmd
);
2837 install_element (ENABLE_NODE
, &terminal_monitor_cmd
);
2838 install_element (ENABLE_NODE
, &terminal_no_monitor_cmd
);
2839 install_element (ENABLE_NODE
, &show_history_cmd
);
2841 install_default (VTY_NODE
);
2842 install_element (VTY_NODE
, &exec_timeout_min_cmd
);
2843 install_element (VTY_NODE
, &exec_timeout_sec_cmd
);
2844 install_element (VTY_NODE
, &no_exec_timeout_cmd
);
2845 install_element (VTY_NODE
, &vty_access_class_cmd
);
2846 install_element (VTY_NODE
, &no_vty_access_class_cmd
);
2847 install_element (VTY_NODE
, &vty_login_cmd
);
2848 install_element (VTY_NODE
, &no_vty_login_cmd
);
2850 install_element (VTY_NODE
, &vty_ipv6_access_class_cmd
);
2851 install_element (VTY_NODE
, &no_vty_ipv6_access_class_cmd
);
2852 #endif /* HAVE_IPV6 */