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"
40 #include <arpa/telnet.h>
43 DEFINE_MTYPE_STATIC(LIB
, VTY
, "VTY")
44 DEFINE_MTYPE_STATIC(LIB
, VTY_OUT_BUF
, "VTY output buffer")
45 DEFINE_MTYPE_STATIC(LIB
, VTY_HIST
, "VTY history")
61 static void vty_event (enum event
, int, struct vty
*);
63 /* Extern host structure from command.c */
64 extern struct host host
;
66 /* Vector which store each vty structure. */
69 /* Vty timeout value. */
70 static unsigned long vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
72 /* Vty access-class command */
73 static char *vty_accesslist_name
= NULL
;
75 /* Vty access-calss for IPv6. */
76 static char *vty_ipv6_accesslist_name
= NULL
;
78 /* VTY server thread. */
79 static vector Vvty_serv_thread
;
81 /* Current directory. */
85 static int vty_config
;
87 /* Login password check. */
88 static int no_password_check
= 0;
90 /* Restrict unauthenticated logins? */
91 static const u_char restricted_mode_default
= 0;
92 static u_char restricted_mode
= 0;
94 /* Integrated configuration file path */
95 char integrate_default
[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG
;
97 static int do_log_commands
= 0;
99 /* VTY standard output function. */
101 vty_out (struct vty
*vty
, const char *format
, ...)
111 va_start (args
, format
);
112 vprintf (format
, args
);
117 /* Try to write to initial buffer. */
118 va_start (args
, format
);
119 len
= vsnprintf (buf
, sizeof(buf
), format
, args
);
122 /* Initial buffer is not enough. */
123 if (len
< 0 || len
>= size
)
132 p
= XREALLOC (MTYPE_VTY_OUT_BUF
, p
, size
);
136 va_start (args
, format
);
137 len
= vsnprintf (p
, size
, format
, args
);
140 if (len
> -1 && len
< size
)
145 /* When initial buffer is enough to store all output. */
149 /* Pointer p must point out buffer. */
150 buffer_put (vty
->obuf
, (u_char
*) p
, len
);
152 /* If p is not different with buf, it is allocated buffer. */
154 XFREE (MTYPE_VTY_OUT_BUF
, p
);
161 vty_log_out (struct vty
*vty
, const char *level
, const char *proto_str
,
162 const char *format
, struct timestamp_control
*ctl
, va_list va
)
168 if (!ctl
->already_rendered
)
170 ctl
->len
= quagga_timestamp(ctl
->precision
, ctl
->buf
, sizeof(ctl
->buf
));
171 ctl
->already_rendered
= 1;
173 if (ctl
->len
+1 >= sizeof(buf
))
175 memcpy(buf
, ctl
->buf
, len
= ctl
->len
);
180 ret
= snprintf(buf
+len
, sizeof(buf
)-len
, "%s: %s: ", level
, proto_str
);
182 ret
= snprintf(buf
+len
, sizeof(buf
)-len
, "%s: ", proto_str
);
183 if ((ret
< 0) || ((size_t)(len
+= ret
) >= sizeof(buf
)))
186 if (((ret
= vsnprintf(buf
+len
, sizeof(buf
)-len
, format
, va
)) < 0) ||
187 ((size_t)((len
+= ret
)+2) > sizeof(buf
)))
193 if (write(vty
->wfd
, buf
, len
) < 0)
195 if (ERRNO_IO_RETRY(errno
))
196 /* Kernel buffer is full, probably too much debugging output, so just
197 drop the data and ignore. */
199 /* Fatal I/O error. */
200 vty
->monitor
= 0; /* disable monitoring to avoid infinite recursion */
201 zlog_warn("%s: write failed to vty client fd %d, closing: %s",
202 __func__
, vty
->fd
, safe_strerror(errno
));
203 buffer_reset(vty
->obuf
);
204 /* cannot call vty_close, because a parent routine may still try
205 to access the vty struct */
206 vty
->status
= VTY_CLOSE
;
207 shutdown(vty
->fd
, SHUT_RDWR
);
213 /* Output current time to the vty. */
215 vty_time_print (struct vty
*vty
, int cr
)
217 char buf
[QUAGGA_TIMESTAMP_LEN
];
219 if (quagga_timestamp(0, buf
, sizeof(buf
)) == 0)
221 zlog (NULL
, LOG_INFO
, "quagga_timestamp error");
225 vty_out (vty
, "%s\n", buf
);
227 vty_out (vty
, "%s ", buf
);
232 /* Say hello to vty interface. */
234 vty_hello (struct vty
*vty
)
241 f
= fopen (host
.motdfile
, "r");
244 while (fgets (buf
, sizeof (buf
), f
))
247 /* work backwards to ignore trailling isspace() */
248 for (s
= buf
+ strlen (buf
); (s
> buf
) && isspace ((int)*(s
- 1));
251 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
256 vty_out (vty
, "MOTD file not found%s", VTY_NEWLINE
);
259 vty_out (vty
, "%s", host
.motd
);
262 /* Put out prompt and wait input from user. */
264 vty_prompt (struct vty
*vty
)
266 struct utsname names
;
269 if (vty
->type
== VTY_TERM
)
271 hostname
= host
.name
;
275 hostname
= names
.nodename
;
277 vty_out (vty
, cmd_prompt (vty
->node
), hostname
);
281 /* Send WILL TELOPT_ECHO to remote server. */
283 vty_will_echo (struct vty
*vty
)
285 unsigned char cmd
[] = { IAC
, WILL
, TELOPT_ECHO
, '\0' };
286 vty_out (vty
, "%s", cmd
);
289 /* Make suppress Go-Ahead telnet option. */
291 vty_will_suppress_go_ahead (struct vty
*vty
)
293 unsigned char cmd
[] = { IAC
, WILL
, TELOPT_SGA
, '\0' };
294 vty_out (vty
, "%s", cmd
);
297 /* Make don't use linemode over telnet. */
299 vty_dont_linemode (struct vty
*vty
)
301 unsigned char cmd
[] = { IAC
, DONT
, TELOPT_LINEMODE
, '\0' };
302 vty_out (vty
, "%s", cmd
);
305 /* Use window size. */
307 vty_do_window_size (struct vty
*vty
)
309 unsigned char cmd
[] = { IAC
, DO
, TELOPT_NAWS
, '\0' };
310 vty_out (vty
, "%s", cmd
);
313 #if 0 /* Currently not used. */
314 /* Make don't use lflow vty interface. */
316 vty_dont_lflow_ahead (struct vty
*vty
)
318 unsigned char cmd
[] = { IAC
, DONT
, TELOPT_LFLOW
, '\0' };
319 vty_out (vty
, "%s", cmd
);
323 /* Allocate new vty struct. */
327 struct vty
*new = XCALLOC (MTYPE_VTY
, sizeof (struct vty
));
329 new->obuf
= buffer_new(0); /* Use default buffer size. */
330 new->buf
= XCALLOC (MTYPE_VTY
, VTY_BUFSIZ
);
331 new->error_buf
= XCALLOC (MTYPE_VTY
, VTY_BUFSIZ
);
332 new->max
= VTY_BUFSIZ
;
337 /* Authentication of vty */
339 vty_auth (struct vty
*vty
, char *buf
)
342 enum node_type next_node
= 0;
344 char *crypt (const char *, const char *);
350 passwd
= host
.password_encrypt
;
352 passwd
= host
.password
;
354 next_node
= host
.enable
? VIEW_NODE
: ENABLE_NODE
;
356 next_node
= VIEW_NODE
;
358 case AUTH_ENABLE_NODE
:
360 passwd
= host
.enable_encrypt
;
362 passwd
= host
.enable
;
363 next_node
= ENABLE_NODE
;
370 fail
= strcmp (crypt(buf
, passwd
), passwd
);
372 fail
= strcmp (buf
, passwd
);
380 vty
->node
= next_node
; /* Success ! */
387 if (vty
->node
== AUTH_NODE
)
389 vty_out (vty
, "%% Bad passwords, too many failures!%s", VTY_NEWLINE
);
390 vty
->status
= VTY_CLOSE
;
394 /* AUTH_ENABLE_NODE */
396 vty_out (vty
, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE
);
397 vty
->node
= restricted_mode
? RESTRICTED_NODE
: VIEW_NODE
;
403 /* Command execution over the vty interface. */
405 vty_command (struct vty
*vty
, char *buf
)
409 const char *protocolname
;
413 * Log non empty command lines
419 /* Skip white spaces. */
420 while (isspace ((int) *cp
) && *cp
!= '\0')
423 if (cp
!= NULL
&& *cp
!= '\0')
426 char vty_str
[VTY_BUFSIZ
];
427 char prompt_str
[VTY_BUFSIZ
];
429 /* format the base vty info */
430 snprintf(vty_str
, sizeof(vty_str
), "vty[??]@%s", vty
->address
);
432 for (i
= 0; i
< vector_active (vtyvec
); i
++)
433 if (vty
== vector_slot (vtyvec
, i
))
435 snprintf(vty_str
, sizeof(vty_str
), "vty[%d]@%s",
440 /* format the prompt */
441 snprintf(prompt_str
, sizeof(prompt_str
), cmd_prompt (vty
->node
), vty_str
);
443 /* now log the command */
444 zlog(NULL
, LOG_ERR
, "%s%s", prompt_str
, buf
);
446 /* Split readline string up into the vector */
447 vline
= cmd_make_strvec (buf
);
452 #ifdef CONSUMED_TIME_CHECK
456 unsigned long realtime
, cputime
;
459 #endif /* CONSUMED_TIME_CHECK */
461 ret
= cmd_execute_command (vline
, vty
, NULL
, 0);
463 /* Get the name of the protocol if any */
465 protocolname
= zlog_proto_names
[zlog_default
->protocol
];
467 protocolname
= zlog_proto_names
[ZLOG_NONE
];
469 #ifdef CONSUMED_TIME_CHECK
471 if ((realtime
= thread_consumed_time(&after
, &before
, &cputime
)) >
473 /* Warn about CPU hog that must be fixed. */
474 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
475 realtime
/1000, cputime
/1000, buf
);
477 #endif /* CONSUMED_TIME_CHECK */
479 if (ret
!= CMD_SUCCESS
)
483 if (vty
->type
== VTY_FILE
)
484 vty_out (vty
, "Warning...%s", VTY_NEWLINE
);
486 case CMD_ERR_AMBIGUOUS
:
487 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
489 case CMD_ERR_NO_MATCH
:
490 vty_out (vty
, "%% [%s] Unknown command: %s%s", protocolname
, buf
, VTY_NEWLINE
);
492 case CMD_ERR_INCOMPLETE
:
493 vty_out (vty
, "%% Command incomplete.%s", VTY_NEWLINE
);
496 cmd_free_strvec (vline
);
501 static const char telnet_backward_char
= 0x08;
502 static const char telnet_space_char
= ' ';
504 /* Basic function to write buffer to vty. */
506 vty_write (struct vty
*vty
, const char *buf
, size_t nbytes
)
508 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
511 /* Should we do buffering here ? And make vty_flush (vty) ? */
512 buffer_put (vty
->obuf
, buf
, nbytes
);
515 /* Ensure length of input buffer. Is buffer is short, double it. */
517 vty_ensure (struct vty
*vty
, int length
)
519 if (vty
->max
<= length
)
522 vty
->buf
= XREALLOC (MTYPE_VTY
, vty
->buf
, vty
->max
);
523 vty
->error_buf
= XREALLOC (MTYPE_VTY
, vty
->error_buf
, vty
->max
);
527 /* Basic function to insert character into vty. */
529 vty_self_insert (struct vty
*vty
, char c
)
534 vty_ensure (vty
, vty
->length
+ 1);
535 length
= vty
->length
- vty
->cp
;
536 memmove (&vty
->buf
[vty
->cp
+ 1], &vty
->buf
[vty
->cp
], length
);
537 vty
->buf
[vty
->cp
] = c
;
539 vty_write (vty
, &vty
->buf
[vty
->cp
], length
+ 1);
540 for (i
= 0; i
< length
; i
++)
541 vty_write (vty
, &telnet_backward_char
, 1);
547 /* Self insert character 'c' in overwrite mode. */
549 vty_self_insert_overwrite (struct vty
*vty
, char c
)
551 vty_ensure (vty
, vty
->length
+ 1);
552 vty
->buf
[vty
->cp
++] = c
;
554 if (vty
->cp
> vty
->length
)
557 if ((vty
->node
== AUTH_NODE
) || (vty
->node
== AUTH_ENABLE_NODE
))
560 vty_write (vty
, &c
, 1);
563 /* Insert a word into vty interface with overwrite mode. */
565 vty_insert_word_overwrite (struct vty
*vty
, char *str
)
567 int len
= strlen (str
);
568 vty_write (vty
, str
, len
);
569 strcpy (&vty
->buf
[vty
->cp
], str
);
571 vty
->length
= vty
->cp
;
574 /* Forward character. */
576 vty_forward_char (struct vty
*vty
)
578 if (vty
->cp
< vty
->length
)
580 vty_write (vty
, &vty
->buf
[vty
->cp
], 1);
585 /* Backward character. */
587 vty_backward_char (struct vty
*vty
)
592 vty_write (vty
, &telnet_backward_char
, 1);
596 /* Move to the beginning of the line. */
598 vty_beginning_of_line (struct vty
*vty
)
601 vty_backward_char (vty
);
604 /* Move to the end of the line. */
606 vty_end_of_line (struct vty
*vty
)
608 while (vty
->cp
< vty
->length
)
609 vty_forward_char (vty
);
612 static void vty_kill_line_from_beginning (struct vty
*);
613 static void vty_redraw_line (struct vty
*);
615 /* Print command line history. This function is called from
616 vty_next_line and vty_previous_line. */
618 vty_history_print (struct vty
*vty
)
622 vty_kill_line_from_beginning (vty
);
624 /* Get previous line from history buffer */
625 length
= strlen (vty
->hist
[vty
->hp
]);
626 memcpy (vty
->buf
, vty
->hist
[vty
->hp
], length
);
627 vty
->cp
= vty
->length
= length
;
629 /* Redraw current line */
630 vty_redraw_line (vty
);
633 /* Show next command line history. */
635 vty_next_line (struct vty
*vty
)
639 if (vty
->hp
== vty
->hindex
)
642 /* Try is there history exist or not. */
644 if (try_index
== (VTY_MAXHIST
- 1))
649 /* If there is not history return. */
650 if (vty
->hist
[try_index
] == NULL
)
655 vty_history_print (vty
);
658 /* Show previous command line history. */
660 vty_previous_line (struct vty
*vty
)
666 try_index
= VTY_MAXHIST
- 1;
670 if (vty
->hist
[try_index
] == NULL
)
675 vty_history_print (vty
);
678 /* This function redraw all of the command line character. */
680 vty_redraw_line (struct vty
*vty
)
682 vty_write (vty
, vty
->buf
, vty
->length
);
683 vty
->cp
= vty
->length
;
688 vty_forward_word (struct vty
*vty
)
690 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
691 vty_forward_char (vty
);
693 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
694 vty_forward_char (vty
);
697 /* Backward word without skipping training space. */
699 vty_backward_pure_word (struct vty
*vty
)
701 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
702 vty_backward_char (vty
);
707 vty_backward_word (struct vty
*vty
)
709 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
710 vty_backward_char (vty
);
712 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
713 vty_backward_char (vty
);
716 /* When '^D' is typed at the beginning of the line we move to the down
719 vty_down_level (struct vty
*vty
)
721 vty_out (vty
, "%s", VTY_NEWLINE
);
722 (*config_exit_cmd
.func
)(NULL
, vty
, 0, NULL
);
727 /* When '^Z' is received from vty, move down to the enable mode. */
729 vty_end_config (struct vty
*vty
)
731 vty_out (vty
, "%s", VTY_NEWLINE
);
737 case RESTRICTED_NODE
:
749 case BGP_ENCAPV6_NODE
:
760 case LDP_IPV4_IFACE_NODE
:
761 case LDP_IPV6_IFACE_NODE
:
763 case LDP_PSEUDOWIRE_NODE
:
766 case KEYCHAIN_KEY_NODE
:
770 vty_config_unlock (vty
);
771 vty
->node
= ENABLE_NODE
;
774 /* Unknown node, we have to ignore it. */
782 /* Delete a charcter at the current point. */
784 vty_delete_char (struct vty
*vty
)
789 if (vty
->length
== 0)
791 vty_down_level (vty
);
795 if (vty
->cp
== vty
->length
)
796 return; /* completion need here? */
798 size
= vty
->length
- vty
->cp
;
801 memmove (&vty
->buf
[vty
->cp
], &vty
->buf
[vty
->cp
+ 1], size
- 1);
802 vty
->buf
[vty
->length
] = '\0';
804 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
807 vty_write (vty
, &vty
->buf
[vty
->cp
], size
- 1);
808 vty_write (vty
, &telnet_space_char
, 1);
810 for (i
= 0; i
< size
; i
++)
811 vty_write (vty
, &telnet_backward_char
, 1);
814 /* Delete a character before the point. */
816 vty_delete_backward_char (struct vty
*vty
)
821 vty_backward_char (vty
);
822 vty_delete_char (vty
);
825 /* Kill rest of line from current point. */
827 vty_kill_line (struct vty
*vty
)
832 size
= vty
->length
- vty
->cp
;
837 for (i
= 0; i
< size
; i
++)
838 vty_write (vty
, &telnet_space_char
, 1);
839 for (i
= 0; i
< size
; i
++)
840 vty_write (vty
, &telnet_backward_char
, 1);
842 memset (&vty
->buf
[vty
->cp
], 0, size
);
843 vty
->length
= vty
->cp
;
846 /* Kill line from the beginning. */
848 vty_kill_line_from_beginning (struct vty
*vty
)
850 vty_beginning_of_line (vty
);
854 /* Delete a word before the point. */
856 vty_forward_kill_word (struct vty
*vty
)
858 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] == ' ')
859 vty_delete_char (vty
);
860 while (vty
->cp
!= vty
->length
&& vty
->buf
[vty
->cp
] != ' ')
861 vty_delete_char (vty
);
864 /* Delete a word before the point. */
866 vty_backward_kill_word (struct vty
*vty
)
868 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] == ' ')
869 vty_delete_backward_char (vty
);
870 while (vty
->cp
> 0 && vty
->buf
[vty
->cp
- 1] != ' ')
871 vty_delete_backward_char (vty
);
874 /* Transpose chars before or at the point. */
876 vty_transpose_chars (struct vty
*vty
)
880 /* If length is short or point is near by the beginning of line then
882 if (vty
->length
< 2 || vty
->cp
< 1)
885 /* In case of point is located at the end of the line. */
886 if (vty
->cp
== vty
->length
)
888 c1
= vty
->buf
[vty
->cp
- 1];
889 c2
= vty
->buf
[vty
->cp
- 2];
891 vty_backward_char (vty
);
892 vty_backward_char (vty
);
893 vty_self_insert_overwrite (vty
, c1
);
894 vty_self_insert_overwrite (vty
, c2
);
898 c1
= vty
->buf
[vty
->cp
];
899 c2
= vty
->buf
[vty
->cp
- 1];
901 vty_backward_char (vty
);
902 vty_self_insert_overwrite (vty
, c1
);
903 vty_self_insert_overwrite (vty
, c2
);
907 /* Do completion at vty interface. */
909 vty_complete_command (struct vty
*vty
)
913 char **matched
= NULL
;
916 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
919 vline
= cmd_make_strvec (vty
->buf
);
923 /* In case of 'help \t'. */
924 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
925 vector_set (vline
, NULL
);
927 matched
= cmd_complete_command_lib (vline
, vty
, &ret
, 1);
929 cmd_free_strvec (vline
);
931 vty_out (vty
, "%s", VTY_NEWLINE
);
934 case CMD_ERR_AMBIGUOUS
:
935 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
937 vty_redraw_line (vty
);
939 case CMD_ERR_NO_MATCH
:
940 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
942 vty_redraw_line (vty
);
944 case CMD_COMPLETE_FULL_MATCH
:
946 vty_redraw_line (vty
);
947 vty_backward_pure_word (vty
);
948 vty_insert_word_overwrite (vty
, matched
[0]);
949 vty_self_insert (vty
, ' ');
950 XFREE (MTYPE_TMP
, matched
[0]);
952 case CMD_COMPLETE_MATCH
:
954 vty_redraw_line (vty
);
955 vty_backward_pure_word (vty
);
956 vty_insert_word_overwrite (vty
, matched
[0]);
957 XFREE (MTYPE_TMP
, matched
[0]);
958 vector_only_index_free (matched
);
961 case CMD_COMPLETE_LIST_MATCH
:
962 for (i
= 0; matched
[i
] != NULL
; i
++)
964 if (i
!= 0 && ((i
% 6) == 0))
965 vty_out (vty
, "%s", VTY_NEWLINE
);
966 vty_out (vty
, "%-10s ", matched
[i
]);
967 XFREE (MTYPE_TMP
, matched
[i
]);
969 vty_out (vty
, "%s", VTY_NEWLINE
);
972 vty_redraw_line (vty
);
974 case CMD_ERR_NOTHING_TODO
:
976 vty_redraw_line (vty
);
982 vector_only_index_free (matched
);
986 vty_describe_fold (struct vty
*vty
, int cmd_width
,
987 unsigned int desc_width
, struct cmd_token
*token
)
993 cmd
= token
->cmd
[0] == '.' ? token
->cmd
+ 1 : token
->cmd
;
997 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, token
->desc
, VTY_NEWLINE
);
1001 buf
= XCALLOC (MTYPE_TMP
, strlen (token
->desc
) + 1);
1003 for (p
= token
->desc
; strlen (p
) > desc_width
; p
+= pos
+ 1)
1005 for (pos
= desc_width
; pos
> 0; pos
--)
1006 if (*(p
+ pos
) == ' ')
1012 strncpy (buf
, p
, pos
);
1014 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, buf
, VTY_NEWLINE
);
1019 vty_out (vty
, " %-*s %s%s", cmd_width
, cmd
, p
, VTY_NEWLINE
);
1021 XFREE (MTYPE_TMP
, buf
);
1024 /* Describe matched command function. */
1026 vty_describe_command (struct vty
*vty
)
1031 unsigned int i
, width
, desc_width
;
1032 struct cmd_token
*token
, *token_cr
= NULL
;
1034 vline
= cmd_make_strvec (vty
->buf
);
1036 /* In case of '> ?'. */
1039 vline
= vector_init (1);
1040 vector_set (vline
, NULL
);
1043 if (isspace ((int) vty
->buf
[vty
->length
- 1]))
1044 vector_set (vline
, NULL
);
1046 describe
= cmd_describe_command (vline
, vty
, &ret
);
1048 vty_out (vty
, "%s", VTY_NEWLINE
);
1050 /* Ambiguous error. */
1053 case CMD_ERR_AMBIGUOUS
:
1054 vty_out (vty
, "%% Ambiguous command.%s", VTY_NEWLINE
);
1057 case CMD_ERR_NO_MATCH
:
1058 vty_out (vty
, "%% There is no matched command.%s", VTY_NEWLINE
);
1063 /* Get width of command string. */
1065 for (i
= 0; i
< vector_active (describe
); i
++)
1066 if ((token
= vector_slot (describe
, i
)) != NULL
)
1070 if (token
->cmd
[0] == '\0')
1073 len
= strlen (token
->cmd
);
1074 if (token
->cmd
[0] == '.')
1081 /* Get width of description string. */
1082 desc_width
= vty
->width
- (width
+ 6);
1084 /* Print out description. */
1085 for (i
= 0; i
< vector_active (describe
); i
++)
1086 if ((token
= vector_slot (describe
, i
)) != NULL
)
1088 if (token
->cmd
[0] == '\0')
1091 if (strcmp (token
->cmd
, command_cr
) == 0)
1098 vty_out (vty
, " %-s%s",
1099 token
->cmd
[0] == '.' ? token
->cmd
+ 1 : token
->cmd
,
1101 else if (desc_width
>= strlen (token
->desc
))
1102 vty_out (vty
, " %-*s %s%s", width
,
1103 token
->cmd
[0] == '.' ? token
->cmd
+ 1 : token
->cmd
,
1104 token
->desc
, VTY_NEWLINE
);
1106 vty_describe_fold (vty
, width
, desc_width
, token
);
1109 vty_out (vty
, " %-*s %s%s", width
1110 desc
->cmd
[0] == '.' ? desc
->cmd
+ 1 : desc
->cmd
,
1111 desc
->str
? desc
->str
: "", VTY_NEWLINE
);
1115 if ((token
= token_cr
))
1118 vty_out (vty
, " %-s%s",
1119 token
->cmd
[0] == '.' ? token
->cmd
+ 1 : token
->cmd
,
1121 else if (desc_width
>= strlen (token
->desc
))
1122 vty_out (vty
, " %-*s %s%s", width
,
1123 token
->cmd
[0] == '.' ? token
->cmd
+ 1 : token
->cmd
,
1124 token
->desc
, VTY_NEWLINE
);
1126 vty_describe_fold (vty
, width
, desc_width
, token
);
1130 cmd_free_strvec (vline
);
1132 vector_free (describe
);
1135 vty_redraw_line (vty
);
1139 vty_clear_buf (struct vty
*vty
)
1141 memset (vty
->buf
, 0, vty
->max
);
1144 /* ^C stop current input and do not add command line to the history. */
1146 vty_stop_input (struct vty
*vty
)
1148 vty
->cp
= vty
->length
= 0;
1149 vty_clear_buf (vty
);
1150 vty_out (vty
, "%s", VTY_NEWLINE
);
1156 case RESTRICTED_NODE
:
1157 /* Nothing to do. */
1160 case INTERFACE_NODE
:
1171 case LDP_IPV4_IFACE_NODE
:
1172 case LDP_IPV6_IFACE_NODE
:
1173 case LDP_L2VPN_NODE
:
1174 case LDP_PSEUDOWIRE_NODE
:
1177 case KEYCHAIN_KEY_NODE
:
1181 vty_config_unlock (vty
);
1182 vty
->node
= ENABLE_NODE
;
1185 /* Unknown node, we have to ignore it. */
1190 /* Set history pointer to the latest one. */
1191 vty
->hp
= vty
->hindex
;
1194 /* Add current command line to the history buffer. */
1196 vty_hist_add (struct vty
*vty
)
1200 if (vty
->length
== 0)
1203 index
= vty
->hindex
? vty
->hindex
- 1 : VTY_MAXHIST
- 1;
1205 /* Ignore the same string as previous one. */
1206 if (vty
->hist
[index
])
1207 if (strcmp (vty
->buf
, vty
->hist
[index
]) == 0)
1209 vty
->hp
= vty
->hindex
;
1213 /* Insert history entry. */
1214 if (vty
->hist
[vty
->hindex
])
1215 XFREE (MTYPE_VTY_HIST
, vty
->hist
[vty
->hindex
]);
1216 vty
->hist
[vty
->hindex
] = XSTRDUP (MTYPE_VTY_HIST
, vty
->buf
);
1218 /* History index rotation. */
1220 if (vty
->hindex
== VTY_MAXHIST
)
1223 vty
->hp
= vty
->hindex
;
1226 /* #define TELNET_OPTION_DEBUG */
1228 /* Get telnet window size. */
1230 vty_telnet_option (struct vty
*vty
, unsigned char *buf
, int nbytes
)
1232 #ifdef TELNET_OPTION_DEBUG
1235 for (i
= 0; i
< nbytes
; i
++)
1240 vty_out (vty
, "IAC ");
1243 vty_out (vty
, "WILL ");
1246 vty_out (vty
, "WONT ");
1249 vty_out (vty
, "DO ");
1252 vty_out (vty
, "DONT ");
1255 vty_out (vty
, "SB ");
1258 vty_out (vty
, "SE ");
1261 vty_out (vty
, "TELOPT_ECHO %s", VTY_NEWLINE
);
1264 vty_out (vty
, "TELOPT_SGA %s", VTY_NEWLINE
);
1267 vty_out (vty
, "TELOPT_NAWS %s", VTY_NEWLINE
);
1270 vty_out (vty
, "%x ", buf
[i
]);
1274 vty_out (vty
, "%s", VTY_NEWLINE
);
1276 #endif /* TELNET_OPTION_DEBUG */
1282 vty
->iac_sb_in_progress
= 1;
1287 if (!vty
->iac_sb_in_progress
)
1290 if ((vty
->sb_len
== 0) || (vty
->sb_buf
[0] == '\0'))
1292 vty
->iac_sb_in_progress
= 0;
1295 switch (vty
->sb_buf
[0])
1298 if (vty
->sb_len
!= TELNET_NAWS_SB_LEN
)
1299 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1300 "should send %d characters, but we received %lu",
1301 TELNET_NAWS_SB_LEN
, (u_long
)vty
->sb_len
);
1302 else if (sizeof(vty
->sb_buf
) < TELNET_NAWS_SB_LEN
)
1303 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1304 "too small to handle the telnet NAWS option",
1305 (u_long
)sizeof(vty
->sb_buf
), TELNET_NAWS_SB_LEN
);
1308 vty
->width
= ((vty
->sb_buf
[1] << 8)|vty
->sb_buf
[2]);
1309 vty
->height
= ((vty
->sb_buf
[3] << 8)|vty
->sb_buf
[4]);
1310 #ifdef TELNET_OPTION_DEBUG
1311 vty_out(vty
, "TELNET NAWS window size negotiation completed: "
1312 "width %d, height %d%s",
1313 vty
->width
, vty
->height
, VTY_NEWLINE
);
1318 vty
->iac_sb_in_progress
= 0;
1328 /* Execute current command line. */
1330 vty_execute (struct vty
*vty
)
1339 case AUTH_ENABLE_NODE
:
1340 vty_auth (vty
, vty
->buf
);
1343 ret
= vty_command (vty
, vty
->buf
);
1344 if (vty
->type
== VTY_TERM
)
1349 /* Clear command line buffer. */
1350 vty
->cp
= vty
->length
= 0;
1351 vty_clear_buf (vty
);
1353 if (vty
->status
!= VTY_CLOSE
)
1359 #define CONTROL(X) ((X) - '@')
1360 #define VTY_NORMAL 0
1361 #define VTY_PRE_ESCAPE 1
1362 #define VTY_ESCAPE 2
1364 /* Escape character command map. */
1366 vty_escape_map (unsigned char c
, struct vty
*vty
)
1371 vty_previous_line (vty
);
1374 vty_next_line (vty
);
1377 vty_forward_char (vty
);
1380 vty_backward_char (vty
);
1386 /* Go back to normal mode. */
1387 vty
->escape
= VTY_NORMAL
;
1390 /* Quit print out to the buffer. */
1392 vty_buffer_reset (struct vty
*vty
)
1394 buffer_reset (vty
->obuf
);
1396 vty_redraw_line (vty
);
1399 /* Read data via vty socket. */
1401 vty_read (struct thread
*thread
)
1405 unsigned char buf
[VTY_READ_BUFSIZ
];
1407 int vty_sock
= THREAD_FD (thread
);
1408 struct vty
*vty
= THREAD_ARG (thread
);
1411 /* Read raw data from socket */
1412 if ((nbytes
= read (vty
->fd
, buf
, VTY_READ_BUFSIZ
)) <= 0)
1416 if (ERRNO_IO_RETRY(errno
))
1418 vty_event (VTY_READ
, vty_sock
, vty
);
1421 vty
->monitor
= 0; /* disable monitoring to avoid infinite recursion */
1422 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1423 __func__
, vty
->fd
, safe_strerror(errno
));
1424 buffer_reset(vty
->obuf
);
1426 vty
->status
= VTY_CLOSE
;
1429 for (i
= 0; i
< nbytes
; i
++)
1444 if (vty
->iac_sb_in_progress
&& !vty
->iac
)
1446 if (vty
->sb_len
< sizeof(vty
->sb_buf
))
1447 vty
->sb_buf
[vty
->sb_len
] = buf
[i
];
1454 /* In case of telnet command */
1456 ret
= vty_telnet_option (vty
, buf
+ i
, nbytes
- i
);
1463 if (vty
->status
== VTY_MORE
)
1470 vty_buffer_reset (vty
);
1472 #if 0 /* More line does not work for "show ip bgp". */
1475 vty
->status
= VTY_MORELINE
;
1484 /* Escape character. */
1485 if (vty
->escape
== VTY_ESCAPE
)
1487 vty_escape_map (buf
[i
], vty
);
1491 /* Pre-escape status. */
1492 if (vty
->escape
== VTY_PRE_ESCAPE
)
1497 vty
->escape
= VTY_ESCAPE
;
1500 vty_backward_word (vty
);
1501 vty
->escape
= VTY_NORMAL
;
1504 vty_forward_word (vty
);
1505 vty
->escape
= VTY_NORMAL
;
1508 vty_forward_kill_word (vty
);
1509 vty
->escape
= VTY_NORMAL
;
1513 vty_backward_kill_word (vty
);
1514 vty
->escape
= VTY_NORMAL
;
1517 vty
->escape
= VTY_NORMAL
;
1526 vty_beginning_of_line (vty
);
1529 vty_backward_char (vty
);
1532 vty_stop_input (vty
);
1535 vty_delete_char (vty
);
1538 vty_end_of_line (vty
);
1541 vty_forward_char (vty
);
1545 vty_delete_backward_char (vty
);
1548 vty_kill_line (vty
);
1551 vty_next_line (vty
);
1554 vty_previous_line (vty
);
1557 vty_transpose_chars (vty
);
1560 vty_kill_line_from_beginning (vty
);
1563 vty_backward_kill_word (vty
);
1566 vty_end_config (vty
);
1570 vty_out (vty
, "%s", VTY_NEWLINE
);
1574 vty_complete_command (vty
);
1577 if (vty
->node
== AUTH_NODE
|| vty
->node
== AUTH_ENABLE_NODE
)
1578 vty_self_insert (vty
, buf
[i
]);
1580 vty_describe_command (vty
);
1583 if (i
+ 1 < nbytes
&& buf
[i
+ 1] == '[')
1585 vty
->escape
= VTY_ESCAPE
;
1589 vty
->escape
= VTY_PRE_ESCAPE
;
1592 if (buf
[i
] > 31 && buf
[i
] < 127)
1593 vty_self_insert (vty
, buf
[i
]);
1599 if (vty
->status
== VTY_CLOSE
)
1603 vty_event (VTY_WRITE
, vty
->wfd
, vty
);
1604 vty_event (VTY_READ
, vty_sock
, vty
);
1609 /* Flush buffer to the vty. */
1611 vty_flush (struct thread
*thread
)
1614 buffer_status_t flushrc
;
1615 int vty_sock
= THREAD_FD (thread
);
1616 struct vty
*vty
= THREAD_ARG (thread
);
1618 vty
->t_write
= NULL
;
1620 /* Tempolary disable read thread. */
1621 if ((vty
->lines
== 0) && vty
->t_read
)
1623 thread_cancel (vty
->t_read
);
1627 /* Function execution continue. */
1628 erase
= ((vty
->status
== VTY_MORE
|| vty
->status
== VTY_MORELINE
));
1630 /* N.B. if width is 0, that means we don't know the window size. */
1631 if ((vty
->lines
== 0) || (vty
->width
== 0) || (vty
->height
== 0))
1632 flushrc
= buffer_flush_available(vty
->obuf
, vty_sock
);
1633 else if (vty
->status
== VTY_MORELINE
)
1634 flushrc
= buffer_flush_window(vty
->obuf
, vty_sock
, vty
->width
,
1637 flushrc
= buffer_flush_window(vty
->obuf
, vty_sock
, vty
->width
,
1638 vty
->lines
>= 0 ? vty
->lines
:
1644 vty
->monitor
= 0; /* disable monitoring to avoid infinite recursion */
1645 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1647 buffer_reset(vty
->obuf
);
1651 if (vty
->status
== VTY_CLOSE
)
1655 vty
->status
= VTY_NORMAL
;
1656 if (vty
->lines
== 0)
1657 vty_event (VTY_READ
, vty_sock
, vty
);
1660 case BUFFER_PENDING
:
1661 /* There is more data waiting to be written. */
1662 vty
->status
= VTY_MORE
;
1663 if (vty
->lines
== 0)
1664 vty_event (VTY_WRITE
, vty_sock
, vty
);
1671 /* allocate and initialise vty */
1673 vty_new_init (int vty_sock
)
1679 vty
->wfd
= vty_sock
;
1680 vty
->type
= VTY_TERM
;
1681 vty
->node
= AUTH_NODE
;
1684 vty_clear_buf (vty
);
1686 memset (vty
->hist
, 0, sizeof (vty
->hist
));
1689 vector_set_index (vtyvec
, vty_sock
, vty
);
1690 vty
->status
= VTY_NORMAL
;
1693 vty
->iac_sb_in_progress
= 0;
1699 /* Create new vty structure. */
1701 vty_create (int vty_sock
, union sockunion
*su
)
1703 char buf
[SU_ADDRSTRLEN
];
1706 sockunion2str(su
, buf
, SU_ADDRSTRLEN
);
1708 /* Allocate new vty structure and set up default values. */
1709 vty
= vty_new_init (vty_sock
);
1711 /* configurable parameters not part of basic init */
1712 vty
->v_timeout
= vty_timeout_val
;
1713 strcpy (vty
->address
, buf
);
1714 if (no_password_check
)
1716 if (restricted_mode
)
1717 vty
->node
= RESTRICTED_NODE
;
1718 else if (host
.advanced
)
1719 vty
->node
= ENABLE_NODE
;
1721 vty
->node
= VIEW_NODE
;
1723 if (host
.lines
>= 0)
1724 vty
->lines
= host
.lines
;
1726 if (! no_password_check
)
1728 /* Vty is not available if password isn't set. */
1729 if (host
.password
== NULL
&& host
.password_encrypt
== NULL
)
1731 vty_out (vty
, "Vty password is not set.%s", VTY_NEWLINE
);
1732 vty
->status
= VTY_CLOSE
;
1738 /* Say hello to the world. */
1740 if (! no_password_check
)
1741 vty_out (vty
, "%sUser Access Verification%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1743 /* Setting up terminal. */
1744 vty_will_echo (vty
);
1745 vty_will_suppress_go_ahead (vty
);
1747 vty_dont_linemode (vty
);
1748 vty_do_window_size (vty
);
1749 /* vty_dont_lflow_ahead (vty); */
1753 /* Add read/write thread. */
1754 vty_event (VTY_WRITE
, vty_sock
, vty
);
1755 vty_event (VTY_READ
, vty_sock
, vty
);
1760 /* create vty for stdio */
1761 static struct termios stdio_orig_termios
;
1762 static struct vty
*stdio_vty
= NULL
;
1763 static void (*stdio_vty_atclose
)(void);
1766 vty_stdio_reset (void)
1770 tcsetattr (0, TCSANOW
, &stdio_orig_termios
);
1773 if (stdio_vty_atclose
)
1774 stdio_vty_atclose ();
1775 stdio_vty_atclose
= NULL
;
1780 vty_stdio (void (*atclose
)())
1783 struct termios termios
;
1785 /* refuse creating two vtys on stdio */
1789 vty
= stdio_vty
= vty_new_init (0);
1790 stdio_vty_atclose
= atclose
;
1793 /* always have stdio vty in a known _unchangeable_ state, don't want config
1794 * to have any effect here to make sure scripting this works as intended */
1795 vty
->node
= ENABLE_NODE
;
1797 strcpy (vty
->address
, "console");
1799 if (!tcgetattr (0, &stdio_orig_termios
))
1801 termios
= stdio_orig_termios
;
1802 termios
.c_iflag
&= ~(IGNBRK
| BRKINT
| PARMRK
| ISTRIP
1803 | INLCR
| IGNCR
| ICRNL
| IXON
);
1804 termios
.c_oflag
&= ~OPOST
;
1805 termios
.c_lflag
&= ~(ECHO
| ECHONL
| ICANON
| ISIG
| IEXTEN
);
1806 termios
.c_cflag
&= ~(CSIZE
| PARENB
);
1807 termios
.c_cflag
|= CS8
;
1808 tcsetattr (0, TCSANOW
, &termios
);
1813 /* Add read/write thread. */
1814 vty_event (VTY_WRITE
, 1, vty
);
1815 vty_event (VTY_READ
, 0, vty
);
1820 /* Accept connection from the network. */
1822 vty_accept (struct thread
*thread
)
1830 struct access_list
*acl
= NULL
;
1831 char buf
[SU_ADDRSTRLEN
];
1833 accept_sock
= THREAD_FD (thread
);
1835 /* We continue hearing vty socket. */
1836 vty_event (VTY_SERV
, accept_sock
, NULL
);
1838 memset (&su
, 0, sizeof (union sockunion
));
1840 /* We can handle IPv4 or IPv6 socket. */
1841 vty_sock
= sockunion_accept (accept_sock
, &su
);
1844 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno
));
1847 set_nonblocking(vty_sock
);
1849 sockunion2hostprefix (&su
, &p
);
1851 /* VTY's accesslist apply. */
1852 if (p
.family
== AF_INET
&& vty_accesslist_name
)
1854 if ((acl
= access_list_lookup (AFI_IP
, vty_accesslist_name
)) &&
1855 (access_list_apply (acl
, &p
) == FILTER_DENY
))
1857 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1858 sockunion2str (&su
, buf
, SU_ADDRSTRLEN
));
1861 /* continue accepting connections */
1862 vty_event (VTY_SERV
, accept_sock
, NULL
);
1869 /* VTY's ipv6 accesslist apply. */
1870 if (p
.family
== AF_INET6
&& vty_ipv6_accesslist_name
)
1872 if ((acl
= access_list_lookup (AFI_IP6
, vty_ipv6_accesslist_name
)) &&
1873 (access_list_apply (acl
, &p
) == FILTER_DENY
))
1875 zlog (NULL
, LOG_INFO
, "Vty connection refused from %s",
1876 sockunion2str (&su
, buf
, SU_ADDRSTRLEN
));
1879 /* continue accepting connections */
1880 vty_event (VTY_SERV
, accept_sock
, NULL
);
1885 #endif /* HAVE_IPV6 */
1888 ret
= setsockopt (vty_sock
, IPPROTO_TCP
, TCP_NODELAY
,
1889 (char *) &on
, sizeof (on
));
1891 zlog (NULL
, LOG_INFO
, "can't set sockopt to vty_sock : %s",
1892 safe_strerror (errno
));
1894 zlog (NULL
, LOG_INFO
, "Vty connection from %s",
1895 sockunion2str (&su
, buf
, SU_ADDRSTRLEN
));
1897 vty_create (vty_sock
, &su
);
1904 vty_serv_sock_addrinfo (const char *hostname
, unsigned short port
)
1907 struct addrinfo req
;
1908 struct addrinfo
*ainfo
;
1909 struct addrinfo
*ainfo_save
;
1911 char port_str
[BUFSIZ
];
1913 memset (&req
, 0, sizeof (struct addrinfo
));
1914 req
.ai_flags
= AI_PASSIVE
;
1915 req
.ai_family
= AF_UNSPEC
;
1916 req
.ai_socktype
= SOCK_STREAM
;
1917 sprintf (port_str
, "%d", port
);
1918 port_str
[sizeof (port_str
) - 1] = '\0';
1920 ret
= getaddrinfo (hostname
, port_str
, &req
, &ainfo
);
1924 fprintf (stderr
, "getaddrinfo failed: %s\n", gai_strerror (ret
));
1932 if (ainfo
->ai_family
!= AF_INET
1934 && ainfo
->ai_family
!= AF_INET6
1935 #endif /* HAVE_IPV6 */
1939 sock
= socket (ainfo
->ai_family
, ainfo
->ai_socktype
, ainfo
->ai_protocol
);
1943 sockopt_v6only (ainfo
->ai_family
, sock
);
1944 sockopt_reuseaddr (sock
);
1945 sockopt_reuseport (sock
);
1947 ret
= bind (sock
, ainfo
->ai_addr
, ainfo
->ai_addrlen
);
1950 close (sock
); /* Avoid sd leak. */
1954 ret
= listen (sock
, 3);
1957 close (sock
); /* Avoid sd leak. */
1961 vty_event (VTY_SERV
, sock
, NULL
);
1963 while ((ainfo
= ainfo
->ai_next
) != NULL
);
1965 freeaddrinfo (ainfo_save
);
1967 #else /* HAVE_IPV6 */
1969 /* Make vty server socket. */
1971 vty_serv_sock_family (const char* addr
, unsigned short port
, int family
)
1978 memset (&su
, 0, sizeof (union sockunion
));
1979 su
.sa
.sa_family
= family
;
1984 naddr
=&su
.sin
.sin_addr
;
1988 naddr
=&su
.sin6
.sin6_addr
;
1994 switch(inet_pton(family
,addr
,naddr
))
1997 zlog_err("bad address %s",addr
);
2001 zlog_err("error translating address %s: %s",addr
,safe_strerror(errno
));
2005 /* Make new socket. */
2006 accept_sock
= sockunion_stream_socket (&su
);
2007 if (accept_sock
< 0)
2010 /* This is server, so reuse address. */
2011 sockopt_reuseaddr (accept_sock
);
2012 sockopt_reuseport (accept_sock
);
2014 /* Bind socket to universal address and given port. */
2015 ret
= sockunion_bind (accept_sock
, &su
, port
, naddr
);
2018 zlog_warn("can't bind socket");
2019 close (accept_sock
); /* Avoid sd leak. */
2023 /* Listen socket under queue 3. */
2024 ret
= listen (accept_sock
, 3);
2027 zlog (NULL
, LOG_WARNING
, "can't listen socket");
2028 close (accept_sock
); /* Avoid sd leak. */
2032 /* Add vty server event. */
2033 vty_event (VTY_SERV
, accept_sock
, NULL
);
2035 #endif /* HAVE_IPV6 */
2038 /* For sockaddr_un. */
2041 /* VTY shell UNIX domain socket. */
2043 vty_serv_un (const char *path
)
2047 struct sockaddr_un serv
;
2049 struct zprivs_ids_t ids
;
2051 /* First of all, unlink existing socket */
2055 old_mask
= umask (0007);
2057 /* Make UNIX domain socket. */
2058 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
2061 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno
));
2065 /* Make server socket. */
2066 memset (&serv
, 0, sizeof (struct sockaddr_un
));
2067 serv
.sun_family
= AF_UNIX
;
2068 strncpy (serv
.sun_path
, path
, strlen (path
));
2069 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
2070 len
= serv
.sun_len
= SUN_LEN(&serv
);
2072 len
= sizeof (serv
.sun_family
) + strlen (serv
.sun_path
);
2073 #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
2075 ret
= bind (sock
, (struct sockaddr
*) &serv
, len
);
2078 zlog_err("Cannot bind path %s: %s", path
, safe_strerror(errno
));
2079 close (sock
); /* Avoid sd leak. */
2083 ret
= listen (sock
, 5);
2086 zlog_err("listen(fd %d) failed: %s", sock
, safe_strerror(errno
));
2087 close (sock
); /* Avoid sd leak. */
2093 zprivs_get_ids(&ids
);
2095 if (ids
.gid_vty
> 0)
2097 /* set group of socket */
2098 if ( chown (path
, -1, ids
.gid_vty
) )
2100 zlog_err ("vty_serv_un: could chown socket, %s",
2101 safe_strerror (errno
) );
2105 vty_event (VTYSH_SERV
, sock
, NULL
);
2108 /* #define VTYSH_DEBUG 1 */
2111 vtysh_accept (struct thread
*thread
)
2116 struct sockaddr_un client
;
2119 accept_sock
= THREAD_FD (thread
);
2121 vty_event (VTYSH_SERV
, accept_sock
, NULL
);
2123 memset (&client
, 0, sizeof (struct sockaddr_un
));
2124 client_len
= sizeof (struct sockaddr_un
);
2126 sock
= accept (accept_sock
, (struct sockaddr
*) &client
,
2127 (socklen_t
*) &client_len
);
2131 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno
));
2135 if (set_nonblocking(sock
) < 0)
2137 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
2138 " %s, closing", sock
, safe_strerror (errno
));
2144 printf ("VTY shell accept\n");
2145 #endif /* VTYSH_DEBUG */
2150 vty
->type
= VTY_SHELL_SERV
;
2151 vty
->node
= VIEW_NODE
;
2153 vty_event (VTYSH_READ
, sock
, vty
);
2159 vtysh_flush(struct vty
*vty
)
2161 switch (buffer_flush_available(vty
->obuf
, vty
->wfd
))
2163 case BUFFER_PENDING
:
2164 vty_event(VTYSH_WRITE
, vty
->wfd
, vty
);
2167 vty
->monitor
= 0; /* disable monitoring to avoid infinite recursion */
2168 zlog_warn("%s: write error to fd %d, closing", __func__
, vty
->fd
);
2169 buffer_reset(vty
->obuf
);
2180 vtysh_read (struct thread
*thread
)
2186 unsigned char buf
[VTY_READ_BUFSIZ
];
2188 u_char header
[4] = {0, 0, 0, 0};
2190 sock
= THREAD_FD (thread
);
2191 vty
= THREAD_ARG (thread
);
2194 if ((nbytes
= read (sock
, buf
, VTY_READ_BUFSIZ
)) <= 0)
2198 if (ERRNO_IO_RETRY(errno
))
2200 vty_event (VTYSH_READ
, sock
, vty
);
2203 vty
->monitor
= 0; /* disable monitoring to avoid infinite recursion */
2204 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2205 __func__
, sock
, safe_strerror(errno
));
2207 buffer_reset(vty
->obuf
);
2210 printf ("close vtysh\n");
2211 #endif /* VTYSH_DEBUG */
2216 printf ("line: %.*s\n", nbytes
, buf
);
2217 #endif /* VTYSH_DEBUG */
2219 for (p
= buf
; p
< buf
+nbytes
; p
++)
2221 vty_ensure(vty
, vty
->length
+1);
2222 vty
->buf
[vty
->length
++] = *p
;
2225 /* Pass this line to parser. */
2226 ret
= vty_execute (vty
);
2227 /* Note that vty_execute clears the command buffer and resets
2228 vty->length to 0. */
2230 /* Return result. */
2232 printf ("result: %d\n", ret
);
2233 printf ("vtysh node: %d\n", vty
->node
);
2234 #endif /* VTYSH_DEBUG */
2237 buffer_put(vty
->obuf
, header
, 4);
2239 if (!vty
->t_write
&& (vtysh_flush(vty
) < 0))
2240 /* Try to flush results; exit if a write error occurs. */
2245 vty_event (VTYSH_READ
, sock
, vty
);
2251 vtysh_write (struct thread
*thread
)
2253 struct vty
*vty
= THREAD_ARG (thread
);
2255 vty
->t_write
= NULL
;
2262 /* Determine address family to bind. */
2264 vty_serv_sock (const char *addr
, unsigned short port
, const char *path
)
2266 /* If port is set to 0, do not listen on TCP/IP at all! */
2271 vty_serv_sock_addrinfo (addr
, port
);
2272 #else /* ! HAVE_IPV6 */
2273 vty_serv_sock_family (addr
,port
, AF_INET
);
2274 #endif /* HAVE_IPV6 */
2282 /* Close vty interface. Warning: call this only from functions that
2283 will be careful not to access the vty afterwards (since it has
2284 now been freed). This is safest from top-level functions (called
2285 directly by the thread dispatcher). */
2287 vty_close (struct vty
*vty
)
2291 /* Cancel threads.*/
2293 thread_cancel (vty
->t_read
);
2295 thread_cancel (vty
->t_write
);
2297 thread_cancel (vty
->t_timeout
);
2300 buffer_flush_all (vty
->obuf
, vty
->wfd
);
2302 /* Free input buffer. */
2303 buffer_free (vty
->obuf
);
2305 /* Free command history. */
2306 for (i
= 0; i
< VTY_MAXHIST
; i
++)
2308 XFREE (MTYPE_VTY_HIST
, vty
->hist
[i
]);
2311 vector_unset (vtyvec
, vty
->fd
);
2320 XFREE (MTYPE_VTY
, vty
->buf
);
2323 XFREE (MTYPE_VTY
, vty
->error_buf
);
2325 /* Check configure. */
2326 vty_config_unlock (vty
);
2329 XFREE (MTYPE_VTY
, vty
);
2332 /* When time out occur output message then close connection. */
2334 vty_timeout (struct thread
*thread
)
2338 vty
= THREAD_ARG (thread
);
2339 vty
->t_timeout
= NULL
;
2343 buffer_reset (vty
->obuf
);
2344 vty_out (vty
, "%sVty connection is timed out.%s", VTY_NEWLINE
, VTY_NEWLINE
);
2346 /* Close connection. */
2347 vty
->status
= VTY_CLOSE
;
2353 /* Read up configuration file from file_name. */
2355 vty_read_file (FILE *confp
)
2359 unsigned int line_num
= 0;
2362 vty
->wfd
= dup(STDERR_FILENO
); /* vty_close() will close this */
2365 /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
2366 vty
->wfd
= STDOUT_FILENO
;
2368 vty
->fd
= STDIN_FILENO
;
2369 vty
->type
= VTY_FILE
;
2370 vty
->node
= CONFIG_NODE
;
2372 /* Execute configuration file */
2373 ret
= config_from_file (vty
, confp
, &line_num
);
2375 /* Flush any previous errors before printing messages below */
2376 buffer_flush_all (vty
->obuf
, vty
->fd
);
2378 if ( !((ret
== CMD_SUCCESS
) || (ret
== CMD_ERR_NOTHING_TODO
)) )
2382 case CMD_ERR_AMBIGUOUS
:
2383 fprintf (stderr
, "*** Error reading config: Ambiguous command.\n");
2385 case CMD_ERR_NO_MATCH
:
2386 fprintf (stderr
, "*** Error reading config: There is no such command.\n");
2389 fprintf (stderr
, "*** Error occured processing line %u, below:\n%s\n",
2390 line_num
, vty
->error_buf
);
2397 vty_use_backup_config (char *fullpath
)
2399 char *fullpath_sav
, *fullpath_tmp
;
2406 fullpath_sav
= malloc (strlen (fullpath
) + strlen (CONF_BACKUP_EXT
) + 1);
2407 strcpy (fullpath_sav
, fullpath
);
2408 strcat (fullpath_sav
, CONF_BACKUP_EXT
);
2409 if (stat (fullpath_sav
, &buf
) == -1)
2411 free (fullpath_sav
);
2415 fullpath_tmp
= malloc (strlen (fullpath
) + 8);
2416 sprintf (fullpath_tmp
, "%s.XXXXXX", fullpath
);
2418 /* Open file to configuration write. */
2419 tmp
= mkstemp (fullpath_tmp
);
2422 free (fullpath_sav
);
2423 free (fullpath_tmp
);
2427 sav
= open (fullpath_sav
, O_RDONLY
);
2430 unlink (fullpath_tmp
);
2431 free (fullpath_sav
);
2432 free (fullpath_tmp
);
2436 while((c
= read (sav
, buffer
, 512)) > 0)
2438 if (write (tmp
, buffer
, c
) <= 0)
2440 free (fullpath_sav
);
2441 free (fullpath_tmp
);
2450 if (chmod(fullpath_tmp
, CONFIGFILE_MASK
) != 0)
2452 unlink (fullpath_tmp
);
2453 free (fullpath_sav
);
2454 free (fullpath_tmp
);
2458 if (link (fullpath_tmp
, fullpath
) == 0)
2459 ret
= fopen (fullpath
, "r");
2461 unlink (fullpath_tmp
);
2463 free (fullpath_sav
);
2464 free (fullpath_tmp
);
2468 /* Read up configuration file from file_name. */
2470 vty_read_config (char *config_file
,
2471 char *config_default_dir
)
2473 char cwd
[MAXPATHLEN
];
2478 /* If -f flag specified. */
2479 if (config_file
!= NULL
)
2481 if (! IS_DIRECTORY_SEP (config_file
[0]))
2483 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
2485 fprintf (stderr
, "Failure to determine Current Working Directory %d!\n", errno
);
2488 tmp
= XMALLOC (MTYPE_TMP
,
2489 strlen (cwd
) + strlen (config_file
) + 2);
2490 sprintf (tmp
, "%s/%s", cwd
, config_file
);
2494 fullpath
= config_file
;
2496 confp
= fopen (fullpath
, "r");
2500 fprintf (stderr
, "%s: failed to open configuration file %s: %s\n",
2501 __func__
, fullpath
, safe_strerror (errno
));
2503 confp
= vty_use_backup_config (fullpath
);
2505 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2508 fprintf (stderr
, "can't open configuration file [%s]\n",
2517 host_config_set (config_default_dir
);
2521 struct stat conf_stat
;
2523 /* !!!!PLEASE LEAVE!!!!
2524 * This is NEEDED for use with vtysh -b, or else you can get
2525 * a real configuration food fight with a lot garbage in the
2526 * merged configuration file it creates coming from the per
2527 * daemon configuration files. This also allows the daemons
2528 * to start if there default configuration file is not
2529 * present or ignore them, as needed when using vtysh -b to
2530 * configure the daemons at boot - MAG
2533 /* Stat for vtysh Zebra.conf, if found startup and wait for
2534 * boot configuration
2537 if ( strstr(config_default_dir
, "vtysh") == NULL
)
2539 ret
= stat (integrate_default
, &conf_stat
);
2541 goto tmp_free_and_out
;
2544 confp
= fopen (config_default_dir
, "r");
2547 fprintf (stderr
, "%s: failed to open configuration file %s: %s\n",
2548 __func__
, config_default_dir
, safe_strerror (errno
));
2550 confp
= vty_use_backup_config (config_default_dir
);
2553 fprintf (stderr
, "WARNING: using backup configuration file!\n");
2554 fullpath
= config_default_dir
;
2558 fprintf (stderr
, "can't open configuration file [%s]\n",
2559 config_default_dir
);
2560 goto tmp_free_and_out
;
2564 fullpath
= config_default_dir
;
2567 vty_read_file (confp
);
2571 host_config_set (fullpath
);
2575 XFREE (MTYPE_TMP
, fullpath
);
2578 /* Small utility function which output log to the VTY. */
2580 vty_log (const char *level
, const char *proto_str
,
2581 const char *format
, struct timestamp_control
*ctl
, va_list va
)
2589 for (i
= 0; i
< vector_active (vtyvec
); i
++)
2590 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
2595 vty_log_out (vty
, level
, proto_str
, format
, ctl
, ac
);
2600 /* Async-signal-safe version of vty_log for fixed strings. */
2602 vty_log_fixed (char *buf
, size_t len
)
2605 struct iovec iov
[2];
2606 char crlf
[4] = "\r\n";
2608 /* vty may not have been initialised */
2612 iov
[0].iov_base
= buf
;
2613 iov
[0].iov_len
= len
;
2614 iov
[1].iov_base
= crlf
;
2617 for (i
= 0; i
< vector_active (vtyvec
); i
++)
2620 if (((vty
= vector_slot (vtyvec
, i
)) != NULL
) && vty
->monitor
)
2621 /* N.B. We don't care about the return code, since process is
2622 most likely just about to die anyway. */
2623 if (writev(vty
->wfd
, iov
, 2) == -1)
2625 fprintf(stderr
, "Failure to writev: %d\n", errno
);
2632 vty_config_lock (struct vty
*vty
)
2634 if (vty_config
== 0)
2643 vty_config_unlock (struct vty
*vty
)
2645 if (vty_config
== 1 && vty
->config
== 1)
2653 /* Master of the threads. */
2654 static struct thread_master
*vty_master
;
2657 vty_event (enum event event
, int sock
, struct vty
*vty
)
2659 struct thread
*vty_serv_thread
;
2664 vty_serv_thread
= thread_add_read (vty_master
, vty_accept
, vty
, sock
);
2665 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2669 vty_serv_thread
= thread_add_read (vty_master
, vtysh_accept
, vty
, sock
);
2670 vector_set_index (Vvty_serv_thread
, sock
, vty_serv_thread
);
2673 vty
->t_read
= thread_add_read (vty_master
, vtysh_read
, vty
, sock
);
2676 vty
->t_write
= thread_add_write (vty_master
, vtysh_write
, vty
, sock
);
2680 vty
->t_read
= thread_add_read (vty_master
, vty_read
, vty
, sock
);
2682 /* Time out treatment. */
2686 thread_cancel (vty
->t_timeout
);
2688 thread_add_timer (vty_master
, vty_timeout
, vty
, vty
->v_timeout
);
2693 vty
->t_write
= thread_add_write (vty_master
, vty_flush
, vty
, sock
);
2695 case VTY_TIMEOUT_RESET
:
2698 thread_cancel (vty
->t_timeout
);
2699 vty
->t_timeout
= NULL
;
2704 thread_add_timer (vty_master
, vty_timeout
, vty
, vty
->v_timeout
);
2713 "Display who is on vty\n")
2718 for (i
= 0; i
< vector_active (vtyvec
); i
++)
2719 if ((v
= vector_slot (vtyvec
, i
)) != NULL
)
2720 vty_out (vty
, "%svty[%d] connected from %s.%s",
2721 v
->config
? "*" : " ",
2722 i
, v
->address
, VTY_NEWLINE
);
2726 /* Move to vty configuration mode. */
2730 "Configure a terminal line\n"
2731 "Virtual terminal\n")
2733 vty
->node
= VTY_NODE
;
2737 /* Set time out value. */
2739 exec_timeout (struct vty
*vty
, const char *min_str
, const char *sec_str
)
2741 unsigned long timeout
= 0;
2743 /* min_str and sec_str are already checked by parser. So it must be
2744 all digit string. */
2747 timeout
= strtol (min_str
, NULL
, 10);
2751 timeout
+= strtol (sec_str
, NULL
, 10);
2753 vty_timeout_val
= timeout
;
2754 vty
->v_timeout
= timeout
;
2755 vty_event (VTY_TIMEOUT_RESET
, 0, vty
);
2761 DEFUN (exec_timeout_min
,
2762 exec_timeout_min_cmd
,
2763 "exec-timeout <0-35791>",
2764 "Set timeout value\n"
2765 "Timeout value in minutes\n")
2767 return exec_timeout (vty
, argv
[0], NULL
);
2770 DEFUN (exec_timeout_sec
,
2771 exec_timeout_sec_cmd
,
2772 "exec-timeout <0-35791> <0-2147483>",
2773 "Set the EXEC timeout\n"
2774 "Timeout in minutes\n"
2775 "Timeout in seconds\n")
2777 return exec_timeout (vty
, argv
[0], argv
[1]);
2780 DEFUN (no_exec_timeout
,
2781 no_exec_timeout_cmd
,
2784 "Set the EXEC timeout\n")
2786 return exec_timeout (vty
, NULL
, NULL
);
2789 /* Set vty access class. */
2790 DEFUN (vty_access_class
,
2791 vty_access_class_cmd
,
2792 "access-class WORD",
2793 "Filter connections based on an IP access list\n"
2796 if (vty_accesslist_name
)
2797 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2799 vty_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2804 /* Clear vty access class. */
2805 DEFUN (no_vty_access_class
,
2806 no_vty_access_class_cmd
,
2807 "no access-class [WORD]",
2809 "Filter connections based on an IP access list\n"
2812 if (! vty_accesslist_name
|| (argc
&& strcmp(vty_accesslist_name
, argv
[0])))
2814 vty_out (vty
, "Access-class is not currently applied to vty%s",
2819 XFREE(MTYPE_VTY
, vty_accesslist_name
);
2821 vty_accesslist_name
= NULL
;
2827 /* Set vty access class. */
2828 DEFUN (vty_ipv6_access_class
,
2829 vty_ipv6_access_class_cmd
,
2830 "ipv6 access-class WORD",
2832 "Filter connections based on an IP access list\n"
2833 "IPv6 access list\n")
2835 if (vty_ipv6_accesslist_name
)
2836 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2838 vty_ipv6_accesslist_name
= XSTRDUP(MTYPE_VTY
, argv
[0]);
2843 /* Clear vty access class. */
2844 DEFUN (no_vty_ipv6_access_class
,
2845 no_vty_ipv6_access_class_cmd
,
2846 "no ipv6 access-class [WORD]",
2849 "Filter connections based on an IP access list\n"
2850 "IPv6 access list\n")
2852 if (! vty_ipv6_accesslist_name
||
2853 (argc
&& strcmp(vty_ipv6_accesslist_name
, argv
[0])))
2855 vty_out (vty
, "IPv6 access-class is not currently applied to vty%s",
2860 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
2862 vty_ipv6_accesslist_name
= NULL
;
2866 #endif /* HAVE_IPV6 */
2872 "Enable password checking\n")
2874 no_password_check
= 0;
2878 DEFUN (no_vty_login
,
2882 "Enable password checking\n")
2884 no_password_check
= 1;
2889 DEFUN (vty_restricted_mode
,
2890 vty_restricted_mode_cmd
,
2891 "anonymous restricted",
2892 "Restrict view commands available in anonymous, unauthenticated vty\n")
2894 restricted_mode
= 1;
2898 DEFUN (vty_no_restricted_mode
,
2899 vty_no_restricted_mode_cmd
,
2900 "no anonymous restricted",
2902 "Enable password checking\n")
2904 restricted_mode
= 0;
2908 DEFUN (service_advanced_vty
,
2909 service_advanced_vty_cmd
,
2910 "service advanced-vty",
2911 "Set up miscellaneous service\n"
2912 "Enable advanced mode vty interface\n")
2918 DEFUN (no_service_advanced_vty
,
2919 no_service_advanced_vty_cmd
,
2920 "no service advanced-vty",
2922 "Set up miscellaneous service\n"
2923 "Enable advanced mode vty interface\n")
2929 DEFUN (terminal_monitor
,
2930 terminal_monitor_cmd
,
2932 "Set terminal line parameters\n"
2933 "Copy debug output to the current terminal line\n")
2939 DEFUN (terminal_no_monitor
,
2940 terminal_no_monitor_cmd
,
2941 "terminal no monitor",
2942 "Set terminal line parameters\n"
2944 "Copy debug output to the current terminal line\n")
2950 ALIAS (terminal_no_monitor
,
2951 no_terminal_monitor_cmd
,
2952 "no terminal monitor",
2954 "Set terminal line parameters\n"
2955 "Copy debug output to the current terminal line\n")
2957 DEFUN (show_history
,
2961 "Display the session command history\n")
2965 for (index
= vty
->hindex
+ 1; index
!= vty
->hindex
;)
2967 if (index
== VTY_MAXHIST
)
2973 if (vty
->hist
[index
] != NULL
)
2974 vty_out (vty
, " %s%s", vty
->hist
[index
], VTY_NEWLINE
);
2983 DEFUN (log_commands
,
2987 "Log all commands (can't be unset without restart)\n")
2989 do_log_commands
= 1;
2993 /* Display current configuration. */
2995 vty_config_write (struct vty
*vty
)
2997 vty_out (vty
, "line vty%s", VTY_NEWLINE
);
2999 if (vty_accesslist_name
)
3000 vty_out (vty
, " access-class %s%s",
3001 vty_accesslist_name
, VTY_NEWLINE
);
3003 if (vty_ipv6_accesslist_name
)
3004 vty_out (vty
, " ipv6 access-class %s%s",
3005 vty_ipv6_accesslist_name
, VTY_NEWLINE
);
3008 if (vty_timeout_val
!= VTY_TIMEOUT_DEFAULT
)
3009 vty_out (vty
, " exec-timeout %ld %ld%s",
3010 vty_timeout_val
/ 60,
3011 vty_timeout_val
% 60, VTY_NEWLINE
);
3014 if (no_password_check
)
3015 vty_out (vty
, " no login%s", VTY_NEWLINE
);
3017 if (restricted_mode
!= restricted_mode_default
)
3019 if (restricted_mode_default
)
3020 vty_out (vty
, " no anonymous restricted%s", VTY_NEWLINE
);
3022 vty_out (vty
, " anonymous restricted%s", VTY_NEWLINE
);
3025 if (do_log_commands
)
3026 vty_out (vty
, "log commands%s", VTY_NEWLINE
);
3028 vty_out (vty
, "!%s", VTY_NEWLINE
);
3033 struct cmd_node vty_node
=
3036 "%s(config-line)# ",
3040 /* Reset all VTY status. */
3046 struct thread
*vty_serv_thread
;
3048 for (i
= 0; i
< vector_active (vtyvec
); i
++)
3049 if ((vty
= vector_slot (vtyvec
, i
)) != NULL
)
3051 buffer_reset (vty
->obuf
);
3052 vty
->status
= VTY_CLOSE
;
3056 for (i
= 0; i
< vector_active (Vvty_serv_thread
); i
++)
3057 if ((vty_serv_thread
= vector_slot (Vvty_serv_thread
, i
)) != NULL
)
3059 thread_cancel (vty_serv_thread
);
3060 vector_slot (Vvty_serv_thread
, i
) = NULL
;
3064 vty_timeout_val
= VTY_TIMEOUT_DEFAULT
;
3066 if (vty_accesslist_name
)
3068 XFREE(MTYPE_VTY
, vty_accesslist_name
);
3069 vty_accesslist_name
= NULL
;
3072 if (vty_ipv6_accesslist_name
)
3074 XFREE(MTYPE_VTY
, vty_ipv6_accesslist_name
);
3075 vty_ipv6_accesslist_name
= NULL
;
3082 char cwd
[MAXPATHLEN
];
3085 c
= getcwd (cwd
, MAXPATHLEN
);
3090 * At this point if these go wrong, more than likely
3091 * the whole world is coming down around us
3092 * Hence not worrying about it too much.
3094 if (!chdir (SYSCONFDIR
))
3096 fprintf(stderr
, "Failure to chdir to %s, errno: %d\n", SYSCONFDIR
, errno
);
3099 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
3101 fprintf(stderr
, "Failure to getcwd, errno: %d\n", errno
);
3106 vty_cwd
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + 1);
3107 strcpy (vty_cwd
, cwd
);
3117 vty_shell (struct vty
*vty
)
3119 return vty
->type
== VTY_SHELL
? 1 : 0;
3123 vty_shell_serv (struct vty
*vty
)
3125 return vty
->type
== VTY_SHELL_SERV
? 1 : 0;
3131 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
3134 /* Install vty's own commands like `who' command. */
3136 vty_init (struct thread_master
*master_thread
)
3138 /* For further configuration read, preserve current directory. */
3141 vtyvec
= vector_init (VECTOR_MIN_SIZE
);
3143 vty_master
= master_thread
;
3145 atexit (vty_stdio_reset
);
3147 /* Initilize server thread vector. */
3148 Vvty_serv_thread
= vector_init (VECTOR_MIN_SIZE
);
3150 /* Install bgp top node. */
3151 install_node (&vty_node
, vty_config_write
);
3153 install_element (RESTRICTED_NODE
, &config_who_cmd
);
3154 install_element (RESTRICTED_NODE
, &show_history_cmd
);
3155 install_element (VIEW_NODE
, &config_who_cmd
);
3156 install_element (VIEW_NODE
, &show_history_cmd
);
3157 install_element (ENABLE_NODE
, &config_who_cmd
);
3158 install_element (CONFIG_NODE
, &line_vty_cmd
);
3159 install_element (CONFIG_NODE
, &service_advanced_vty_cmd
);
3160 install_element (CONFIG_NODE
, &no_service_advanced_vty_cmd
);
3161 install_element (CONFIG_NODE
, &show_history_cmd
);
3162 install_element (CONFIG_NODE
, &log_commands_cmd
);
3163 install_element (ENABLE_NODE
, &terminal_monitor_cmd
);
3164 install_element (ENABLE_NODE
, &terminal_no_monitor_cmd
);
3165 install_element (ENABLE_NODE
, &no_terminal_monitor_cmd
);
3166 install_element (ENABLE_NODE
, &show_history_cmd
);
3168 install_default (VTY_NODE
);
3169 install_element (VTY_NODE
, &exec_timeout_min_cmd
);
3170 install_element (VTY_NODE
, &exec_timeout_sec_cmd
);
3171 install_element (VTY_NODE
, &no_exec_timeout_cmd
);
3172 install_element (VTY_NODE
, &vty_access_class_cmd
);
3173 install_element (VTY_NODE
, &no_vty_access_class_cmd
);
3174 install_element (VTY_NODE
, &vty_login_cmd
);
3175 install_element (VTY_NODE
, &no_vty_login_cmd
);
3176 install_element (VTY_NODE
, &vty_restricted_mode_cmd
);
3177 install_element (VTY_NODE
, &vty_no_restricted_mode_cmd
);
3179 install_element (VTY_NODE
, &vty_ipv6_access_class_cmd
);
3180 install_element (VTY_NODE
, &no_vty_ipv6_access_class_cmd
);
3181 #endif /* HAVE_IPV6 */
3185 vty_terminate (void)
3188 XFREE (MTYPE_TMP
, vty_cwd
);
3190 if (vtyvec
&& Vvty_serv_thread
)
3193 vector_free (vtyvec
);
3194 vector_free (Vvty_serv_thread
);
3198 /* Utility functions to get arguments from commands generated
3199 by the xml2cli.pl script. */
3201 vty_get_arg_value (struct vty_arg
*args
[], const char *arg
)
3205 if (strcmp ((*args
)->name
, arg
) == 0)
3206 return (*args
)->value
;
3213 vty_get_arg (struct vty_arg
*args
[], const char *arg
)
3217 if (strcmp ((*args
)->name
, arg
) == 0)