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 unsigned 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 unsigned 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 unsigned 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 unsigned 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 unsigned 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
)
1859 int sock
, len
, flags
;
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. */
1904 /* set to non-blocking*/
1905 if ( ((flags
= fcntl (sock
, F_GETFL
)) == -1)
1906 || (fcntl (sock
, F_SETFL
, flags
|O_NONBLOCK
) == -1) )
1907 zlog_warn ("vty_serv_un: could not set vty socket to non-blocking,"
1908 " %s", strerror (errno
));
1912 zprivs_get_ids(&ids
);
1914 if (ids
.gid_vty
> 0)
1916 /* set group of socket */
1917 if ( chown (path
, -1, ids
.gid_vty
) )
1919 zlog_err ("vty_serv_un: could chown socket, %s",
1924 vty_event (VTYSH_SERV
, sock
, NULL
);
1927 /* #define VTYSH_DEBUG 1 */
1930 vtysh_accept (struct thread
*thread
)
1935 struct sockaddr_un client
;
1938 accept_sock
= THREAD_FD (thread
);
1940 vty_event (VTYSH_SERV
, accept_sock
, NULL
);
1942 memset (&client
, 0, sizeof (struct sockaddr_un
));
1943 client_len
= sizeof (struct sockaddr_un
);
1945 sock
= accept (accept_sock
, (struct sockaddr
*) &client
,
1946 (socklen_t
*) &client_len
);
1950 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1955 printf ("VTY shell accept\n");
1956 #endif /* VTYSH_DEBUG */
1960 vty
->type
= VTY_SHELL_SERV
;
1961 vty
->node
= VIEW_NODE
;
1963 vty_event (VTYSH_READ
, sock
, vty
);
1969 vtysh_read (struct thread
*thread
)
1975 unsigned char buf
[VTY_READ_BUFSIZ
];
1976 u_char header
[4] = {0, 0, 0, 0};
1978 sock
= THREAD_FD (thread
);
1979 vty
= THREAD_ARG (thread
);
1982 nbytes
= read (sock
, buf
, VTY_READ_BUFSIZ
);
1987 printf ("close vtysh\n");
1988 #endif /* VTYSH_DEBUG */
1993 printf ("line: %s\n", buf
);
1994 #endif /* VTYSH_DEBUG */
1996 vty_ensure (vty
, nbytes
);
1997 memcpy (vty
->buf
, buf
, nbytes
);
1999 /* Pass this line to parser. */
2000 ret
= vty_execute (vty
);
2002 vty_clear_buf (vty
);
2004 /* Return result. */
2006 printf ("result: %d\n", ret
);
2007 printf ("vtysh node: %d\n", vty
->node
);
2008 #endif /* VTYSH_DEBUG */
2011 write (vty
->fd
, header
, 4);
2013 vty_event (VTYSH_READ
, sock
, vty
);
2019 /* Determine address family to bind. */
2021 vty_serv_sock (const char *addr
, unsigned short port
, char *path
)
2023 /* If port is set to 0, do not listen on TCP/IP at all! */
2029 vty_serv_sock_family (addr
, port
, AF_INET
);
2030 vty_serv_sock_family (addr
, port
, AF_INET6
);
2032 vty_serv_sock_addrinfo (addr
, port
);
2034 #else /* ! HAVE_IPV6 */
2035 vty_serv_sock_family (addr
,port
, AF_INET
);
2036 #endif /* HAVE_IPV6 */
2044 /* Close vty interface. */
2046 vty_close (struct vty
*vty
)
2050 /* Cancel threads.*/
2052 thread_cancel (vty
->t_read
);
2054 thread_cancel (vty
->t_write
);
2056 thread_cancel (vty
->t_timeout
);
2058 thread_cancel (vty
->t_output
);
2061 if (! buffer_empty (vty
->obuf
))
2062 buffer_flush_all (vty
->obuf
, vty
->fd
);
2064 /* Free input buffer. */
2065 buffer_free (vty
->obuf
);
2067 /* Free SB buffer. */
2069 buffer_free (vty
->sb_buffer
);
2071 /* Free command history. */
2072 for (i
= 0; i
< VTY_MAXHIST
; i
++)
2074 XFREE (MTYPE_VTY_HIST
, vty
->hist
[i
]);
2077 vector_unset (vtyvec
, vty
->fd
);
2084 XFREE (0, vty
->address
);
2086 XFREE (MTYPE_VTY
, vty
->buf
);
2088 /* Check configure. */
2089 vty_config_unlock (vty
);
2092 XFREE (MTYPE_VTY
, vty
);
2095 /* When time out occur output message then close connection. */
2097 vty_timeout (struct thread
*thread
)
2101 vty
= THREAD_ARG (thread
);
2102 vty
->t_timeout
= NULL
;
2106 buffer_reset (vty
->obuf
);
2107 vty_out (vty
, "%sVty connection is timed out.%s", VTY_NEWLINE
, VTY_NEWLINE
);
2109 /* Close connection. */
2110 vty
->status
= VTY_CLOSE
;
2116 /* Read up configuration file from file_name. */
2118 vty_read_file (FILE *confp
)
2124 vty
->fd
= 0; /* stdout */
2125 vty
->type
= VTY_TERM
;
2126 vty
->node
= CONFIG_NODE
;
2128 /* Execute configuration file */
2129 ret
= config_from_file (vty
, confp
);
2131 if ( !((ret
== CMD_SUCCESS
) || (ret
== CMD_ERR_NOTHING_TODO
)) )
2135 case CMD_ERR_AMBIGUOUS
:
2136 fprintf (stderr
, "Ambiguous command.\n");
2138 case CMD_ERR_NO_MATCH
:
2139 fprintf (stderr
, "There is no such command.\n");
2142 fprintf (stderr
, "Error occured during reading below line.\n%s\n",
2152 vty_use_backup_config (char *fullpath
)
2154 char *fullpath_sav
, *fullpath_tmp
;
2161 fullpath_sav
= malloc (strlen (fullpath
) + strlen (CONF_BACKUP_EXT
) + 1);
2162 strcpy (fullpath_sav
, fullpath
);
2163 strcat (fullpath_sav
, CONF_BACKUP_EXT
);
2164 if (stat (fullpath_sav
, &buf
) == -1)
2166 free (fullpath_sav
);
2170 fullpath_tmp
= malloc (strlen (fullpath
) + 8);
2171 sprintf (fullpath_tmp
, "%s.XXXXXX", fullpath
);
2173 /* Open file to configuration write. */
2174 tmp
= mkstemp (fullpath_tmp
);
2177 free (fullpath_sav
);
2178 free (fullpath_tmp
);
2182 sav
= open (fullpath_sav
, O_RDONLY
);
2185 unlink (fullpath_tmp
);
2186 free (fullpath_sav
);
2187 free (fullpath_tmp
);
2191 while((c
= read (sav
, buffer
, 512)) > 0)
2192 write (tmp
, buffer
, c
);
2197 if (chmod(fullpath_tmp
, CONFIGFILE_MASK
) != 0)
2199 unlink (fullpath_tmp
);
2200 free (fullpath_sav
);
2201 free (fullpath_tmp
);
2205 if (link (fullpath_tmp
, fullpath
) == 0)
2206 ret
= fopen (fullpath
, "r");
2208 unlink (fullpath_tmp
);
2210 free (fullpath_sav
);
2211 free (fullpath_tmp
);
2212 return fopen (fullpath
, "r");
2215 /* Read up configuration file from file_name. */
2217 vty_read_config (char *config_file
,
2218 char *config_default_dir
)
2220 char cwd
[MAXPATHLEN
];
2224 /* If -f flag specified. */
2225 if (config_file
!= NULL
)
2227 if (! IS_DIRECTORY_SEP (config_file
[0]))
2229 getcwd (cwd
, MAXPATHLEN
);
2230 fullpath
= XMALLOC (MTYPE_TMP
,
2231 strlen (cwd
) + strlen (config_file
) + 2);
2232 sprintf (fullpath
, "%s/%s", cwd
, config_file
);
2235 fullpath
= config_file
;
2237 confp
= fopen (fullpath
, "r");
2241 confp
= vty_use_backup_config (fullpath
);
2243 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2246 fprintf (stderr
, "can't open configuration file [%s]\n",
2256 struct stat conf_stat
;
2258 /* !!!!PLEASE LEAVE!!!!
2259 * This is NEEDED for use with vtysh -b, or else you can get
2260 * a real configuration food fight with a lot garbage in the
2261 * merged configuration file it creates coming from the per
2262 * daemon configuration files. This also allows the daemons
2263 * to start if there default configuration file is not
2264 * present or ignore them, as needed when using vtysh -b to
2265 * configure the daemons at boot - MAG
2268 /* Stat for vtysh Zebra.conf, if found startup and wait for
2269 * boot configuration
2272 if ( strstr(config_default_dir
, "vtysh") == NULL
)
2274 ret
= stat (integrate_default
, &conf_stat
);
2280 confp
= fopen (config_default_dir
, "r");
2283 confp
= vty_use_backup_config (config_default_dir
);
2286 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2287 fullpath
= config_default_dir
;
2291 fprintf (stderr
, "can't open configuration file [%s]\n",
2292 config_default_dir
);
2297 fullpath
= config_default_dir
;
2300 vty_read_file (confp
);
2304 host_config_set (fullpath
);
2307 /* Small utility function which output log to the VTY. */
2309 vty_log (const char *proto_str
, const char *format
, va_list va
)
2314 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2315 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2317 vty_log_out (vty
, proto_str
, format
, va
);
2321 vty_config_lock (struct vty
*vty
)
2323 if (vty_config
== 0)
2332 vty_config_unlock (struct vty
*vty
)
2334 if (vty_config
== 1 && vty
->config
== 1)
2342 /* Master of the threads. */
2343 static struct thread_master
*master
;
2346 vty_event (enum event event
, int sock
, struct vty
*vty
)
2348 struct thread
*vty_serv_thread
;
2353 vty_serv_thread
= thread_add_read (master
, vty_accept
, vty
, sock
);
2354 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2358 thread_add_read (master
, vtysh_accept
, vty
, sock
);
2361 thread_add_read (master
, vtysh_read
, vty
, sock
);
2365 vty
->t_read
= thread_add_read (master
, vty_read
, vty
, sock
);
2367 /* Time out treatment. */
2371 thread_cancel (vty
->t_timeout
);
2373 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2378 vty
->t_write
= thread_add_write (master
, vty_flush
, vty
, sock
);
2380 case VTY_TIMEOUT_RESET
:
2383 thread_cancel (vty
->t_timeout
);
2384 vty
->t_timeout
= NULL
;
2389 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2398 "Display who is on vty\n")
2403 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2404 if ((v
= vector_slot (vtyvec
, i
)) != NULL
)
2405 vty_out (vty
, "%svty[%d] connected from %s.%s",
2406 v
->config
? "*" : " ",
2407 i
, v
->address
, VTY_NEWLINE
);
2411 /* Move to vty configuration mode. */
2415 "Configure a terminal line\n"
2416 "Virtual terminal\n")
2418 vty
->node
= VTY_NODE
;
2422 /* Set time out value. */
2424 exec_timeout (struct vty
*vty
, char *min_str
, char *sec_str
)
2426 unsigned long timeout
= 0;
2428 /* min_str and sec_str are already checked by parser. So it must be
2429 all digit string. */
2432 timeout
= strtol (min_str
, NULL
, 10);
2436 timeout
+= strtol (sec_str
, NULL
, 10);
2438 vty_timeout_val
= timeout
;
2439 vty
->v_timeout
= timeout
;
2440 vty_event (VTY_TIMEOUT_RESET
, 0, vty
);
2446 DEFUN (exec_timeout_min
,
2447 exec_timeout_min_cmd
,
2448 "exec-timeout <0-35791>",
2449 "Set timeout value\n"
2450 "Timeout value in minutes\n")
2452 return exec_timeout (vty
, argv
[0], NULL
);
2455 DEFUN (exec_timeout_sec
,
2456 exec_timeout_sec_cmd
,
2457 "exec-timeout <0-35791> <0-2147483>",
2458 "Set the EXEC timeout\n"
2459 "Timeout in minutes\n"
2460 "Timeout in seconds\n")
2462 return exec_timeout (vty
, argv
[0], argv
[1]);
2465 DEFUN (no_exec_timeout
,
2466 no_exec_timeout_cmd
,
2469 "Set the EXEC timeout\n")
2471 return exec_timeout (vty
, NULL
, NULL
);
2474 /* Set vty access class. */
2475 DEFUN (vty_access_class
,
2476 vty_access_class_cmd
,
2477 "access-class WORD",
2478 "Filter connections based on an IP access list\n"
2481 if (vty_accesslist_name
)
2482 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2484 vty_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2489 /* Clear vty access class. */
2490 DEFUN (no_vty_access_class
,
2491 no_vty_access_class_cmd
,
2492 "no access-class [WORD]",
2494 "Filter connections based on an IP access list\n"
2497 if (! vty_accesslist_name
|| (argc
&& strcmp(vty_accesslist_name
, argv
[0])))
2499 vty_out (vty
, "Access-class is not currently applied to vty%s",
2504 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2506 vty_accesslist_name
= NULL
;
2512 /* Set vty access class. */
2513 DEFUN (vty_ipv6_access_class
,
2514 vty_ipv6_access_class_cmd
,
2515 "ipv6 access-class WORD",
2517 "Filter connections based on an IP access list\n"
2518 "IPv6 access list\n")
2520 if (vty_ipv6_accesslist_name
)
2521 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2523 vty_ipv6_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2528 /* Clear vty access class. */
2529 DEFUN (no_vty_ipv6_access_class
,
2530 no_vty_ipv6_access_class_cmd
,
2531 "no 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 (argc
&& strcmp(vty_ipv6_accesslist_name
, argv
[0])))
2540 vty_out (vty
, "IPv6 access-class is not currently applied to vty%s",
2545 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2547 vty_ipv6_accesslist_name
= NULL
;
2551 #endif /* HAVE_IPV6 */
2557 "Enable password checking\n")
2559 no_password_check
= 0;
2563 DEFUN (no_vty_login
,
2567 "Enable password checking\n")
2569 no_password_check
= 1;
2573 DEFUN (service_advanced_vty
,
2574 service_advanced_vty_cmd
,
2575 "service advanced-vty",
2576 "Set up miscellaneous service\n"
2577 "Enable advanced mode vty interface\n")
2583 DEFUN (no_service_advanced_vty
,
2584 no_service_advanced_vty_cmd
,
2585 "no service advanced-vty",
2587 "Set up miscellaneous service\n"
2588 "Enable advanced mode vty interface\n")
2594 DEFUN (terminal_monitor
,
2595 terminal_monitor_cmd
,
2597 "Set terminal line parameters\n"
2598 "Copy debug output to the current terminal line\n")
2604 DEFUN (terminal_no_monitor
,
2605 terminal_no_monitor_cmd
,
2606 "terminal no monitor",
2607 "Set terminal line parameters\n"
2609 "Copy debug output to the current terminal line\n")
2615 DEFUN (show_history
,
2619 "Display the session command history\n")
2623 for (index
= vty
->hindex
+ 1; index
!= vty
->hindex
;)
2625 if (index
== VTY_MAXHIST
)
2631 if (vty
->hist
[index
] != NULL
)
2632 vty_out (vty
, " %s%s", vty
->hist
[index
], VTY_NEWLINE
);
2640 /* Display current configuration. */
2642 vty_config_write (struct vty
*vty
)
2644 vty_out (vty
, "line vty%s", VTY_NEWLINE
);
2646 if (vty_accesslist_name
)
2647 vty_out (vty
, " access-class %s%s",
2648 vty_accesslist_name
, VTY_NEWLINE
);
2650 if (vty_ipv6_accesslist_name
)
2651 vty_out (vty
, " ipv6 access-class %s%s",
2652 vty_ipv6_accesslist_name
, VTY_NEWLINE
);
2655 if (vty_timeout_val
!= VTY_TIMEOUT_DEFAULT
)
2656 vty_out (vty
, " exec-timeout %ld %ld%s",
2657 vty_timeout_val
/ 60,
2658 vty_timeout_val
% 60, VTY_NEWLINE
);
2661 if (no_password_check
)
2662 vty_out (vty
, " no login%s", VTY_NEWLINE
);
2664 vty_out (vty
, "!%s", VTY_NEWLINE
);
2669 struct cmd_node vty_node
=
2672 "%s(config-line)# ",
2676 /* Reset all VTY status. */
2682 struct thread
*vty_serv_thread
;
2684 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2685 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2687 buffer_reset (vty
->obuf
);
2688 vty
->status
= VTY_CLOSE
;
2692 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2693 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2695 thread_cancel (vty_serv_thread
);
2696 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2700 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2702 if (vty_accesslist_name
)
2704 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2705 vty_accesslist_name
= NULL
;
2708 if (vty_ipv6_accesslist_name
)
2710 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2711 vty_ipv6_accesslist_name
= NULL
;
2715 /* for ospf6d easy temprary reload function */
2716 /* vty_reset + close accept socket */
2722 struct thread
*vty_serv_thread
;
2724 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2725 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2727 buffer_reset (vty
->obuf
);
2728 vty
->status
= VTY_CLOSE
;
2732 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2733 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2735 thread_cancel (vty_serv_thread
);
2736 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2740 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2742 if (vty_accesslist_name
)
2744 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2745 vty_accesslist_name
= NULL
;
2748 if (vty_ipv6_accesslist_name
)
2750 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2751 vty_ipv6_accesslist_name
= NULL
;
2758 char cwd
[MAXPATHLEN
];
2761 c
= getcwd (cwd
, MAXPATHLEN
);
2766 getcwd (cwd
, MAXPATHLEN
);
2769 vty_cwd
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + 1);
2770 strcpy (vty_cwd
, cwd
);
2780 vty_shell (struct vty
*vty
)
2782 return vty
->type
== VTY_SHELL
? 1 : 0;
2786 vty_shell_serv (struct vty
*vty
)
2788 return vty
->type
== VTY_SHELL_SERV
? 1 : 0;
2794 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2797 /* Install vty's own commands like `who' command. */
2799 vty_init (struct thread_master
*master_thread
)
2801 /* For further configuration read, preserve current directory. */
2804 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2806 master
= master_thread
;
2808 /* Initilize server thread vector. */
2809 Vvty_serv_thread
= vector_init (VECTOR_MIN_SIZE
);
2811 /* Install bgp top node. */
2812 install_node (&vty_node
, vty_config_write
);
2814 install_element (VIEW_NODE
, &config_who_cmd
);
2815 install_element (VIEW_NODE
, &show_history_cmd
);
2816 install_element (ENABLE_NODE
, &config_who_cmd
);
2817 install_element (CONFIG_NODE
, &line_vty_cmd
);
2818 install_element (CONFIG_NODE
, &service_advanced_vty_cmd
);
2819 install_element (CONFIG_NODE
, &no_service_advanced_vty_cmd
);
2820 install_element (CONFIG_NODE
, &show_history_cmd
);
2821 install_element (ENABLE_NODE
, &terminal_monitor_cmd
);
2822 install_element (ENABLE_NODE
, &terminal_no_monitor_cmd
);
2823 install_element (ENABLE_NODE
, &show_history_cmd
);
2825 install_default (VTY_NODE
);
2826 install_element (VTY_NODE
, &exec_timeout_min_cmd
);
2827 install_element (VTY_NODE
, &exec_timeout_sec_cmd
);
2828 install_element (VTY_NODE
, &no_exec_timeout_cmd
);
2829 install_element (VTY_NODE
, &vty_access_class_cmd
);
2830 install_element (VTY_NODE
, &no_vty_access_class_cmd
);
2831 install_element (VTY_NODE
, &vty_login_cmd
);
2832 install_element (VTY_NODE
, &no_vty_login_cmd
);
2834 install_element (VTY_NODE
, &vty_ipv6_access_class_cmd
);
2835 install_element (VTY_NODE
, &no_vty_ipv6_access_class_cmd
);
2836 #endif /* HAVE_IPV6 */