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
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
);
630 case KEYCHAIN_KEY_NODE
:
633 vty_config_unlock (vty
);
634 vty
->node
= ENABLE_NODE
;
637 /* Unknown node, we have to ignore it. */
645 /* Delete a charcter at the current point. */
647 vty_delete_char (struct vty
*vty
)
652 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
655 if (vty
->length
== 0)
657 vty_down_level (vty
);
661 if (vty
->cp
== vty
->length
)
662 return; /* completion need here? */
664 size
= vty
->length
- vty
->cp
;
667 memmove (&vty
->buf
[vty
->cp
], &vty
->buf
[vty
->cp
+ 1], size
- 1);
668 vty
->buf
[vty
->length
] = '\0';
670 vty_write (vty
, &vty
->buf
[vty
->cp
], size
- 1);
671 vty_write (vty
, &telnet_space_char
, 1);
673 for (i
= 0; i
< size
; i
++)
674 vty_write (vty
, &telnet_backward_char
, 1);
677 /* Delete a character before the point. */
679 vty_delete_backward_char (struct vty
*vty
)
684 vty_backward_char (vty
);
685 vty_delete_char (vty
);
688 /* Kill rest of line from current point. */
690 vty_kill_line (struct vty
*vty
)
695 size
= vty
->length
- vty
->cp
;
700 for (i
= 0; i
< size
; i
++)
701 vty_write (vty
, &telnet_space_char
, 1);
702 for (i
= 0; i
< size
; i
++)
703 vty_write (vty
, &telnet_backward_char
, 1);
705 memset (&vty
->buf
[vty
->cp
], 0, size
);
706 vty
->length
= vty
->cp
;
709 /* Kill line from the beginning. */
711 vty_kill_line_from_beginning (struct vty
*vty
)
713 vty_beginning_of_line (vty
);
717 /* Delete a word before the point. */
719 vty_forward_kill_word (struct vty
*vty
)
721 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
722 vty_delete_char (vty
);
723 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
724 vty_delete_char (vty
);
727 /* Delete a word before the point. */
729 vty_backward_kill_word (struct vty
*vty
)
731 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
732 vty_delete_backward_char (vty
);
733 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
734 vty_delete_backward_char (vty
);
737 /* Transpose chars before or at the point. */
739 vty_transpose_chars (struct vty
*vty
)
743 /* If length is short or point is near by the beginning of line then
745 if (vty
->length
< 2 || vty
->cp
< 1)
748 /* In case of point is located at the end of the line. */
749 if (vty
->cp
== vty
->length
)
751 c1
= vty
->buf
[vty
->cp
- 1];
752 c2
= vty
->buf
[vty
->cp
- 2];
754 vty_backward_char (vty
);
755 vty_backward_char (vty
);
756 vty_self_insert_overwrite (vty
, c1
);
757 vty_self_insert_overwrite (vty
, c2
);
761 c1
= vty
->buf
[vty
->cp
];
762 c2
= vty
->buf
[vty
->cp
- 1];
764 vty_backward_char (vty
);
765 vty_self_insert_overwrite (vty
, c1
);
766 vty_self_insert_overwrite (vty
, c2
);
770 /* Do completion at vty interface. */
772 vty_complete_command (struct vty
*vty
)
776 char **matched
= NULL
;
779 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
782 vline
= cmd_make_strvec (vty
->buf
);
786 /* In case of 'help \t'. */
787 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
788 vector_set (vline
, '\0');
790 matched
= cmd_complete_command (vline
, vty
, &ret
);
792 cmd_free_strvec (vline
);
794 vty_out (vty
, "%s", VTY_NEWLINE
);
797 case CMD_ERR_AMBIGUOUS
:
798 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
800 vty_redraw_line (vty
);
802 case CMD_ERR_NO_MATCH
:
803 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
805 vty_redraw_line (vty
);
807 case CMD_COMPLETE_FULL_MATCH
:
809 vty_redraw_line (vty
);
810 vty_backward_pure_word (vty
);
811 vty_insert_word_overwrite (vty
, matched
[0]);
812 vty_self_insert (vty
, ' ');
813 XFREE (MTYPE_TMP
, matched
[0]);
815 case CMD_COMPLETE_MATCH
:
817 vty_redraw_line (vty
);
818 vty_backward_pure_word (vty
);
819 vty_insert_word_overwrite (vty
, matched
[0]);
820 XFREE (MTYPE_TMP
, matched
[0]);
821 vector_only_index_free (matched
);
824 case CMD_COMPLETE_LIST_MATCH
:
825 for (i
= 0; matched
[i
] != NULL
; i
++)
827 if (i
!= 0 && ((i
% 6) == 0))
828 vty_out (vty
, "%s", VTY_NEWLINE
);
829 vty_out (vty
, "%-10s ", matched
[i
]);
830 XFREE (MTYPE_TMP
, matched
[i
]);
832 vty_out (vty
, "%s", VTY_NEWLINE
);
835 vty_redraw_line (vty
);
837 case CMD_ERR_NOTHING_TODO
:
839 vty_redraw_line (vty
);
845 vector_only_index_free (matched
);
849 vty_describe_fold (struct vty
*vty
, int cmd_width
,
850 int desc_width
, struct desc
*desc
)
855 cmd
= desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
;
859 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, desc
->str
, VTY_NEWLINE
);
863 buf
= XCALLOC (MTYPE_TMP
, strlen (desc
->str
) + 1);
865 for (p
= desc
->str
; strlen (p
) > desc_width
; p
+= pos
+ 1)
867 for (pos
= desc_width
; pos
> 0; pos
--)
868 if (*(p
+ pos
) == ' ')
874 strncpy (buf
, p
, pos
);
876 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, buf
, VTY_NEWLINE
);
881 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, p
, VTY_NEWLINE
);
883 XFREE (MTYPE_TMP
, buf
);
886 /* Describe matched command function. */
888 vty_describe_command (struct vty
*vty
)
893 int i
, width
, desc_width
;
894 struct desc
*desc
, *desc_cr
= NULL
;
896 vline
= cmd_make_strvec (vty
->buf
);
898 /* In case of '> ?'. */
901 vline
= vector_init (1);
902 vector_set (vline
, '\0');
905 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
906 vector_set (vline
, '\0');
908 describe
= cmd_describe_command (vline
, vty
, &ret
);
910 vty_out (vty
, "%s", VTY_NEWLINE
);
912 /* Ambiguous error. */
915 case CMD_ERR_AMBIGUOUS
:
916 cmd_free_strvec (vline
);
917 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
919 vty_redraw_line (vty
);
922 case CMD_ERR_NO_MATCH
:
923 cmd_free_strvec (vline
);
924 vty_out (vty
, "%% There is no matched command.%s", VTY_NEWLINE
);
926 vty_redraw_line (vty
);
931 /* Get width of command string. */
933 for (i
= 0; i
< vector_max (describe
); i
++)
934 if ((desc
= vector_slot (describe
, i
)) != NULL
)
938 if (desc
->cmd
[0] == '\0')
941 len
= strlen (desc
->cmd
);
942 if (desc
->cmd
[0] == '.')
949 /* Get width of description string. */
950 desc_width
= vty
->width
- (width
+ 6);
952 /* Print out description. */
953 for (i
= 0; i
< vector_max (describe
); i
++)
954 if ((desc
= vector_slot (describe
, i
)) != NULL
)
956 if (desc
->cmd
[0] == '\0')
959 if (strcmp (desc
->cmd
, "<cr>") == 0)
966 vty_out (vty
, " %-s%s",
967 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
969 else if (desc_width
>= strlen (desc
->str
))
970 vty_out (vty
, " %-*s %s%s", width
,
971 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
972 desc
->str
, VTY_NEWLINE
);
974 vty_describe_fold (vty
, width
, desc_width
, desc
);
977 vty_out (vty
, " %-*s %s%s", width
978 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
979 desc
->str
? desc
->str
: "", VTY_NEWLINE
);
983 if ((desc
= desc_cr
))
986 vty_out (vty
, " %-s%s",
987 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
989 else if (desc_width
>= strlen (desc
->str
))
990 vty_out (vty
, " %-*s %s%s", width
,
991 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
992 desc
->str
, VTY_NEWLINE
);
994 vty_describe_fold (vty
, width
, desc_width
, desc
);
997 cmd_free_strvec (vline
);
998 vector_free (describe
);
1001 vty_redraw_line (vty
);
1005 vty_clear_buf (struct vty
*vty
)
1007 memset (vty
->buf
, 0, vty
->max
);
1010 /* ^C stop current input and do not add command line to the history. */
1012 vty_stop_input (struct vty
*vty
)
1014 vty
->cp
= vty
->length
= 0;
1015 vty_clear_buf (vty
);
1016 vty_out (vty
, "%s", VTY_NEWLINE
);
1022 /* Nothing to do. */
1025 case INTERFACE_NODE
:
1034 case KEYCHAIN_KEY_NODE
:
1037 vty_config_unlock (vty
);
1038 vty
->node
= ENABLE_NODE
;
1041 /* Unknown node, we have to ignore it. */
1046 /* Set history pointer to the latest one. */
1047 vty
->hp
= vty
->hindex
;
1050 /* Add current command line to the history buffer. */
1052 vty_hist_add (struct vty
*vty
)
1056 if (vty
->length
== 0)
1059 index
= vty
->hindex
? vty
->hindex
- 1 : VTY_MAXHIST
- 1;
1061 /* Ignore the same string as previous one. */
1062 if (vty
->hist
[index
])
1063 if (strcmp (vty
->buf
, vty
->hist
[index
]) == 0)
1065 vty
->hp
= vty
->hindex
;
1069 /* Insert history entry. */
1070 if (vty
->hist
[vty
->hindex
])
1071 XFREE (MTYPE_VTY_HIST
, vty
->hist
[vty
->hindex
]);
1072 vty
->hist
[vty
->hindex
] = XSTRDUP (MTYPE_VTY_HIST
, vty
->buf
);
1074 /* History index rotation. */
1076 if (vty
->hindex
== VTY_MAXHIST
)
1079 vty
->hp
= vty
->hindex
;
1082 /* #define TELNET_OPTION_DEBUG */
1084 /* Get telnet window size. */
1086 vty_telnet_option (struct vty
*vty
, unsigned char *buf
, int nbytes
)
1088 #ifdef TELNET_OPTION_DEBUG
1091 for (i
= 0; i
< nbytes
; i
++)
1096 vty_out (vty
, "IAC ");
1099 vty_out (vty
, "WILL ");
1102 vty_out (vty
, "WONT ");
1105 vty_out (vty
, "DO ");
1108 vty_out (vty
, "DONT ");
1111 vty_out (vty
, "SB ");
1114 vty_out (vty
, "SE ");
1117 vty_out (vty
, "TELOPT_ECHO %s", VTY_NEWLINE
);
1120 vty_out (vty
, "TELOPT_SGA %s", VTY_NEWLINE
);
1123 vty_out (vty
, "TELOPT_NAWS %s", VTY_NEWLINE
);
1126 vty_out (vty
, "%x ", buf
[i
]);
1130 vty_out (vty
, "%s", VTY_NEWLINE
);
1132 #endif /* TELNET_OPTION_DEBUG */
1137 buffer_reset(vty
->sb_buffer
);
1138 vty
->iac_sb_in_progress
= 1;
1143 char *buffer
= (char *)vty
->sb_buffer
->head
->data
;
1144 int length
= vty
->sb_buffer
->length
;
1149 if (!vty
->iac_sb_in_progress
)
1152 if (buffer
[0] == '\0')
1154 vty
->iac_sb_in_progress
= 0;
1162 vty
->width
= buffer
[2];
1163 vty
->height
= vty
->lines
>= 0 ? vty
->lines
: buffer
[4];
1166 vty
->iac_sb_in_progress
= 0;
1176 /* Execute current command line. */
1178 vty_execute (struct vty
*vty
)
1187 case AUTH_ENABLE_NODE
:
1188 vty_auth (vty
, vty
->buf
);
1191 ret
= vty_command (vty
, vty
->buf
);
1192 if (vty
->type
== VTY_TERM
)
1197 /* Clear command line buffer. */
1198 vty
->cp
= vty
->length
= 0;
1199 vty_clear_buf (vty
);
1201 if (vty
->status
!= VTY_CLOSE
1202 && vty
->status
!= VTY_START
1203 && vty
->status
!= VTY_CONTINUE
)
1209 #define CONTROL(X) ((X) - '@')
1210 #define VTY_NORMAL 0
1211 #define VTY_PRE_ESCAPE 1
1212 #define VTY_ESCAPE 2
1214 /* Escape character command map. */
1216 vty_escape_map (unsigned char c
, struct vty
*vty
)
1221 vty_previous_line (vty
);
1224 vty_next_line (vty
);
1227 vty_forward_char (vty
);
1230 vty_backward_char (vty
);
1236 /* Go back to normal mode. */
1237 vty
->escape
= VTY_NORMAL
;
1240 /* Quit print out to the buffer. */
1242 vty_buffer_reset (struct vty
*vty
)
1244 buffer_reset (vty
->obuf
);
1246 vty_redraw_line (vty
);
1249 /* Read data via vty socket. */
1251 vty_read (struct thread
*thread
)
1256 unsigned char buf
[VTY_READ_BUFSIZ
];
1258 int vty_sock
= THREAD_FD (thread
);
1259 struct vty
*vty
= THREAD_ARG (thread
);
1262 /* Read raw data from socket */
1263 nbytes
= read (vty
->fd
, buf
, VTY_READ_BUFSIZ
);
1265 vty
->status
= VTY_CLOSE
;
1267 for (i
= 0; i
< nbytes
; i
++)
1282 if (vty
->iac_sb_in_progress
&& !vty
->iac
)
1284 buffer_putc(vty
->sb_buffer
, buf
[i
]);
1290 /* In case of telnet command */
1291 ret
= vty_telnet_option (vty
, buf
+ i
, nbytes
- i
);
1297 if (vty
->status
== VTY_MORE
)
1304 if (vty
->output_func
)
1305 (*vty
->output_func
) (vty
, 1);
1306 vty_buffer_reset (vty
);
1308 #if 0 /* More line does not work for "show ip bgp". */
1311 vty
->status
= VTY_MORELINE
;
1315 if (vty
->output_func
)
1316 (*vty
->output_func
) (vty
, 0);
1322 /* Escape character. */
1323 if (vty
->escape
== VTY_ESCAPE
)
1325 vty_escape_map (buf
[i
], vty
);
1329 /* Pre-escape status. */
1330 if (vty
->escape
== VTY_PRE_ESCAPE
)
1335 vty
->escape
= VTY_ESCAPE
;
1338 vty_backward_word (vty
);
1339 vty
->escape
= VTY_NORMAL
;
1342 vty_forward_word (vty
);
1343 vty
->escape
= VTY_NORMAL
;
1346 vty_forward_kill_word (vty
);
1347 vty
->escape
= VTY_NORMAL
;
1351 vty_backward_kill_word (vty
);
1352 vty
->escape
= VTY_NORMAL
;
1355 vty
->escape
= VTY_NORMAL
;
1364 vty_beginning_of_line (vty
);
1367 vty_backward_char (vty
);
1370 vty_stop_input (vty
);
1373 vty_delete_char (vty
);
1376 vty_end_of_line (vty
);
1379 vty_forward_char (vty
);
1383 vty_delete_backward_char (vty
);
1386 vty_kill_line (vty
);
1389 vty_next_line (vty
);
1392 vty_previous_line (vty
);
1395 vty_transpose_chars (vty
);
1398 vty_kill_line_from_beginning (vty
);
1401 vty_backward_kill_word (vty
);
1404 vty_end_config (vty
);
1408 vty_out (vty
, "%s", VTY_NEWLINE
);
1412 vty_complete_command (vty
);
1415 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
1416 vty_self_insert (vty
, buf
[i
]);
1418 vty_describe_command (vty
);
1421 if (i
+ 1 < nbytes
&& buf
[i
+ 1] == '[')
1423 vty
->escape
= VTY_ESCAPE
;
1427 vty
->escape
= VTY_PRE_ESCAPE
;
1430 if (buf
[i
] > 31 && buf
[i
] < 127)
1431 vty_self_insert (vty
, buf
[i
]);
1437 if (vty
->status
== VTY_CLOSE
)
1441 vty_event (VTY_WRITE
, vty_sock
, vty
);
1442 vty_event (VTY_READ
, vty_sock
, vty
);
1447 /* Flush buffer to the vty. */
1449 vty_flush (struct thread
*thread
)
1453 int vty_sock
= THREAD_FD (thread
);
1454 struct vty
*vty
= THREAD_ARG (thread
);
1455 vty
->t_write
= NULL
;
1457 /* Tempolary disable read thread. */
1458 if (vty
->lines
== 0)
1461 thread_cancel (vty
->t_read
);
1465 /* Function execution continue. */
1466 if (vty
->status
== VTY_START
|| vty
->status
== VTY_CONTINUE
)
1468 if (vty
->status
== VTY_CONTINUE
)
1473 if (vty
->output_func
== NULL
)
1478 if (vty
->lines
== 0)
1484 buffer_flush_vty_all (vty
->obuf
, vty
->fd
, erase
, dont_more
);
1486 if (vty
->status
== VTY_CLOSE
)
1492 if (vty
->output_func
== NULL
)
1494 vty
->status
= VTY_NORMAL
;
1496 vty_event (VTY_WRITE
, vty_sock
, vty
);
1499 vty
->status
= VTY_MORE
;
1501 if (vty
->lines
== 0)
1503 if (vty
->output_func
== NULL
)
1504 vty_event (VTY_READ
, vty_sock
, vty
);
1507 if (vty
->output_func
)
1508 (*vty
->output_func
) (vty
, 0);
1509 vty_event (VTY_WRITE
, vty_sock
, vty
);
1515 if (vty
->status
== VTY_MORE
|| vty
->status
== VTY_MORELINE
)
1520 if (vty
->lines
== 0)
1521 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 25, 0, 1);
1522 else if (vty
->status
== VTY_MORELINE
)
1523 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
, 1, erase
, 0);
1525 buffer_flush_window (vty
->obuf
, vty
->fd
, vty
->width
,
1526 vty
->lines
>= 0 ? vty
->lines
: vty
->height
,
1529 if (buffer_empty (vty
->obuf
))
1531 if (vty
->status
== VTY_CLOSE
)
1535 vty
->status
= VTY_NORMAL
;
1537 if (vty
->lines
== 0)
1538 vty_event (VTY_READ
, vty_sock
, vty
);
1543 vty
->status
= VTY_MORE
;
1545 if (vty
->lines
== 0)
1546 vty_event (VTY_WRITE
, vty_sock
, vty
);
1553 /* Create new vty structure. */
1555 vty_create (int vty_sock
, union sockunion
*su
)
1559 /* Allocate new vty structure and set up default values. */
1562 vty
->type
= VTY_TERM
;
1563 vty
->address
= sockunion_su2str (su
);
1564 if (no_password_check
)
1567 vty
->node
= ENABLE_NODE
;
1569 vty
->node
= VIEW_NODE
;
1572 vty
->node
= AUTH_NODE
;
1575 vty_clear_buf (vty
);
1577 memset (vty
->hist
, 0, sizeof (vty
->hist
));
1580 vector_set_index (vtyvec
, vty_sock
, vty
);
1581 vty
->status
= VTY_NORMAL
;
1582 vty
->v_timeout
= vty_timeout_val
;
1583 if (host
.lines
>= 0)
1584 vty
->lines
= host
.lines
;
1588 vty
->iac_sb_in_progress
= 0;
1589 vty
->sb_buffer
= buffer_new (1024);
1591 if (! no_password_check
)
1593 /* Vty is not available if password isn't set. */
1594 if (host
.password
== NULL
&& host
.password_encrypt
== NULL
)
1596 vty_out (vty
, "Vty password is not set.%s", VTY_NEWLINE
);
1597 vty
->status
= VTY_CLOSE
;
1603 /* Say hello to the world. */
1605 if (! no_password_check
)
1606 vty_out (vty
, "%sUser Access Verification%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1608 /* Setting up terminal. */
1609 vty_will_echo (vty
);
1610 vty_will_suppress_go_ahead (vty
);
1612 vty_dont_linemode (vty
);
1613 vty_do_window_size (vty
);
1614 /* vty_dont_lflow_ahead (vty); */
1618 /* Add read/write thread. */
1619 vty_event (VTY_WRITE
, vty_sock
, vty
);
1620 vty_event (VTY_READ
, vty_sock
, vty
);
1625 /* Accept connection from the network. */
1627 vty_accept (struct thread
*thread
)
1635 struct prefix
*p
= NULL
;
1636 struct access_list
*acl
= NULL
;
1638 accept_sock
= THREAD_FD (thread
);
1640 /* We continue hearing vty socket. */
1641 vty_event (VTY_SERV
, accept_sock
, NULL
);
1643 memset (&su
, 0, sizeof (union sockunion
));
1645 /* We can handle IPv4 or IPv6 socket. */
1646 vty_sock
= sockunion_accept (accept_sock
, &su
);
1649 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1653 p
= sockunion2hostprefix (&su
);
1655 /* VTY's accesslist apply. */
1656 if (p
->family
== AF_INET
&& vty_accesslist_name
)
1658 if ((acl
= access_list_lookup (AFI_IP
, vty_accesslist_name
)) &&
1659 (access_list_apply (acl
, p
) == FILTER_DENY
))
1662 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1663 (buf
= sockunion_su2str (&su
)));
1667 /* continue accepting connections */
1668 vty_event (VTY_SERV
, accept_sock
, NULL
);
1677 /* VTY's ipv6 accesslist apply. */
1678 if (p
->family
== AF_INET6
&& vty_ipv6_accesslist_name
)
1680 if ((acl
= access_list_lookup (AFI_IP6
, vty_ipv6_accesslist_name
)) &&
1681 (access_list_apply (acl
, p
) == FILTER_DENY
))
1684 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1685 (buf
= sockunion_su2str (&su
)));
1689 /* continue accepting connections */
1690 vty_event (VTY_SERV
, accept_sock
, NULL
);
1697 #endif /* HAVE_IPV6 */
1702 ret
= setsockopt (vty_sock
, IPPROTO_TCP
, TCP_NODELAY
,
1703 (char *) &on
, sizeof (on
));
1705 zlog (NULL
, LOG_INFO
, "can't set sockopt to vty_sock : %s",
1708 vty
= vty_create (vty_sock
, &su
);
1713 #if defined(HAVE_IPV6) && !defined(NRL)
1715 vty_serv_sock_addrinfo (const char *hostname
, unsigned short port
)
1718 struct addrinfo req
;
1719 struct addrinfo
*ainfo
;
1720 struct addrinfo
*ainfo_save
;
1722 char port_str
[BUFSIZ
];
1724 memset (&req
, 0, sizeof (struct addrinfo
));
1725 req
.ai_flags
= AI_PASSIVE
;
1726 req
.ai_family
= AF_UNSPEC
;
1727 req
.ai_socktype
= SOCK_STREAM
;
1728 sprintf (port_str
, "%d", port
);
1729 port_str
[sizeof (port_str
) - 1] = '\0';
1731 ret
= getaddrinfo (hostname
, port_str
, &req
, &ainfo
);
1735 fprintf (stderr
, "getaddrinfo failed: %s\n", gai_strerror (ret
));
1743 if (ainfo
->ai_family
!= AF_INET
1745 && ainfo
->ai_family
!= AF_INET6
1746 #endif /* HAVE_IPV6 */
1750 sock
= socket (ainfo
->ai_family
, ainfo
->ai_socktype
, ainfo
->ai_protocol
);
1754 sockopt_reuseaddr (sock
);
1755 sockopt_reuseport (sock
);
1757 ret
= bind (sock
, ainfo
->ai_addr
, ainfo
->ai_addrlen
);
1760 close (sock
); /* Avoid sd leak. */
1764 ret
= listen (sock
, 3);
1767 close (sock
); /* Avoid sd leak. */
1771 vty_event (VTY_SERV
, sock
, NULL
);
1773 while ((ainfo
= ainfo
->ai_next
) != NULL
);
1775 freeaddrinfo (ainfo_save
);
1777 #endif /* HAVE_IPV6 && ! NRL */
1779 /* Make vty server socket. */
1781 vty_serv_sock_family (const char* addr
, unsigned short port
, int family
)
1788 memset (&su
, 0, sizeof (union sockunion
));
1789 su
.sa
.sa_family
= family
;
1794 naddr
=&su
.sin
.sin_addr
;
1797 naddr
=&su
.sin6
.sin6_addr
;
1802 switch(inet_pton(family
,addr
,naddr
))
1805 zlog_err("bad address %s",addr
);
1809 zlog_err("error translating address %s: %s",addr
,strerror(errno
));
1813 /* Make new socket. */
1814 accept_sock
= sockunion_stream_socket (&su
);
1815 if (accept_sock
< 0)
1818 /* This is server, so reuse address. */
1819 sockopt_reuseaddr (accept_sock
);
1820 sockopt_reuseport (accept_sock
);
1822 /* Bind socket to universal address and given port. */
1823 ret
= sockunion_bind (accept_sock
, &su
, port
, naddr
);
1826 zlog_warn("can't bind socket");
1827 close (accept_sock
); /* Avoid sd leak. */
1831 /* Listen socket under queue 3. */
1832 ret
= listen (accept_sock
, 3);
1835 zlog (NULL
, LOG_WARNING
, "can't listen socket");
1836 close (accept_sock
); /* Avoid sd leak. */
1840 /* Add vty server event. */
1841 vty_event (VTY_SERV
, accept_sock
, NULL
);
1845 /* For sockaddr_un. */
1848 /* VTY shell UNIX domain socket. */
1850 vty_serv_un (char *path
)
1854 struct sockaddr_un serv
;
1856 struct zprivs_ids_t ids
;
1858 /* First of all, unlink existing socket */
1862 old_mask
= umask (0007);
1864 /* Make UNIX domain socket. */
1865 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
1872 /* Make server socket. */
1873 memset (&serv
, 0, sizeof (struct sockaddr_un
));
1874 serv
.sun_family
= AF_UNIX
;
1875 strncpy (serv
.sun_path
, path
, strlen (path
));
1877 len
= serv
.sun_len
= SUN_LEN(&serv
);
1879 len
= sizeof (serv
.sun_family
) + strlen (serv
.sun_path
);
1880 #endif /* HAVE_SUN_LEN */
1882 ret
= bind (sock
, (struct sockaddr
*) &serv
, len
);
1886 close (sock
); /* Avoid sd leak. */
1890 ret
= listen (sock
, 5);
1894 close (sock
); /* Avoid sd leak. */
1900 zprivs_get_ids(&ids
);
1902 if (ids
.gid_vty
> 0)
1904 /* set group of socket */
1905 if ( chown (path
, -1, ids
.gid_vty
) )
1907 zlog_err ("vty_serv_un: could chown socket, %s",
1912 vty_event (VTYSH_SERV
, sock
, NULL
);
1915 /* #define VTYSH_DEBUG 1 */
1918 vtysh_accept (struct thread
*thread
)
1923 struct sockaddr_un client
;
1926 accept_sock
= THREAD_FD (thread
);
1928 vty_event (VTYSH_SERV
, accept_sock
, NULL
);
1930 memset (&client
, 0, sizeof (struct sockaddr_un
));
1931 client_len
= sizeof (struct sockaddr_un
);
1933 sock
= accept (accept_sock
, (struct sockaddr
*) &client
, &client_len
);
1937 zlog_warn ("can't accept vty socket : %s", strerror (errno
));
1942 printf ("VTY shell accept\n");
1943 #endif /* VTYSH_DEBUG */
1947 vty
->type
= VTY_SHELL_SERV
;
1948 vty
->node
= VIEW_NODE
;
1950 vty_event (VTYSH_READ
, sock
, vty
);
1956 vtysh_read (struct thread
*thread
)
1962 unsigned char buf
[VTY_READ_BUFSIZ
];
1963 u_char header
[4] = {0, 0, 0, 0};
1965 sock
= THREAD_FD (thread
);
1966 vty
= THREAD_ARG (thread
);
1969 nbytes
= read (sock
, buf
, VTY_READ_BUFSIZ
);
1974 printf ("close vtysh\n");
1975 #endif /* VTYSH_DEBUG */
1980 printf ("line: %s\n", buf
);
1981 #endif /* VTYSH_DEBUG */
1983 vty_ensure (vty
, nbytes
);
1984 memcpy (vty
->buf
, buf
, nbytes
);
1986 /* Pass this line to parser. */
1987 ret
= vty_execute (vty
);
1989 vty_clear_buf (vty
);
1991 /* Return result. */
1993 printf ("result: %d\n", ret
);
1994 printf ("vtysh node: %d\n", vty
->node
);
1995 #endif /* VTYSH_DEBUG */
1998 write (vty
->fd
, header
, 4);
2000 vty_event (VTYSH_READ
, sock
, vty
);
2006 /* Determine address family to bind. */
2008 vty_serv_sock (const char *addr
, unsigned short port
, char *path
)
2010 /* If port is set to 0, do not listen on TCP/IP at all! */
2016 vty_serv_sock_family (addr
, port
, AF_INET
);
2017 vty_serv_sock_family (addr
, port
, AF_INET6
);
2019 vty_serv_sock_addrinfo (addr
, port
);
2021 #else /* ! HAVE_IPV6 */
2022 vty_serv_sock_family (addr
,port
, AF_INET
);
2023 #endif /* HAVE_IPV6 */
2031 /* Close vty interface. */
2033 vty_close (struct vty
*vty
)
2037 /* Cancel threads.*/
2039 thread_cancel (vty
->t_read
);
2041 thread_cancel (vty
->t_write
);
2043 thread_cancel (vty
->t_timeout
);
2045 thread_cancel (vty
->t_output
);
2048 if (! buffer_empty (vty
->obuf
))
2049 buffer_flush_all (vty
->obuf
, vty
->fd
);
2051 /* Free input buffer. */
2052 buffer_free (vty
->obuf
);
2054 /* Free SB buffer. */
2056 buffer_free (vty
->sb_buffer
);
2058 /* Free command history. */
2059 for (i
= 0; i
< VTY_MAXHIST
; i
++)
2061 XFREE (MTYPE_VTY_HIST
, vty
->hist
[i
]);
2064 vector_unset (vtyvec
, vty
->fd
);
2071 XFREE (0, vty
->address
);
2073 XFREE (MTYPE_VTY
, vty
->buf
);
2075 /* Check configure. */
2076 vty_config_unlock (vty
);
2079 XFREE (MTYPE_VTY
, vty
);
2082 /* When time out occur output message then close connection. */
2084 vty_timeout (struct thread
*thread
)
2088 vty
= THREAD_ARG (thread
);
2089 vty
->t_timeout
= NULL
;
2093 buffer_reset (vty
->obuf
);
2094 vty_out (vty
, "%sVty connection is timed out.%s", VTY_NEWLINE
, VTY_NEWLINE
);
2096 /* Close connection. */
2097 vty
->status
= VTY_CLOSE
;
2103 /* Read up configuration file from file_name. */
2105 vty_read_file (FILE *confp
)
2111 vty
->fd
= 0; /* stdout */
2112 vty
->type
= VTY_TERM
;
2113 vty
->node
= CONFIG_NODE
;
2115 /* Execute configuration file */
2116 ret
= config_from_file (vty
, confp
);
2118 if ( !((ret
== CMD_SUCCESS
) || (ret
== CMD_ERR_NOTHING_TODO
)) )
2122 case CMD_ERR_AMBIGUOUS
:
2123 fprintf (stderr
, "Ambiguous command.\n");
2125 case CMD_ERR_NO_MATCH
:
2126 fprintf (stderr
, "There is no such command.\n");
2129 fprintf (stderr
, "Error occured during reading below line.\n%s\n",
2139 vty_use_backup_config (char *fullpath
)
2141 char *fullpath_sav
, *fullpath_tmp
;
2148 fullpath_sav
= malloc (strlen (fullpath
) + strlen (CONF_BACKUP_EXT
) + 1);
2149 strcpy (fullpath_sav
, fullpath
);
2150 strcat (fullpath_sav
, CONF_BACKUP_EXT
);
2151 if (stat (fullpath_sav
, &buf
) == -1)
2153 free (fullpath_sav
);
2157 fullpath_tmp
= malloc (strlen (fullpath
) + 8);
2158 sprintf (fullpath_tmp
, "%s.XXXXXX", fullpath
);
2160 /* Open file to configuration write. */
2161 tmp
= mkstemp (fullpath_tmp
);
2164 free (fullpath_sav
);
2165 free (fullpath_tmp
);
2169 sav
= open (fullpath_sav
, O_RDONLY
);
2172 free (fullpath_sav
);
2173 free (fullpath_tmp
);
2174 unlink (fullpath_tmp
);
2178 while((c
= read (sav
, buffer
, 512)) > 0)
2179 write (tmp
, buffer
, c
);
2184 if (link (fullpath_tmp
, fullpath
) == 0)
2185 ret
= fopen (fullpath
, "r");
2187 unlink (fullpath_tmp
);
2189 free (fullpath_sav
);
2190 free (fullpath_tmp
);
2191 return fopen (fullpath
, "r");
2194 /* Read up configuration file from file_name. */
2196 vty_read_config (char *config_file
,
2197 char *config_current_dir
,
2198 char *config_default_dir
)
2204 /* If -f flag specified. */
2205 if (config_file
!= NULL
)
2207 if (! IS_DIRECTORY_SEP (config_file
[0]))
2209 cwd
= getcwd (NULL
, MAXPATHLEN
);
2210 fullpath
= XMALLOC (MTYPE_TMP
,
2211 strlen (cwd
) + strlen (config_file
) + 2);
2212 sprintf (fullpath
, "%s/%s", cwd
, config_file
);
2215 fullpath
= config_file
;
2217 confp
= fopen (fullpath
, "r");
2221 confp
= vty_use_backup_config (fullpath
);
2223 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2226 fprintf (stderr
, "can't open configuration file [%s]\n",
2234 /* Relative path configuration file open. */
2235 if (config_current_dir
)
2237 confp
= fopen (config_current_dir
, "r");
2240 confp
= vty_use_backup_config (config_current_dir
);
2242 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2246 /* If there is no relative path exists, open system default file. */
2251 struct stat conf_stat
;
2253 /* !!!!PLEASE LEAVE!!!!
2254 This is NEEDED for use with vtysh -b, or else you can get
2255 a real configuration food fight with a lot garbage in the
2256 merged configuration file it creates coming from the per
2257 daemon configuration files. This also allows the daemons
2258 to start if there default configuration file is not
2259 present or ignore them, as needed when using vtysh -b to
2260 configure the daemons at boot - MAG */
2262 /* Stat for vtysh Zebra.conf, if found startup and wait for
2263 boot configuration */
2265 if ( strstr(config_default_dir
, "vtysh") == NULL
)
2267 ret
= stat (integrate_default
, &conf_stat
);
2275 confp
= fopen (config_default_dir
, "r");
2278 confp
= vty_use_backup_config (config_default_dir
);
2281 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2282 fullpath
= config_default_dir
;
2286 fprintf (stderr
, "can't open configuration file [%s]\n",
2287 config_default_dir
);
2292 fullpath
= config_default_dir
;
2296 /* Rleative path configuration file. */
2297 cwd
= getcwd (NULL
, MAXPATHLEN
);
2298 fullpath
= XMALLOC (MTYPE_TMP
,
2299 strlen (cwd
) + strlen (config_current_dir
) + 2);
2300 sprintf (fullpath
, "%s/%s", cwd
, config_current_dir
);
2303 vty_read_file (confp
);
2307 host_config_set (fullpath
);
2310 /* Small utility function which output log to the VTY. */
2312 vty_log (const char *proto_str
, const char *format
, va_list va
)
2317 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2318 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2320 vty_log_out (vty
, proto_str
, format
, va
);
2324 vty_config_lock (struct vty
*vty
)
2326 if (vty_config
== 0)
2335 vty_config_unlock (struct vty
*vty
)
2337 if (vty_config
== 1 && vty
->config
== 1)
2345 /* Master of the threads. */
2346 static struct thread_master
*master
;
2349 vty_event (enum event event
, int sock
, struct vty
*vty
)
2351 struct thread
*vty_serv_thread
;
2356 vty_serv_thread
= thread_add_read (master
, vty_accept
, vty
, sock
);
2357 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2361 thread_add_read (master
, vtysh_accept
, vty
, sock
);
2364 thread_add_read (master
, vtysh_read
, vty
, sock
);
2368 vty
->t_read
= thread_add_read (master
, vty_read
, vty
, sock
);
2370 /* Time out treatment. */
2374 thread_cancel (vty
->t_timeout
);
2376 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2381 vty
->t_write
= thread_add_write (master
, vty_flush
, vty
, sock
);
2383 case VTY_TIMEOUT_RESET
:
2386 thread_cancel (vty
->t_timeout
);
2387 vty
->t_timeout
= NULL
;
2392 thread_add_timer (master
, vty_timeout
, vty
, vty
->v_timeout
);
2401 "Display who is on vty\n")
2406 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2407 if ((v
= vector_slot (vtyvec
, i
)) != NULL
)
2408 vty_out (vty
, "%svty[%d] connected from %s.%s",
2409 v
->config
? "*" : " ",
2410 i
, v
->address
, VTY_NEWLINE
);
2414 /* Move to vty configuration mode. */
2418 "Configure a terminal line\n"
2419 "Virtual terminal\n")
2421 vty
->node
= VTY_NODE
;
2425 /* Set time out value. */
2427 exec_timeout (struct vty
*vty
, char *min_str
, char *sec_str
)
2429 unsigned long timeout
= 0;
2431 /* min_str and sec_str are already checked by parser. So it must be
2432 all digit string. */
2435 timeout
= strtol (min_str
, NULL
, 10);
2439 timeout
+= strtol (sec_str
, NULL
, 10);
2441 vty_timeout_val
= timeout
;
2442 vty
->v_timeout
= timeout
;
2443 vty_event (VTY_TIMEOUT_RESET
, 0, vty
);
2449 DEFUN (exec_timeout_min
,
2450 exec_timeout_min_cmd
,
2451 "exec-timeout <0-35791>",
2452 "Set timeout value\n"
2453 "Timeout value in minutes\n")
2455 return exec_timeout (vty
, argv
[0], NULL
);
2458 DEFUN (exec_timeout_sec
,
2459 exec_timeout_sec_cmd
,
2460 "exec-timeout <0-35791> <0-2147483>",
2461 "Set the EXEC timeout\n"
2462 "Timeout in minutes\n"
2463 "Timeout in seconds\n")
2465 return exec_timeout (vty
, argv
[0], argv
[1]);
2468 DEFUN (no_exec_timeout
,
2469 no_exec_timeout_cmd
,
2472 "Set the EXEC timeout\n")
2474 return exec_timeout (vty
, NULL
, NULL
);
2477 /* Set vty access class. */
2478 DEFUN (vty_access_class
,
2479 vty_access_class_cmd
,
2480 "access-class WORD",
2481 "Filter connections based on an IP access list\n"
2484 if (vty_accesslist_name
)
2485 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2487 vty_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2492 /* Clear vty access class. */
2493 DEFUN (no_vty_access_class
,
2494 no_vty_access_class_cmd
,
2495 "no access-class [WORD]",
2497 "Filter connections based on an IP access list\n"
2500 if (! vty_accesslist_name
|| (argc
&& strcmp(vty_accesslist_name
, argv
[0])))
2502 vty_out (vty
, "Access-class is not currently applied to vty%s",
2507 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2509 vty_accesslist_name
= NULL
;
2515 /* Set vty access class. */
2516 DEFUN (vty_ipv6_access_class
,
2517 vty_ipv6_access_class_cmd
,
2518 "ipv6 access-class WORD",
2520 "Filter connections based on an IP access list\n"
2521 "IPv6 access list\n")
2523 if (vty_ipv6_accesslist_name
)
2524 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2526 vty_ipv6_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2531 /* Clear vty access class. */
2532 DEFUN (no_vty_ipv6_access_class
,
2533 no_vty_ipv6_access_class_cmd
,
2534 "no ipv6 access-class [WORD]",
2537 "Filter connections based on an IP access list\n"
2538 "IPv6 access list\n")
2540 if (! vty_ipv6_accesslist_name
||
2541 (argc
&& strcmp(vty_ipv6_accesslist_name
, argv
[0])))
2543 vty_out (vty
, "IPv6 access-class is not currently applied to vty%s",
2548 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2550 vty_ipv6_accesslist_name
= NULL
;
2554 #endif /* HAVE_IPV6 */
2560 "Enable password checking\n")
2562 no_password_check
= 0;
2566 DEFUN (no_vty_login
,
2570 "Enable password checking\n")
2572 no_password_check
= 1;
2576 DEFUN (service_advanced_vty
,
2577 service_advanced_vty_cmd
,
2578 "service advanced-vty",
2579 "Set up miscellaneous service\n"
2580 "Enable advanced mode vty interface\n")
2586 DEFUN (no_service_advanced_vty
,
2587 no_service_advanced_vty_cmd
,
2588 "no service advanced-vty",
2590 "Set up miscellaneous service\n"
2591 "Enable advanced mode vty interface\n")
2597 DEFUN (terminal_monitor
,
2598 terminal_monitor_cmd
,
2600 "Set terminal line parameters\n"
2601 "Copy debug output to the current terminal line\n")
2607 DEFUN (terminal_no_monitor
,
2608 terminal_no_monitor_cmd
,
2609 "terminal no monitor",
2610 "Set terminal line parameters\n"
2612 "Copy debug output to the current terminal line\n")
2618 DEFUN (show_history
,
2622 "Display the session command history\n")
2626 for (index
= vty
->hindex
+ 1; index
!= vty
->hindex
;)
2628 if (index
== VTY_MAXHIST
)
2634 if (vty
->hist
[index
] != NULL
)
2635 vty_out (vty
, " %s%s", vty
->hist
[index
], VTY_NEWLINE
);
2643 /* Display current configuration. */
2645 vty_config_write (struct vty
*vty
)
2647 vty_out (vty
, "line vty%s", VTY_NEWLINE
);
2649 if (vty_accesslist_name
)
2650 vty_out (vty
, " access-class %s%s",
2651 vty_accesslist_name
, VTY_NEWLINE
);
2653 if (vty_ipv6_accesslist_name
)
2654 vty_out (vty
, " ipv6 access-class %s%s",
2655 vty_ipv6_accesslist_name
, VTY_NEWLINE
);
2658 if (vty_timeout_val
!= VTY_TIMEOUT_DEFAULT
)
2659 vty_out (vty
, " exec-timeout %ld %ld%s",
2660 vty_timeout_val
/ 60,
2661 vty_timeout_val
% 60, VTY_NEWLINE
);
2664 if (no_password_check
)
2665 vty_out (vty
, " no login%s", VTY_NEWLINE
);
2667 vty_out (vty
, "!%s", VTY_NEWLINE
);
2672 struct cmd_node vty_node
=
2675 "%s(config-line)# ",
2678 /* Reset all VTY status. */
2684 struct thread
*vty_serv_thread
;
2686 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2687 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2689 buffer_reset (vty
->obuf
);
2690 vty
->status
= VTY_CLOSE
;
2694 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2695 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2697 thread_cancel (vty_serv_thread
);
2698 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2702 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2704 if (vty_accesslist_name
)
2706 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2707 vty_accesslist_name
= NULL
;
2710 if (vty_ipv6_accesslist_name
)
2712 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2713 vty_ipv6_accesslist_name
= NULL
;
2717 /* for ospf6d easy temprary reload function */
2718 /* vty_reset + close accept socket */
2724 struct thread
*vty_serv_thread
;
2726 for (i
= 0; i
< vector_max (vtyvec
); i
++)
2727 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2729 buffer_reset (vty
->obuf
);
2730 vty
->status
= VTY_CLOSE
;
2734 for (i
= 0; i
< vector_max (Vvty_serv_thread
); i
++)
2735 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
2737 thread_cancel (vty_serv_thread
);
2738 vector_slot (Vvty_serv_thread
, i
) = NULL
;
2742 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
2744 if (vty_accesslist_name
)
2746 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2747 vty_accesslist_name
= NULL
;
2750 if (vty_ipv6_accesslist_name
)
2752 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2753 vty_ipv6_accesslist_name
= NULL
;
2762 cwd
= getcwd (NULL
, MAXPATHLEN
);
2764 vty_cwd
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + 1);
2765 strcpy (vty_cwd
, cwd
);
2775 vty_shell (struct vty
*vty
)
2777 return vty
->type
== VTY_SHELL
? 1 : 0;
2781 vty_shell_serv (struct vty
*vty
)
2783 return vty
->type
== VTY_SHELL_SERV
? 1 : 0;
2789 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2792 /* Install vty's own commands like `who' command. */
2794 vty_init (struct thread_master
*master_thread
)
2796 /* For further configuration read, preserve current directory. */
2799 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
2801 master
= master_thread
;
2803 /* Initilize server thread vector. */
2804 Vvty_serv_thread
= vector_init (VECTOR_MIN_SIZE
);
2806 /* Install bgp top node. */
2807 install_node (&vty_node
, vty_config_write
);
2809 install_element (VIEW_NODE
, &config_who_cmd
);
2810 install_element (VIEW_NODE
, &show_history_cmd
);
2811 install_element (ENABLE_NODE
, &config_who_cmd
);
2812 install_element (CONFIG_NODE
, &line_vty_cmd
);
2813 install_element (CONFIG_NODE
, &service_advanced_vty_cmd
);
2814 install_element (CONFIG_NODE
, &no_service_advanced_vty_cmd
);
2815 install_element (CONFIG_NODE
, &show_history_cmd
);
2816 install_element (ENABLE_NODE
, &terminal_monitor_cmd
);
2817 install_element (ENABLE_NODE
, &terminal_no_monitor_cmd
);
2818 install_element (ENABLE_NODE
, &show_history_cmd
);
2820 install_default (VTY_NODE
);
2821 install_element (VTY_NODE
, &exec_timeout_min_cmd
);
2822 install_element (VTY_NODE
, &exec_timeout_sec_cmd
);
2823 install_element (VTY_NODE
, &no_exec_timeout_cmd
);
2824 install_element (VTY_NODE
, &vty_access_class_cmd
);
2825 install_element (VTY_NODE
, &no_vty_access_class_cmd
);
2826 install_element (VTY_NODE
, &vty_login_cmd
);
2827 install_element (VTY_NODE
, &no_vty_login_cmd
);
2829 install_element (VTY_NODE
, &vty_ipv6_access_class_cmd
);
2830 install_element (VTY_NODE
, &no_vty_ipv6_access_class_cmd
);
2831 #endif /* HAVE_IPV6 */