frr/lib/vty.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3169 lines
70 KiB
C
Raw Normal View History

2002-12-13 21:15:29 +01:00
/*
* Virtual terminal [aka TeletYpe] interface routine.
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2002-12-13 21:15:29 +01:00
*/
#include <zebra.h>
#include <lib/version.h>
#include <sys/types.h>
#include <sys/types.h>
#ifdef HAVE_LIBPCREPOSIX
#include <pcreposix.h>
#else
#include <regex.h>
#endif /* HAVE_LIBPCREPOSIX */
#include <stdio.h>
2002-12-13 21:15:29 +01:00
#include "linklist.h"
#include "thread.h"
2002-12-13 21:15:29 +01:00
#include "buffer.h"
#include "command.h"
#include "sockunion.h"
#include "memory.h"
#include "log.h"
#include "prefix.h"
#include "filter.h"
#include "vty.h"
#include "privs.h"
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
#include "network.h"
#include "libfrr.h"
#include "frrstr.h"
#include "lib_errors.h"
#include "northbound_cli.h"
#include "printfrr.h"
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
#include <arpa/telnet.h>
#include <termios.h>
2002-12-13 21:15:29 +01:00
#ifndef VTYSH_EXTRACT_PL
#include "lib/vty_clippy.c"
#endif
DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer");
DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history");
2002-12-13 21:15:29 +01:00
/* Vty events */
enum event {
2002-12-13 21:15:29 +01:00
VTY_SERV,
VTY_READ,
VTY_WRITE,
VTY_TIMEOUT_RESET,
#ifdef VTYSH
VTYSH_SERV,
VTYSH_READ,
VTYSH_WRITE
2002-12-13 21:15:29 +01:00
#endif /* VTYSH */
};
static void vty_event_serv(enum event event, int sock);
static void vty_event(enum event, struct vty *);
2002-12-13 21:15:29 +01:00
/* Extern host structure from command.c */
extern struct host host;
2002-12-13 21:15:29 +01:00
/* Vector which store each vty structure. */
static vector vtyvec;
/* Vty timeout value. */
static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
/* Vty access-class command */
static char *vty_accesslist_name = NULL;
/* Vty access-calss for IPv6. */
static char *vty_ipv6_accesslist_name = NULL;
/* VTY server thread. */
static vector Vvty_serv_thread;
2002-12-13 21:15:29 +01:00
/* Current directory. */
static char vty_cwd[MAXPATHLEN];
2002-12-13 21:15:29 +01:00
/* Login password check. */
static int no_password_check = 0;
/* Integrated configuration file path */
static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
2002-12-13 21:15:29 +01:00
static bool do_log_commands;
static bool do_log_commands_perm;
void vty_frame(struct vty *vty, const char *format, ...)
{
va_list args;
va_start(args, format);
vsnprintfrr(vty->frame + vty->frame_pos,
sizeof(vty->frame) - vty->frame_pos, format, args);
vty->frame_pos = strlen(vty->frame);
va_end(args);
}
void vty_endframe(struct vty *vty, const char *endtext)
{
if (vty->frame_pos == 0 && endtext)
vty_out(vty, "%s", endtext);
vty->frame_pos = 0;
}
bool vty_set_include(struct vty *vty, const char *regexp)
{
int errcode;
bool ret = true;
char errbuf[256];
if (!regexp) {
if (vty->filter) {
regfree(&vty->include);
vty->filter = false;
}
return true;
}
errcode = regcomp(&vty->include, regexp,
REG_EXTENDED | REG_NEWLINE | REG_NOSUB);
if (errcode) {
ret = false;
regerror(errcode, &vty->include, errbuf, sizeof(errbuf));
vty_out(vty, "%% Regex compilation error: %s\n", errbuf);
} else {
vty->filter = true;
}
return ret;
}
/* VTY standard output function. */
int vty_out(struct vty *vty, const char *format, ...)
2002-12-13 21:15:29 +01:00
{
va_list args;
ssize_t len;
2002-12-13 21:15:29 +01:00
char buf[1024];
char *p = NULL;
char *filtered;
/* format string may contain %m, keep errno intact for printfrr */
int saved_errno = errno;
if (vty->frame_pos) {
vty->frame_pos = 0;
vty_out(vty, "%s", vty->frame);
}
va_start(args, format);
errno = saved_errno;
p = vasnprintfrr(MTYPE_VTY_OUT_BUF, buf, sizeof(buf), format, args);
va_end(args);
len = strlen(p);
/* filter buffer */
if (vty->filter) {
vector lines = frrstr_split_vec(p, "\n");
/* Place first value in the cache */
char *firstline = vector_slot(lines, 0);
buffer_put(vty->lbuf, (uint8_t *) firstline, strlen(firstline));
/* If our split returned more than one entry, time to filter */
if (vector_active(lines) > 1) {
/*
* returned string is MTYPE_TMP so it matches the MTYPE
* of everything else in the vector
*/
char *bstr = buffer_getstr(vty->lbuf);
buffer_reset(vty->lbuf);
XFREE(MTYPE_TMP, lines->index[0]);
vector_set_index(lines, 0, bstr);
frrstr_filter_vec(lines, &vty->include);
vector_compact(lines);
/*
* Consider the string "foo\n". If the regex is an empty string
* and the line ended with a newline, then the vector will look
* like:
*
* [0]: 'foo'
* [1]: ''
*
* If the regex isn't empty, the vector will look like:
*
* [0]: 'foo'
*
* In this case we'd like to preserve the newline, so we add
* the empty string [1] as in the first example.
*/
if (p[strlen(p) - 1] == '\n' && vector_active(lines) > 0
&& strlen(vector_slot(lines, vector_active(lines) - 1)))
vector_set(lines, XSTRDUP(MTYPE_TMP, ""));
filtered = frrstr_join_vec(lines, "\n");
}
else {
filtered = NULL;
}
frrstr_strvec_free(lines);
} else {
filtered = p;
}
if (!filtered)
goto done;
switch (vty->type) {
case VTY_TERM:
/* print with crlf replacement */
buffer_put_crlf(vty->obuf, (uint8_t *)filtered,
strlen(filtered));
break;
case VTY_SHELL:
if (vty->of) {
fprintf(vty->of, "%s", filtered);
fflush(vty->of);
} else if (vty->of_saved) {
fprintf(vty->of_saved, "%s", filtered);
fflush(vty->of_saved);
}
break;
case VTY_SHELL_SERV:
case VTY_FILE:
default:
/* print without crlf replacement */
buffer_put(vty->obuf, (uint8_t *)filtered, strlen(filtered));
break;
2002-12-13 21:15:29 +01:00
}
done:
if (vty->filter && filtered)
XFREE(MTYPE_TMP, filtered);
/* If p is not different with buf, it is allocated buffer. */
if (p != buf)
XFREE(MTYPE_VTY_OUT_BUF, p);
2002-12-13 21:15:29 +01:00
return len;
}
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
static int vty_log_out(struct vty *vty, const char *level,
const char *proto_str, const char *msg,
struct timestamp_control *ctl)
2002-12-13 21:15:29 +01:00
{
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
int ret;
2002-12-13 21:15:29 +01:00
int len;
char buf[1024];
if (!ctl->already_rendered) {
ctl->len = quagga_timestamp(ctl->precision, ctl->buf,
sizeof(ctl->buf));
ctl->already_rendered = 1;
}
if (ctl->len + 1 >= sizeof(buf))
return -1;
memcpy(buf, ctl->buf, len = ctl->len);
buf[len++] = ' ';
buf[len] = '\0';
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
if (level)
ret = snprintf(buf + len, sizeof(buf) - len, "%s: %s: ", level,
proto_str);
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
else
ret = snprintf(buf + len, sizeof(buf) - len, "%s: ", proto_str);
if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
return -1;
if (((ret = snprintf(buf + len, sizeof(buf) - len, "%s", msg)) < 0)
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
|| ((size_t)((len += ret) + 2) > sizeof(buf)))
2002-12-13 21:15:29 +01:00
return -1;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buf[len++] = '\r';
buf[len++] = '\n';
if (write(vty->wfd, buf, len) < 0) {
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if (ERRNO_IO_RETRY(errno))
/* Kernel buffer is full, probably too much debugging
output, so just
drop the data and ignore. */
return -1;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
/* Fatal I/O error. */
vty->monitor =
0; /* disable monitoring to avoid infinite recursion */
flog_err(EC_LIB_SOCKET,
"%s: write failed to vty client fd %d, closing: %s",
__func__, vty->fd, safe_strerror(errno));
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_reset(vty->obuf);
buffer_reset(vty->lbuf);
/* cannot call vty_close, because a parent routine may still try
to access the vty struct */
vty->status = VTY_CLOSE;
shutdown(vty->fd, SHUT_RDWR);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
return -1;
}
return 0;
2002-12-13 21:15:29 +01:00
}
/* Output current time to the vty. */
void vty_time_print(struct vty *vty, int cr)
{
char buf[QUAGGA_TIMESTAMP_LEN];
if (quagga_timestamp(0, buf, sizeof(buf)) == 0) {
zlog_info("quagga_timestamp error");
2002-12-13 21:15:29 +01:00
return;
}
if (cr)
vty_out(vty, "%s\n", buf);
else
vty_out(vty, "%s ", buf);
return;
}
/* Say hello to vty interface. */
void vty_hello(struct vty *vty)
{
if (host.motdfile) {
FILE *f;
char buf[4096];
f = fopen(host.motdfile, "r");
if (f) {
while (fgets(buf, sizeof(buf), f)) {
char *s;
/* work backwards to ignore trailling isspace()
*/
for (s = buf + strlen(buf);
(s > buf) && isspace((unsigned char)s[-1]);
s--)
;
*s = '\0';
vty_out(vty, "%s\n", buf);
}
fclose(f);
} else
vty_out(vty, "MOTD file not found\n");
} else if (host.motd)
vty_out(vty, "%s", host.motd);
2002-12-13 21:15:29 +01:00
}
/* Put out prompt and wait input from user. */
static void vty_prompt(struct vty *vty)
{
if (vty->type == VTY_TERM) {
vty_out(vty, cmd_prompt(vty->node), cmd_hostname_get());
2002-12-13 21:15:29 +01:00
}
}
/* Send WILL TELOPT_ECHO to remote server. */
static void vty_will_echo(struct vty *vty)
{
unsigned char cmd[] = {IAC, WILL, TELOPT_ECHO, '\0'};
2002-12-13 21:15:29 +01:00
vty_out(vty, "%s", cmd);
}
/* Make suppress Go-Ahead telnet option. */
static void vty_will_suppress_go_ahead(struct vty *vty)
{
unsigned char cmd[] = {IAC, WILL, TELOPT_SGA, '\0'};
2002-12-13 21:15:29 +01:00
vty_out(vty, "%s", cmd);
}
/* Make don't use linemode over telnet. */
static void vty_dont_linemode(struct vty *vty)
{
unsigned char cmd[] = {IAC, DONT, TELOPT_LINEMODE, '\0'};
2002-12-13 21:15:29 +01:00
vty_out(vty, "%s", cmd);
}
/* Use window size. */
static void vty_do_window_size(struct vty *vty)
{
unsigned char cmd[] = {IAC, DO, TELOPT_NAWS, '\0'};
2002-12-13 21:15:29 +01:00
vty_out(vty, "%s", cmd);
}
/* Authentication of vty */
static void vty_auth(struct vty *vty, char *buf)
{
char *passwd = NULL;
enum node_type next_node = 0;
int fail;
char *crypt(const char *, const char *);
2002-12-13 21:15:29 +01:00
switch (vty->node) {
case AUTH_NODE:
if (host.encrypt)
passwd = host.password_encrypt;
2002-12-13 21:15:29 +01:00
else
passwd = host.password;
2002-12-13 21:15:29 +01:00
if (host.advanced)
next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
2002-12-13 21:15:29 +01:00
else
next_node = VIEW_NODE;
2002-12-13 21:15:29 +01:00
break;
case AUTH_ENABLE_NODE:
if (host.encrypt)
passwd = host.enable_encrypt;
2002-12-13 21:15:29 +01:00
else
passwd = host.enable;
2002-12-13 21:15:29 +01:00
next_node = ENABLE_NODE;
break;
}
2002-12-13 21:15:29 +01:00
if (passwd) {
if (host.encrypt)
fail = strcmp(crypt(buf, passwd), passwd);
2002-12-13 21:15:29 +01:00
else
fail = strcmp(buf, passwd);
2002-12-13 21:15:29 +01:00
} else
fail = 1;
2002-12-13 21:15:29 +01:00
if (!fail) {
vty->fail = 0;
vty->node = next_node; /* Success ! */
2002-12-13 21:15:29 +01:00
} else {
vty->fail++;
if (vty->fail >= 3) {
if (vty->node == AUTH_NODE) {
vty_out(vty,
"%% Bad passwords, too many failures!\n");
vty->status = VTY_CLOSE;
} else {
/* AUTH_ENABLE_NODE */
vty->fail = 0;
vty_out(vty,
"%% Bad enable passwords, too many failures!\n");
vty->status = VTY_CLOSE;
}
}
2002-12-13 21:15:29 +01:00
}
}
/* Command execution over the vty interface. */
static int vty_command(struct vty *vty, char *buf)
{
int ret;
const char *protocolname;
char *cp = NULL;
assert(vty);
/*
* Log non empty command lines
*/
if (do_log_commands)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
while (isspace((unsigned char)*cp) && *cp != '\0')
cp++;
}
if (cp != NULL && *cp != '\0') {
unsigned i;
char vty_str[VTY_BUFSIZ];
char prompt_str[VTY_BUFSIZ];
/* format the base vty info */
snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
for (i = 0; i < vector_active(vtyvec); i++)
if (vty == vector_slot(vtyvec, i)) {
snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
i, vty->address);
break;
}
/* format the prompt */
snprintf(prompt_str, sizeof(prompt_str), cmd_prompt(vty->node),
vty_str);
/* now log the command */
zlog_notice("%s%s", prompt_str, buf);
}
2002-12-13 21:15:29 +01:00
#ifdef CONSUMED_TIME_CHECK
{
RUSAGE_T before;
RUSAGE_T after;
2005-04-27 Andrew J. Schorr <ajschorr@alumni.princeton.edu> Add wall-clock timing statistics to 'show thread cpu' output. * thread.h: Define struct rusage_t to contain wall-clock time and cpu time. Change GETRUSAGE macro to collect both pieces of data. Make appropriate changes to struct cpu_thread_history to track CPU time and real time. Change proto for thread_consumed_time to return real and cpu time elapsed. And declare a new global variable 'struct timeval recent_time'. * thread.c (struct timeval recent_time): New global timestamp variable. (timeval_adjust): If timeout is negative, set to 0 (not 10 microseconds). And remove upper bound of 1,000,000 seconds, since this does not seem to make any sense (and it breaks funcname_thread_add_timer_timeval). (timeval_cmp): Should return long, not int. (vty_out_cpu_thread_history): Show CPU time and real time. (cpu_record_hash_print): Calculate totals for CPU and real time. (cpu_record_print): Change 'show thread cpu' title to show CPU and real time. (thread_timer_remain_second): Put current time in global recent_time. (funcname_thread_add_timer_timeval): Fix assert. Replace 2-case switch assignment with a ternary expression. Use global recent_time variable. Fix use of timeval_adjust (previously, the value was not actually being adjusted). (thread_cancel): Add missing "break" statement in case THREAD_BACKGROUND. (thread_timer_wait): Use global recent_time value instead of calling gettimeofday. And there's no need to check for negative timeouts, since timeval_subtract already sets these to zero. (thread_timer_process): Timers are sorted, so bail out once we encounter a timer that has not yet popped. And remove some extraneous asserts. (thread_fetch): Do not process foreground timers before calling select. Instead, add them to the ready list just after the select. Also, no need to maintain a count of the number of ready threads, since we don't care how many there are, just whether there's one at the head of the ready list (which is easily checked). Stick current time in global variable recent_time to reduce the number of calls to gettimeofday. Tighten logic for calculating the select timeout. (thread_consumed_time): Now returns real time and puts the elapsed cpu time in an additional argument. (thread_should_yield): Use real (wall-clock) time to decide whether to yield. (thread_call): Maintain CPU and real time statistics. * vty.c (vty_command): For slow commands, show real and cpu time.
2005-04-28 03:31:13 +02:00
unsigned long realtime, cputime;
GETRUSAGE(&before);
#endif /* CONSUMED_TIME_CHECK */
ret = cmd_execute(vty, buf, NULL, 0);
2002-12-13 21:15:29 +01:00
/* Get the name of the protocol if any */
protocolname = frr_protoname;
#ifdef CONSUMED_TIME_CHECK
GETRUSAGE(&after);
realtime = thread_consumed_time(&after, &before, &cputime);
if (cputime > CONSUMED_TIME_CHECK) {
/* Warn about CPU hog that must be fixed. */
flog_warn(
EC_LIB_SLOW_THREAD_CPU,
"CPU HOG: command took %lums (cpu time %lums): %s",
realtime / 1000, cputime / 1000, buf);
} else if (realtime > CONSUMED_TIME_CHECK) {
flog_warn(
EC_LIB_SLOW_THREAD_WALL,
"STARVATION: command took %lums (cpu time %lums): %s",
realtime / 1000, cputime / 1000, buf);
}
}
#endif /* CONSUMED_TIME_CHECK */
2002-12-13 21:15:29 +01:00
if (ret != CMD_SUCCESS)
switch (ret) {
case CMD_WARNING:
if (vty->type == VTY_FILE)
vty_out(vty, "Warning...\n");
break;
2002-12-13 21:15:29 +01:00
case CMD_ERR_AMBIGUOUS:
vty_out(vty, "%% Ambiguous command.\n");
break;
2002-12-13 21:15:29 +01:00
case CMD_ERR_NO_MATCH:
vty_out(vty, "%% [%s] Unknown command: %s\n",
protocolname, buf);
break;
2002-12-13 21:15:29 +01:00
case CMD_ERR_INCOMPLETE:
vty_out(vty, "%% Command incomplete.\n");
break;
2002-12-13 21:15:29 +01:00
}
2002-12-13 21:15:29 +01:00
return ret;
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
static const char telnet_backward_char = 0x08;
static const char telnet_space_char = ' ';
2002-12-13 21:15:29 +01:00
/* Basic function to write buffer to vty. */
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
2002-12-13 21:15:29 +01:00
{
if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
return;
/* Should we do buffering here ? And make vty_flush (vty) ? */
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_put(vty->obuf, buf, nbytes);
2002-12-13 21:15:29 +01:00
}
/* Basic function to insert character into vty. */
static void vty_self_insert(struct vty *vty, char c)
{
int i;
int length;
if (vty->length + 1 >= VTY_BUFSIZ)
return;
2002-12-13 21:15:29 +01:00
length = vty->length - vty->cp;
memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
vty->buf[vty->cp] = c;
vty_write(vty, &vty->buf[vty->cp], length + 1);
for (i = 0; i < length; i++)
vty_write(vty, &telnet_backward_char, 1);
vty->cp++;
vty->length++;
vty->buf[vty->length] = '\0';
2002-12-13 21:15:29 +01:00
}
/* Self insert character 'c' in overwrite mode. */
static void vty_self_insert_overwrite(struct vty *vty, char c)
{
if (vty->cp == vty->length) {
vty_self_insert(vty, c);
return;
}
2002-12-13 21:15:29 +01:00
vty->buf[vty->cp++] = c;
2002-12-13 21:15:29 +01:00
vty_write(vty, &c, 1);
}
/**
* Insert a string into vty->buf at the current cursor position.
*
* If the resultant string would be larger than VTY_BUFSIZ it is
* truncated to fit.
*/
2002-12-13 21:15:29 +01:00
static void vty_insert_word_overwrite(struct vty *vty, char *str)
{
if (vty->cp == VTY_BUFSIZ)
return;
size_t nwrite = MIN((int)strlen(str), VTY_BUFSIZ - vty->cp - 1);
memcpy(&vty->buf[vty->cp], str, nwrite);
vty->cp += nwrite;
vty->length = MAX(vty->cp, vty->length);
vty->buf[vty->length] = '\0';
vty_write(vty, str, nwrite);
2002-12-13 21:15:29 +01:00
}
/* Forward character. */
static void vty_forward_char(struct vty *vty)
{
if (vty->cp < vty->length) {
vty_write(vty, &vty->buf[vty->cp], 1);
vty->cp++;
}
}
/* Backward character. */
static void vty_backward_char(struct vty *vty)
{
if (vty->cp > 0) {
vty->cp--;
vty_write(vty, &telnet_backward_char, 1);
}
}
/* Move to the beginning of the line. */
static void vty_beginning_of_line(struct vty *vty)
{
while (vty->cp)
vty_backward_char(vty);
}
/* Move to the end of the line. */
static void vty_end_of_line(struct vty *vty)
{
while (vty->cp < vty->length)
vty_forward_char(vty);
}
static void vty_kill_line_from_beginning(struct vty *);
static void vty_redraw_line(struct vty *);
/* Print command line history. This function is called from
vty_next_line and vty_previous_line. */
static void vty_history_print(struct vty *vty)
{
int length;
vty_kill_line_from_beginning(vty);
/* Get previous line from history buffer */
length = strlen(vty->hist[vty->hp]);
memcpy(vty->buf, vty->hist[vty->hp], length);
vty->cp = vty->length = length;
vty->buf[vty->length] = '\0';
2002-12-13 21:15:29 +01:00
/* Redraw current line */
vty_redraw_line(vty);
}
/* Show next command line history. */
static void vty_next_line(struct vty *vty)
{
int try_index;
if (vty->hp == vty->hindex)
return;
/* Try is there history exist or not. */
try_index = vty->hp;
if (try_index == (VTY_MAXHIST - 1))
try_index = 0;
else
try_index++;
/* If there is not history return. */
if (vty->hist[try_index] == NULL)
return;
else
vty->hp = try_index;
vty_history_print(vty);
}
/* Show previous command line history. */
static void vty_previous_line(struct vty *vty)
{
int try_index;
try_index = vty->hp;
if (try_index == 0)
try_index = VTY_MAXHIST - 1;
else
try_index--;
if (vty->hist[try_index] == NULL)
return;
else
vty->hp = try_index;
vty_history_print(vty);
}
/* This function redraw all of the command line character. */
static void vty_redraw_line(struct vty *vty)
{
vty_write(vty, vty->buf, vty->length);
vty->cp = vty->length;
}
/* Forward word. */
static void vty_forward_word(struct vty *vty)
{
while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
vty_forward_char(vty);
2002-12-13 21:15:29 +01:00
while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
vty_forward_char(vty);
}
/* Backward word without skipping training space. */
static void vty_backward_pure_word(struct vty *vty)
{
while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
vty_backward_char(vty);
}
/* Backward word. */
static void vty_backward_word(struct vty *vty)
{
while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
vty_backward_char(vty);
while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
vty_backward_char(vty);
}
/* When '^D' is typed at the beginning of the line we move to the down
level. */
static void vty_down_level(struct vty *vty)
{
vty_out(vty, "\n");
cmd_exit(vty);
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty->cp = 0;
}
/* When '^Z' is received from vty, move down to the enable mode. */
static void vty_end_config(struct vty *vty)
{
vty_out(vty, "\n");
if (vty->config) {
vty_config_exit(vty);
2002-12-13 21:15:29 +01:00
vty->node = ENABLE_NODE;
}
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty->cp = 0;
}
/* Delete a charcter at the current point. */
static void vty_delete_char(struct vty *vty)
{
int i;
int size;
if (vty->length == 0) {
vty_down_level(vty);
return;
}
if (vty->cp == vty->length)
return; /* completion need here? */
2002-12-13 21:15:29 +01:00
size = vty->length - vty->cp;
vty->length--;
memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
vty->buf[vty->length] = '\0';
if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
return;
2002-12-13 21:15:29 +01:00
vty_write(vty, &vty->buf[vty->cp], size - 1);
vty_write(vty, &telnet_space_char, 1);
for (i = 0; i < size; i++)
vty_write(vty, &telnet_backward_char, 1);
}
/* Delete a character before the point. */
static void vty_delete_backward_char(struct vty *vty)
{
if (vty->cp == 0)
return;
vty_backward_char(vty);
vty_delete_char(vty);
}
/* Kill rest of line from current point. */
static void vty_kill_line(struct vty *vty)
{
int i;
int size;
size = vty->length - vty->cp;
2002-12-13 21:15:29 +01:00
if (size == 0)
return;
for (i = 0; i < size; i++)
vty_write(vty, &telnet_space_char, 1);
for (i = 0; i < size; i++)
vty_write(vty, &telnet_backward_char, 1);
memset(&vty->buf[vty->cp], 0, size);
vty->length = vty->cp;
}
/* Kill line from the beginning. */
static void vty_kill_line_from_beginning(struct vty *vty)
{
vty_beginning_of_line(vty);
vty_kill_line(vty);
}
/* Delete a word before the point. */
static void vty_forward_kill_word(struct vty *vty)
{
while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
vty_delete_char(vty);
while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
vty_delete_char(vty);
}
/* Delete a word before the point. */
static void vty_backward_kill_word(struct vty *vty)
{
while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
vty_delete_backward_char(vty);
while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
vty_delete_backward_char(vty);
}
/* Transpose chars before or at the point. */
static void vty_transpose_chars(struct vty *vty)
{
char c1, c2;
/* If length is short or point is near by the beginning of line then
return. */
if (vty->length < 2 || vty->cp < 1)
return;
/* In case of point is located at the end of the line. */
if (vty->cp == vty->length) {
c1 = vty->buf[vty->cp - 1];
c2 = vty->buf[vty->cp - 2];
vty_backward_char(vty);
vty_backward_char(vty);
vty_self_insert_overwrite(vty, c1);
vty_self_insert_overwrite(vty, c2);
} else {
c1 = vty->buf[vty->cp];
c2 = vty->buf[vty->cp - 1];
vty_backward_char(vty);
vty_self_insert_overwrite(vty, c1);
vty_self_insert_overwrite(vty, c2);
}
}
/* Do completion at vty interface. */
static void vty_complete_command(struct vty *vty)
{
int i;
int ret;
char **matched = NULL;
vector vline;
2002-12-13 21:15:29 +01:00
if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
return;
2002-12-13 21:15:29 +01:00
vline = cmd_make_strvec(vty->buf);
if (vline == NULL)
return;
2002-12-13 21:15:29 +01:00
/* In case of 'help \t'. */
if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
matched = cmd_complete_command(vline, vty, &ret);
2002-12-13 21:15:29 +01:00
cmd_free_strvec(vline);
vty_out(vty, "\n");
2002-12-13 21:15:29 +01:00
switch (ret) {
case CMD_ERR_AMBIGUOUS:
vty_out(vty, "%% Ambiguous command.\n");
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
break;
case CMD_ERR_NO_MATCH:
/* vty_out (vty, "%% There is no matched command.\n"); */
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
break;
case CMD_COMPLETE_FULL_MATCH:
if (!matched[0]) {
/* 2016-11-28 equinox -- need to debug, SEGV here */
vty_out(vty, "%% CLI BUG: FULL_MATCH with NULL str\n");
vty_prompt(vty);
vty_redraw_line(vty);
break;
}
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
vty_backward_pure_word(vty);
vty_insert_word_overwrite(vty, matched[0]);
vty_self_insert(vty, ' ');
XFREE(MTYPE_COMPLETION, matched[0]);
2002-12-13 21:15:29 +01:00
break;
case CMD_COMPLETE_MATCH:
vty_prompt(vty);
vty_redraw_line(vty);
vty_backward_pure_word(vty);
vty_insert_word_overwrite(vty, matched[0]);
XFREE(MTYPE_COMPLETION, matched[0]);
2002-12-13 21:15:29 +01:00
break;
case CMD_COMPLETE_LIST_MATCH:
for (i = 0; matched[i] != NULL; i++) {
if (i != 0 && ((i % 6) == 0))
vty_out(vty, "\n");
vty_out(vty, "%-10s ", matched[i]);
XFREE(MTYPE_COMPLETION, matched[i]);
}
vty_out(vty, "\n");
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
break;
case CMD_ERR_NOTHING_TODO:
vty_prompt(vty);
vty_redraw_line(vty);
break;
default:
break;
}
XFREE(MTYPE_TMP, matched);
2002-12-13 21:15:29 +01:00
}
2002-12-13 21:15:29 +01:00
static void vty_describe_fold(struct vty *vty, int cmd_width,
unsigned int desc_width, struct cmd_token *token)
2002-12-13 21:15:29 +01:00
{
char *buf;
const char *cmd, *p;
2002-12-13 21:15:29 +01:00
int pos;
cmd = token->text;
2002-12-13 21:15:29 +01:00
if (desc_width <= 0) {
vty_out(vty, " %-*s %s\n", cmd_width, cmd, token->desc);
2002-12-13 21:15:29 +01:00
return;
}
buf = XCALLOC(MTYPE_TMP, strlen(token->desc) + 1);
for (p = token->desc; strlen(p) > desc_width; p += pos + 1) {
2002-12-13 21:15:29 +01:00
for (pos = desc_width; pos > 0; pos--)
if (*(p + pos) == ' ')
break;
2002-12-13 21:15:29 +01:00
if (pos == 0)
break;
memcpy(buf, p, pos);
2002-12-13 21:15:29 +01:00
buf[pos] = '\0';
vty_out(vty, " %-*s %s\n", cmd_width, cmd, buf);
2002-12-13 21:15:29 +01:00
cmd = "";
}
vty_out(vty, " %-*s %s\n", cmd_width, cmd, p);
2002-12-13 21:15:29 +01:00
XFREE(MTYPE_TMP, buf);
}
/* Describe matched command function. */
static void vty_describe_command(struct vty *vty)
{
int ret;
vector vline;
vector describe;
unsigned int i, width, desc_width;
struct cmd_token *token, *token_cr = NULL;
2002-12-13 21:15:29 +01:00
vline = cmd_make_strvec(vty->buf);
2002-12-13 21:15:29 +01:00
/* In case of '> ?'. */
if (vline == NULL) {
vline = vector_init(1);
vector_set(vline, NULL);
} else if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
2002-12-13 21:15:29 +01:00
describe = cmd_describe_command(vline, vty, &ret);
vty_out(vty, "\n");
2002-12-13 21:15:29 +01:00
/* Ambiguous error. */
switch (ret) {
case CMD_ERR_AMBIGUOUS:
vty_out(vty, "%% Ambiguous command.\n");
goto out;
2002-12-13 21:15:29 +01:00
break;
case CMD_ERR_NO_MATCH:
vty_out(vty, "%% There is no matched command.\n");
goto out;
2002-12-13 21:15:29 +01:00
break;
}
2002-12-13 21:15:29 +01:00
/* Get width of command string. */
width = 0;
for (i = 0; i < vector_active(describe); i++)
if ((token = vector_slot(describe, i)) != NULL) {
unsigned int len;
if (token->text[0] == '\0')
continue;
len = strlen(token->text);
if (width < len)
width = len;
2002-12-13 21:15:29 +01:00
}
2002-12-13 21:15:29 +01:00
/* Get width of description string. */
desc_width = vty->width - (width + 6);
2002-12-13 21:15:29 +01:00
/* Print out description. */
for (i = 0; i < vector_active(describe); i++)
if ((token = vector_slot(describe, i)) != NULL) {
if (token->text[0] == '\0')
continue;
if (strcmp(token->text, CMD_CR_TEXT) == 0) {
token_cr = token;
continue;
}
if (!token->desc)
vty_out(vty, " %-s\n", token->text);
else if (desc_width >= strlen(token->desc))
vty_out(vty, " %-*s %s\n", width, token->text,
token->desc);
else
vty_describe_fold(vty, width, desc_width,
token);
if (IS_VARYING_TOKEN(token->type)) {
const char *ref = vector_slot(
vline, vector_active(vline) - 1);
vector varcomps = vector_init(VECTOR_MIN_SIZE);
cmd_variable_complete(token, ref, varcomps);
if (vector_active(varcomps) > 0) {
char *ac = cmd_variable_comp2str(
varcomps, vty->width);
vty_out(vty, "%s\n", ac);
XFREE(MTYPE_TMP, ac);
}
vector_free(varcomps);
}
2002-12-13 21:15:29 +01:00
}
if ((token = token_cr)) {
if (!token->desc)
vty_out(vty, " %-s\n", token->text);
else if (desc_width >= strlen(token->desc))
vty_out(vty, " %-*s %s\n", width, token->text,
token->desc);
2002-12-13 21:15:29 +01:00
else
vty_describe_fold(vty, width, desc_width, token);
2002-12-13 21:15:29 +01:00
}
out:
2002-12-13 21:15:29 +01:00
cmd_free_strvec(vline);
if (describe)
vector_free(describe);
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
}
static void vty_clear_buf(struct vty *vty)
{
memset(vty->buf, 0, vty->max);
}
/* ^C stop current input and do not add command line to the history. */
static void vty_stop_input(struct vty *vty)
{
vty->cp = vty->length = 0;
vty_clear_buf(vty);
vty_out(vty, "\n");
if (vty->config) {
vty_config_exit(vty);
2002-12-13 21:15:29 +01:00
vty->node = ENABLE_NODE;
}
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
2002-12-13 21:15:29 +01:00
/* Set history pointer to the latest one. */
vty->hp = vty->hindex;
}
/* Add current command line to the history buffer. */
static void vty_hist_add(struct vty *vty)
{
int index;
if (vty->length == 0)
return;
index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
/* Ignore the same string as previous one. */
if (vty->hist[index])
if (strcmp(vty->buf, vty->hist[index]) == 0) {
vty->hp = vty->hindex;
return;
}
/* Insert history entry. */
XFREE(MTYPE_VTY_HIST, vty->hist[vty->hindex]);
2002-12-13 21:15:29 +01:00
vty->hist[vty->hindex] = XSTRDUP(MTYPE_VTY_HIST, vty->buf);
/* History index rotation. */
vty->hindex++;
if (vty->hindex == VTY_MAXHIST)
vty->hindex = 0;
vty->hp = vty->hindex;
}
/* #define TELNET_OPTION_DEBUG */
/* Get telnet window size. */
static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes)
{
#ifdef TELNET_OPTION_DEBUG
int i;
2002-12-13 21:15:29 +01:00
for (i = 0; i < nbytes; i++) {
switch (buf[i]) {
case IAC:
vty_out(vty, "IAC ");
break;
case WILL:
vty_out(vty, "WILL ");
break;
case WONT:
vty_out(vty, "WONT ");
break;
case DO:
vty_out(vty, "DO ");
break;
case DONT:
vty_out(vty, "DONT ");
break;
case SB:
vty_out(vty, "SB ");
break;
case SE:
vty_out(vty, "SE ");
break;
case TELOPT_ECHO:
vty_out(vty, "TELOPT_ECHO \n");
break;
case TELOPT_SGA:
vty_out(vty, "TELOPT_SGA \n");
break;
case TELOPT_NAWS:
vty_out(vty, "TELOPT_NAWS \n");
break;
default:
vty_out(vty, "%x ", buf[i]);
break;
}
2002-12-13 21:15:29 +01:00
}
vty_out(vty, "\n");
2002-12-13 21:15:29 +01:00
#endif /* TELNET_OPTION_DEBUG */
switch (buf[0]) {
case SB:
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
vty->sb_len = 0;
2002-12-13 21:15:29 +01:00
vty->iac_sb_in_progress = 1;
return 0;
case SE: {
if (!vty->iac_sb_in_progress)
return 0;
if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0')) {
vty->iac_sb_in_progress = 0;
return 0;
}
switch (vty->sb_buf[0]) {
case TELOPT_NAWS:
if (vty->sb_len != TELNET_NAWS_SB_LEN)
flog_err(
EC_LIB_SYSTEM_CALL,
"RFC 1073 violation detected: telnet NAWS option should send %d characters, but we received %lu",
TELNET_NAWS_SB_LEN,
(unsigned long)vty->sb_len);
else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
flog_err(
EC_LIB_DEVELOPMENT,
"Bug detected: sizeof(vty->sb_buf) %lu < %d, too small to handle the telnet NAWS option",
(unsigned long)sizeof(vty->sb_buf),
TELNET_NAWS_SB_LEN);
else {
vty->width = ((vty->sb_buf[1] << 8)
| vty->sb_buf[2]);
vty->height = ((vty->sb_buf[3] << 8)
| vty->sb_buf[4]);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
#ifdef TELNET_OPTION_DEBUG
vty_out(vty,
"TELNET NAWS window size negotiation completed: width %d, height %d\n",
vty->width, vty->height);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
#endif
}
break;
}
vty->iac_sb_in_progress = 0;
return 0;
2002-12-13 21:15:29 +01:00
}
default:
break;
}
return 1;
}
/* Execute current command line. */
static int vty_execute(struct vty *vty)
{
int ret;
ret = CMD_SUCCESS;
switch (vty->node) {
case AUTH_NODE:
case AUTH_ENABLE_NODE:
vty_auth(vty, vty->buf);
break;
default:
ret = vty_command(vty, vty->buf);
if (vty->type == VTY_TERM)
vty_hist_add(vty);
2002-12-13 21:15:29 +01:00
break;
}
/* Clear command line buffer. */
vty->cp = vty->length = 0;
vty_clear_buf(vty);
2004-11-04 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * vty.h: Remove fields in struct vty that were related to VTY_CONTINUE capabilities (that were used only in bgpd/bgp_route.c and are now removed). Also remove some other fields that were not being used at all. * vty.c: (vty_execute) Do not test for obsolete status values VTY_START and VTY_CONTINUE. (vty_read) Remove calls to vty->output_func since that was part of the VTY_CONTINUE infrastructure that has been removed. (vty_flush) Remove code to support VTY_START and VTY_CONTINUE. (vty_close) Remove code to cancel vty->t_output thread, since that thread was never actually used. * bgp_route.c: Remove all code related to VTY_CONTINUE; this feature is deprecated because the output did not represent a single point in time. All output needs to be generated inline and buffered by the library code. (route_vty_out,route_vty_out_tag,damp_route_vty_out, flap_route_vty_out) Remove code to count number of lines of output, since this was only useful for VTY_CONTINUE behavior. (bgp_show_callback) Removed. (bgp_show_table) Remove hooks for VTY_CONTINUE callback support. As a result, there's a new output_arg argument to this function. Make function static. (bgp_show) Make function static and add a new output_arg argument. Change all functions that call bgp_show or bgp_show_table to pass the new output_arg argument (that used to be passed inside vty->output_arg). * bgp_mplsvpn.c: Remove declarations of functions defined in bgp_route.c; these declarations belong in bgp_route.h. * bgp_route.h: Declare 3 global functions used in both bgp_route.c and in bgp_mplsvpn.c.
2004-11-05 02:25:55 +01:00
if (vty->status != VTY_CLOSE)
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
return ret;
}
#define CONTROL(X) ((X) - '@')
#define VTY_NORMAL 0
#define VTY_PRE_ESCAPE 1
#define VTY_ESCAPE 2
#define VTY_CR 3
2002-12-13 21:15:29 +01:00
/* Escape character command map. */
static void vty_escape_map(unsigned char c, struct vty *vty)
{
switch (c) {
case ('A'):
vty_previous_line(vty);
break;
case ('B'):
vty_next_line(vty);
break;
case ('C'):
vty_forward_char(vty);
break;
case ('D'):
vty_backward_char(vty);
break;
default:
break;
}
2002-12-13 21:15:29 +01:00
/* Go back to normal mode. */
vty->escape = VTY_NORMAL;
}
/* Quit print out to the buffer. */
static void vty_buffer_reset(struct vty *vty)
{
buffer_reset(vty->obuf);
buffer_reset(vty->lbuf);
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
vty_redraw_line(vty);
}
/* Read data via vty socket. */
static int vty_read(struct thread *thread)
{
int i;
int nbytes;
unsigned char buf[VTY_READ_BUFSIZ];
2002-12-13 21:15:29 +01:00
struct vty *vty = THREAD_ARG(thread);
2002-12-13 21:15:29 +01:00
/* Read raw data from socket */
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
if (nbytes < 0) {
if (ERRNO_IO_RETRY(errno)) {
vty_event(VTY_READ, vty);
return 0;
}
vty->monitor = 0; /* disable monitoring to avoid
infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read error on vty client fd %d, closing: %s",
__func__, vty->fd, safe_strerror(errno));
buffer_reset(vty->obuf);
buffer_reset(vty->lbuf);
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
vty->status = VTY_CLOSE;
}
for (i = 0; i < nbytes; i++) {
2002-12-13 21:15:29 +01:00
if (buf[i] == IAC) {
if (!vty->iac) {
vty->iac = 1;
continue;
} else {
vty->iac = 0;
}
}
2002-12-13 21:15:29 +01:00
if (vty->iac_sb_in_progress && !vty->iac) {
if (vty->sb_len < sizeof(vty->sb_buf))
vty->sb_buf[vty->sb_len] = buf[i];
vty->sb_len++;
continue;
}
2002-12-13 21:15:29 +01:00
if (vty->iac) {
/* In case of telnet command */
int ret = 0;
ret = vty_telnet_option(vty, buf + i, nbytes - i);
vty->iac = 0;
i += ret;
continue;
}
2002-12-13 21:15:29 +01:00
if (vty->status == VTY_MORE) {
switch (buf[i]) {
case CONTROL('C'):
case 'q':
case 'Q':
vty_buffer_reset(vty);
break;
default:
break;
}
continue;
}
2002-12-13 21:15:29 +01:00
/* Escape character. */
if (vty->escape == VTY_ESCAPE) {
vty_escape_map(buf[i], vty);
continue;
}
2002-12-13 21:15:29 +01:00
/* Pre-escape status. */
if (vty->escape == VTY_PRE_ESCAPE) {
switch (buf[i]) {
case '[':
vty->escape = VTY_ESCAPE;
break;
case 'b':
vty_backward_word(vty);
vty->escape = VTY_NORMAL;
break;
case 'f':
vty_forward_word(vty);
vty->escape = VTY_NORMAL;
break;
case 'd':
vty_forward_kill_word(vty);
vty->escape = VTY_NORMAL;
break;
case CONTROL('H'):
case 0x7f:
vty_backward_kill_word(vty);
vty->escape = VTY_NORMAL;
break;
default:
vty->escape = VTY_NORMAL;
break;
}
continue;
}
if (vty->escape == VTY_CR) {
/* if we get CR+NL, the NL results in an extra empty
* prompt line being printed without this; just drop
* the NL if it immediately follows CR.
*/
vty->escape = VTY_NORMAL;
if (buf[i] == '\n')
continue;
}
2002-12-13 21:15:29 +01:00
switch (buf[i]) {
case CONTROL('A'):
vty_beginning_of_line(vty);
break;
case CONTROL('B'):
vty_backward_char(vty);
break;
case CONTROL('C'):
vty_stop_input(vty);
break;
case CONTROL('D'):
vty_delete_char(vty);
break;
case CONTROL('E'):
vty_end_of_line(vty);
break;
case CONTROL('F'):
vty_forward_char(vty);
break;
case CONTROL('H'):
case 0x7f:
vty_delete_backward_char(vty);
break;
case CONTROL('K'):
vty_kill_line(vty);
break;
case CONTROL('N'):
vty_next_line(vty);
break;
case CONTROL('P'):
vty_previous_line(vty);
break;
case CONTROL('T'):
vty_transpose_chars(vty);
break;
case CONTROL('U'):
vty_kill_line_from_beginning(vty);
break;
case CONTROL('W'):
vty_backward_kill_word(vty);
break;
case CONTROL('Z'):
vty_end_config(vty);
break;
case '\r':
vty->escape = VTY_CR;
/* fallthru */
case '\n':
vty_out(vty, "\n");
buffer_flush_available(vty->obuf, vty->wfd);
vty_execute(vty);
break;
case '\t':
vty_complete_command(vty);
break;
case '?':
if (vty->node == AUTH_NODE
|| vty->node == AUTH_ENABLE_NODE)
vty_self_insert(vty, buf[i]);
else
vty_describe_command(vty);
break;
case '\033':
if (i + 1 < nbytes && buf[i + 1] == '[') {
vty->escape = VTY_ESCAPE;
i++;
} else
vty->escape = VTY_PRE_ESCAPE;
break;
default:
if (buf[i] > 31 && buf[i] < 127)
vty_self_insert(vty, buf[i]);
break;
}
2002-12-13 21:15:29 +01:00
}
2002-12-13 21:15:29 +01:00
/* Check status. */
if (vty->status == VTY_CLOSE)
vty_close(vty);
else {
vty_event(VTY_WRITE, vty);
vty_event(VTY_READ, vty);
2002-12-13 21:15:29 +01:00
}
return 0;
}
/* Flush buffer to the vty. */
static int vty_flush(struct thread *thread)
{
int erase;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_status_t flushrc;
2002-12-13 21:15:29 +01:00
struct vty *vty = THREAD_ARG(thread);
2002-12-13 21:15:29 +01:00
/* Tempolary disable read thread. */
if (vty->lines == 0)
THREAD_OFF(vty->t_read);
2002-12-13 21:15:29 +01:00
/* Function execution continue. */
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
/* N.B. if width is 0, that means we don't know the window size. */
if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0))
flushrc = buffer_flush_available(vty->obuf, vty->wfd);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
else if (vty->status == VTY_MORELINE)
flushrc = buffer_flush_window(vty->obuf, vty->wfd, vty->width,
1, erase, 0);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
else
flushrc = buffer_flush_window(
vty->obuf, vty->wfd, vty->width,
vty->lines >= 0 ? vty->lines : vty->height, erase, 0);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
switch (flushrc) {
case BUFFER_ERROR:
vty->monitor =
0; /* disable monitoring to avoid infinite recursion */
zlog_info("buffer_flush failed on vty client fd %d/%d, closing",
vty->fd, vty->wfd);
buffer_reset(vty->lbuf);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_reset(vty->obuf);
vty_close(vty);
return 0;
case BUFFER_EMPTY:
if (vty->status == VTY_CLOSE)
vty_close(vty);
2002-12-13 21:15:29 +01:00
else {
vty->status = VTY_NORMAL;
if (vty->lines == 0)
vty_event(VTY_READ, vty);
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
break;
case BUFFER_PENDING:
/* There is more data waiting to be written. */
vty->status = VTY_MORE;
if (vty->lines == 0)
vty_event(VTY_WRITE, vty);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
break;
}
2002-12-13 21:15:29 +01:00
return 0;
}
/* Allocate new vty struct. */
struct vty *vty_new(void)
{
struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty));
new->fd = new->wfd = -1;
new->of = stdout;
new->lbuf = buffer_new(0);
new->obuf = buffer_new(0); /* Use default buffer size. */
new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
new->max = VTY_BUFSIZ;
return new;
}
/* allocate and initialise vty */
static struct vty *vty_new_init(int vty_sock)
{
struct vty *vty;
vty = vty_new();
vty->fd = vty_sock;
vty->wfd = vty_sock;
vty->type = VTY_TERM;
vty->node = AUTH_NODE;
vty->fail = 0;
vty->cp = 0;
vty_clear_buf(vty);
vty->length = 0;
memset(vty->hist, 0, sizeof(vty->hist));
vty->hp = 0;
vty->hindex = 0;
vty->xpath_index = 0;
memset(vty->xpath, 0, sizeof(vty->xpath));
vty->private_config = false;
vty->candidate_config = vty_shared_candidate_config;
vector_set_index(vtyvec, vty_sock, vty);
vty->status = VTY_NORMAL;
vty->lines = -1;
vty->iac = 0;
vty->iac_sb_in_progress = 0;
vty->sb_len = 0;
return vty;
}
2002-12-13 21:15:29 +01:00
/* Create new vty structure. */
static struct vty *vty_create(int vty_sock, union sockunion *su)
{
char buf[SU_ADDRSTRLEN];
2002-12-13 21:15:29 +01:00
struct vty *vty;
sockunion2str(su, buf, SU_ADDRSTRLEN);
2002-12-13 21:15:29 +01:00
/* Allocate new vty structure and set up default values. */
vty = vty_new_init(vty_sock);
/* configurable parameters not part of basic init */
vty->v_timeout = vty_timeout_val;
strlcpy(vty->address, buf, sizeof(vty->address));
2002-12-13 21:15:29 +01:00
if (no_password_check) {
if (host.advanced)
vty->node = ENABLE_NODE;
2002-12-13 21:15:29 +01:00
else
vty->node = VIEW_NODE;
2002-12-13 21:15:29 +01:00
}
if (host.lines >= 0)
vty->lines = host.lines;
2002-12-13 21:15:29 +01:00
if (!no_password_check) {
/* Vty is not available if password isn't set. */
if (host.password == NULL && host.password_encrypt == NULL) {
vty_out(vty, "Vty password is not set.\n");
vty->status = VTY_CLOSE;
vty_close(vty);
return NULL;
}
}
2002-12-13 21:15:29 +01:00
/* Say hello to the world. */
vty_hello(vty);
if (!no_password_check)
vty_out(vty, "\nUser Access Verification\n\n");
2002-12-13 21:15:29 +01:00
/* Setting up terminal. */
vty_will_echo(vty);
vty_will_suppress_go_ahead(vty);
2002-12-13 21:15:29 +01:00
vty_dont_linemode(vty);
vty_do_window_size(vty);
/* vty_dont_lflow_ahead (vty); */
2002-12-13 21:15:29 +01:00
vty_prompt(vty);
2002-12-13 21:15:29 +01:00
/* Add read/write thread. */
vty_event(VTY_WRITE, vty);
vty_event(VTY_READ, vty);
2002-12-13 21:15:29 +01:00
return vty;
}
/* create vty for stdio */
static struct termios stdio_orig_termios;
static struct vty *stdio_vty = NULL;
static bool stdio_termios = false;
static void (*stdio_vty_atclose)(int isexit);
static void vty_stdio_reset(int isexit)
{
if (stdio_vty) {
if (stdio_termios)
tcsetattr(0, TCSANOW, &stdio_orig_termios);
stdio_termios = false;
stdio_vty = NULL;
if (stdio_vty_atclose)
stdio_vty_atclose(isexit);
stdio_vty_atclose = NULL;
}
}
static void vty_stdio_atexit(void)
{
vty_stdio_reset(1);
}
void vty_stdio_suspend(void)
{
if (!stdio_vty)
return;
THREAD_OFF(stdio_vty->t_write);
THREAD_OFF(stdio_vty->t_read);
THREAD_OFF(stdio_vty->t_timeout);
if (stdio_termios)
tcsetattr(0, TCSANOW, &stdio_orig_termios);
stdio_termios = false;
}
void vty_stdio_resume(void)
{
if (!stdio_vty)
return;
if (!tcgetattr(0, &stdio_orig_termios)) {
struct termios termios;
termios = stdio_orig_termios;
termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
| IGNCR | ICRNL | IXON);
termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
termios.c_cflag &= ~(CSIZE | PARENB);
termios.c_cflag |= CS8;
tcsetattr(0, TCSANOW, &termios);
stdio_termios = true;
}
vty_prompt(stdio_vty);
/* Add read/write thread. */
vty_event(VTY_WRITE, stdio_vty);
vty_event(VTY_READ, stdio_vty);
}
void vty_stdio_close(void)
{
if (!stdio_vty)
return;
vty_close(stdio_vty);
}
struct vty *vty_stdio(void (*atclose)(int isexit))
{
struct vty *vty;
/* refuse creating two vtys on stdio */
if (stdio_vty)
return NULL;
vty = stdio_vty = vty_new_init(0);
stdio_vty_atclose = atclose;
vty->wfd = 1;
/* always have stdio vty in a known _unchangeable_ state, don't want
* config
* to have any effect here to make sure scripting this works as intended
*/
vty->node = ENABLE_NODE;
vty->v_timeout = 0;
strlcpy(vty->address, "console", sizeof(vty->address));
vty_stdio_resume();
return vty;
}
2002-12-13 21:15:29 +01:00
/* Accept connection from the network. */
static int vty_accept(struct thread *thread)
{
int vty_sock;
union sockunion su;
int ret;
unsigned int on;
int accept_sock;
struct prefix p;
2002-12-13 21:15:29 +01:00
struct access_list *acl = NULL;
2002-12-13 21:15:29 +01:00
accept_sock = THREAD_FD(thread);
2002-12-13 21:15:29 +01:00
/* We continue hearing vty socket. */
vty_event_serv(VTY_SERV, accept_sock);
2002-12-13 21:15:29 +01:00
memset(&su, 0, sizeof(union sockunion));
2002-12-13 21:15:29 +01:00
/* We can handle IPv4 or IPv6 socket. */
vty_sock = sockunion_accept(accept_sock, &su);
if (vty_sock < 0) {
flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s",
safe_strerror(errno));
2002-12-13 21:15:29 +01:00
return -1;
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
set_nonblocking(vty_sock);
set_cloexec(vty_sock);
if (!sockunion2hostprefix(&su, &p)) {
close(vty_sock);
zlog_info("Vty unable to convert prefix from sockunion %pSU",
&su);
return -1;
}
2002-12-13 21:15:29 +01:00
/* VTY's accesslist apply. */
if (p.family == AF_INET && vty_accesslist_name) {
2002-12-13 21:15:29 +01:00
if ((acl = access_list_lookup(AFI_IP, vty_accesslist_name))
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
/* continue accepting connections */
vty_event_serv(VTY_SERV, accept_sock);
2002-12-13 21:15:29 +01:00
return 0;
}
}
2002-12-13 21:15:29 +01:00
/* VTY's ipv6 accesslist apply. */
if (p.family == AF_INET6 && vty_ipv6_accesslist_name) {
if ((acl = access_list_lookup(AFI_IP6,
vty_ipv6_accesslist_name))
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
/* continue accepting connections */
vty_event_serv(VTY_SERV, accept_sock);
return 0;
}
2002-12-13 21:15:29 +01:00
}
on = 1;
ret = setsockopt(vty_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on,
2002-12-13 21:15:29 +01:00
sizeof(on));
if (ret < 0)
zlog_info("can't set sockopt to vty_sock : %s",
safe_strerror(errno));
zlog_info("Vty connection from %pSU", &su);
vty_create(vty_sock, &su);
return 0;
}
2002-12-13 21:15:29 +01:00
static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
{
int ret;
2002-12-13 21:15:29 +01:00
struct addrinfo req;
struct addrinfo *ainfo;
struct addrinfo *ainfo_save;
2002-12-13 21:15:29 +01:00
int sock;
char port_str[BUFSIZ];
memset(&req, 0, sizeof(struct addrinfo));
req.ai_flags = AI_PASSIVE;
2002-12-13 21:15:29 +01:00
req.ai_family = AF_UNSPEC;
req.ai_socktype = SOCK_STREAM;
snprintf(port_str, sizeof(port_str), "%d", port);
port_str[sizeof(port_str) - 1] = '\0';
ret = getaddrinfo(hostname, port_str, &req, &ainfo);
2002-12-13 21:15:29 +01:00
if (ret != 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "getaddrinfo failed: %s",
gai_strerror(ret));
exit(1);
}
2002-12-13 21:15:29 +01:00
ainfo_save = ainfo;
do {
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
continue;
sock = socket(ainfo->ai_family, ainfo->ai_socktype,
ainfo->ai_protocol);
if (sock < 0)
continue;
2002-12-13 21:15:29 +01:00
sockopt_v6only(ainfo->ai_family, sock);
sockopt_reuseaddr(sock);
sockopt_reuseport(sock);
set_cloexec(sock);
2002-12-13 21:15:29 +01:00
ret = bind(sock, ainfo->ai_addr, ainfo->ai_addrlen);
if (ret < 0) {
close(sock); /* Avoid sd leak. */
continue;
}
2002-12-13 21:15:29 +01:00
ret = listen(sock, 3);
if (ret < 0) {
close(sock); /* Avoid sd leak. */
continue;
}
vty_event_serv(VTY_SERV, sock);
2002-12-13 21:15:29 +01:00
} while ((ainfo = ainfo->ai_next) != NULL);
2002-12-13 21:15:29 +01:00
freeaddrinfo(ainfo_save);
}
#ifdef VTYSH
/* For sockaddr_un. */
#include <sys/un.h>
/* VTY shell UNIX domain socket. */
2004-10-07 21:33:46 +02:00
static void vty_serv_un(const char *path)
2002-12-13 21:15:29 +01:00
{
int ret;
int sock, len;
2002-12-13 21:15:29 +01:00
struct sockaddr_un serv;
mode_t old_mask;
struct zprivs_ids_t ids;
2002-12-13 21:15:29 +01:00
/* First of all, unlink existing socket */
unlink(path);
2002-12-13 21:15:29 +01:00
/* Set umask */
2003-05-23 10:12:36 +02:00
old_mask = umask(0007);
2002-12-13 21:15:29 +01:00
/* Make UNIX domain socket. */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
flog_err_sys(EC_LIB_SOCKET,
"Cannot create unix stream socket: %s",
safe_strerror(errno));
2002-12-13 21:15:29 +01:00
return;
}
2002-12-13 21:15:29 +01:00
/* Make server socket. */
memset(&serv, 0, sizeof(struct sockaddr_un));
serv.sun_family = AF_UNIX;
strlcpy(serv.sun_path, path, sizeof(serv.sun_path));
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
2002-12-13 21:15:29 +01:00
len = serv.sun_len = SUN_LEN(&serv);
#else
len = sizeof(serv.sun_family) + strlen(serv.sun_path);
#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
2002-12-13 21:15:29 +01:00
set_cloexec(sock);
2002-12-13 21:15:29 +01:00
ret = bind(sock, (struct sockaddr *)&serv, len);
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET, "Cannot bind path %s: %s", path,
safe_strerror(errno));
close(sock); /* Avoid sd leak. */
2002-12-13 21:15:29 +01:00
return;
}
ret = listen(sock, 5);
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET, "listen(fd %d) failed: %s", sock,
safe_strerror(errno));
close(sock); /* Avoid sd leak. */
2002-12-13 21:15:29 +01:00
return;
}
umask(old_mask);
zprivs_get_ids(&ids);
/* Hack: ids.gid_vty is actually a uint, but we stored -1 in it
earlier for the case when we don't need to chown the file
type casting it here to make a compare */
if ((int)ids.gid_vty > 0) {
/* set group of socket */
if (chown(path, -1, ids.gid_vty)) {
flog_err_sys(EC_LIB_SYSTEM_CALL,
"vty_serv_un: could chown socket, %s",
safe_strerror(errno));
}
}
vty_event_serv(VTYSH_SERV, sock);
2002-12-13 21:15:29 +01:00
}
/* #define VTYSH_DEBUG 1 */
static int vtysh_accept(struct thread *thread)
{
int accept_sock;
int sock;
int client_len;
struct sockaddr_un client;
struct vty *vty;
2002-12-13 21:15:29 +01:00
accept_sock = THREAD_FD(thread);
vty_event_serv(VTYSH_SERV, accept_sock);
2002-12-13 21:15:29 +01:00
memset(&client, 0, sizeof(struct sockaddr_un));
client_len = sizeof(struct sockaddr_un);
2004-09-26 18:08:11 +02:00
sock = accept(accept_sock, (struct sockaddr *)&client,
(socklen_t *)&client_len);
2002-12-13 21:15:29 +01:00
if (sock < 0) {
flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s",
safe_strerror(errno));
2002-12-13 21:15:29 +01:00
return -1;
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if (set_nonblocking(sock) < 0) {
flog_err(
EC_LIB_SOCKET,
"vtysh_accept: could not set vty socket %d to non-blocking, %s, closing",
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
sock, safe_strerror(errno));
close(sock);
return -1;
}
set_cloexec(sock);
2002-12-13 21:15:29 +01:00
#ifdef VTYSH_DEBUG
printf("VTY shell accept\n");
#endif /* VTYSH_DEBUG */
vty = vty_new();
vty->fd = sock;
vty->wfd = sock;
2002-12-13 21:15:29 +01:00
vty->type = VTY_SHELL_SERV;
vty->node = VIEW_NODE;
vty_event(VTYSH_READ, vty);
2002-12-13 21:15:29 +01:00
return 0;
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
static int vtysh_flush(struct vty *vty)
{
switch (buffer_flush_available(vty->obuf, vty->wfd)) {
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
case BUFFER_PENDING:
vty_event(VTYSH_WRITE, vty);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
break;
case BUFFER_ERROR:
vty->monitor =
0; /* disable monitoring to avoid infinite recursion */
flog_err(EC_LIB_SOCKET, "%s: write error to fd %d, closing",
__func__, vty->fd);
buffer_reset(vty->lbuf);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_reset(vty->obuf);
vty_close(vty);
return -1;
case BUFFER_EMPTY:
break;
}
return 0;
}
2002-12-13 21:15:29 +01:00
static int vtysh_read(struct thread *thread)
{
int ret;
int sock;
int nbytes;
struct vty *vty;
unsigned char buf[VTY_READ_BUFSIZ];
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
unsigned char *p;
uint8_t header[4] = {0, 0, 0, 0};
2002-12-13 21:15:29 +01:00
sock = THREAD_FD(thread);
vty = THREAD_ARG(thread);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if ((nbytes = read(sock, buf, VTY_READ_BUFSIZ)) <= 0) {
if (nbytes < 0) {
if (ERRNO_IO_RETRY(errno)) {
vty_event(VTYSH_READ, vty);
return 0;
}
vty->monitor = 0; /* disable monitoring to avoid
infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read failed on vtysh client fd %d, closing: %s",
__func__, sock, safe_strerror(errno));
}
buffer_reset(vty->lbuf);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
buffer_reset(vty->obuf);
2002-12-13 21:15:29 +01:00
vty_close(vty);
#ifdef VTYSH_DEBUG
printf("close vtysh\n");
#endif /* VTYSH_DEBUG */
return 0;
}
#ifdef VTYSH_DEBUG
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
printf("line: %.*s\n", nbytes, buf);
2002-12-13 21:15:29 +01:00
#endif /* VTYSH_DEBUG */
if (vty->length + nbytes >= VTY_BUFSIZ) {
/* Clear command line buffer. */
vty->cp = vty->length = 0;
vty_clear_buf(vty);
vty_out(vty, "%% Command is too long.\n");
} else {
for (p = buf; p < buf + nbytes; p++) {
vty->buf[vty->length++] = *p;
if (*p == '\0') {
/* Pass this line to parser. */
ret = vty_execute(vty);
/* Note that vty_execute clears the command buffer and resets
vty->length to 0. */
/* Return result. */
2002-12-13 21:15:29 +01:00
#ifdef VTYSH_DEBUG
printf("result: %d\n", ret);
printf("vtysh node: %d\n", vty->node);
2002-12-13 21:15:29 +01:00
#endif /* VTYSH_DEBUG */
/* hack for asynchronous "write integrated"
* - other commands in "buf" will be ditched
* - input during pending config-write is
* "unsupported" */
if (ret == CMD_SUSPEND)
break;
/* warning: watchfrr hardcodes this result write
*/
header[3] = ret;
buffer_put(vty->obuf, header, 4);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if (!vty->t_write && (vtysh_flush(vty) < 0))
/* Try to flush results; exit if a write
* error occurs. */
return 0;
}
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
}
2002-12-13 21:15:29 +01:00
if (vty->status == VTY_CLOSE)
vty_close(vty);
else
vty_event(VTYSH_READ, vty);
2002-12-13 21:15:29 +01:00
return 0;
}
static int vtysh_write(struct thread *thread)
{
struct vty *vty = THREAD_ARG(thread);
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
vtysh_flush(vty);
return 0;
}
2002-12-13 21:15:29 +01:00
#endif /* VTYSH */
/* Determine address family to bind. */
2004-10-07 21:33:46 +02:00
void vty_serv_sock(const char *addr, unsigned short port, const char *path)
2002-12-13 21:15:29 +01:00
{
/* If port is set to 0, do not listen on TCP/IP at all! */
if (port)
vty_serv_sock_addrinfo(addr, port);
2002-12-13 21:15:29 +01:00
#ifdef VTYSH
vty_serv_un(path);
#endif /* VTYSH */
}
static void vty_error_delete(void *arg)
{
struct vty_error *ve = arg;
XFREE(MTYPE_TMP, ve);
}
/* Close vty interface. Warning: call this only from functions that
will be careful not to access the vty afterwards (since it has
now been freed). This is safest from top-level functions (called
directly by the thread dispatcher). */
2002-12-13 21:15:29 +01:00
void vty_close(struct vty *vty)
{
int i;
bool was_stdio = false;
2002-12-13 21:15:29 +01:00
/* Drop out of configure / transaction if needed. */
vty_config_exit(vty);
2002-12-13 21:15:29 +01:00
/* Cancel threads.*/
THREAD_OFF(vty->t_read);
THREAD_OFF(vty->t_write);
THREAD_OFF(vty->t_timeout);
2002-12-13 21:15:29 +01:00
/* Flush buffer. */
buffer_flush_all(vty->obuf, vty->wfd);
2002-12-13 21:15:29 +01:00
/* Free input buffer. */
buffer_free(vty->obuf);
buffer_free(vty->lbuf);
2002-12-13 21:15:29 +01:00
/* Free command history. */
for (i = 0; i < VTY_MAXHIST; i++) {
XFREE(MTYPE_VTY_HIST, vty->hist[i]);
}
2002-12-13 21:15:29 +01:00
/* Unset vector. */
if (vty->fd != -1)
vector_unset(vtyvec, vty->fd);
2002-12-13 21:15:29 +01:00
if (vty->wfd > 0 && vty->type == VTY_FILE)
fsync(vty->wfd);
/* Close socket.
* note check is for fd > STDERR_FILENO, not fd != -1.
* We never close stdin/stdout/stderr here, because we may be
* running in foreground mode with logging to stdout. Also,
* additionally, we'd need to replace these fds with /dev/null. */
if (vty->wfd > STDERR_FILENO && vty->wfd != vty->fd)
close(vty->wfd);
if (vty->fd > STDERR_FILENO)
close(vty->fd);
if (vty->fd == STDIN_FILENO)
was_stdio = true;
2002-12-13 21:15:29 +01:00
XFREE(MTYPE_VTY, vty->buf);
2002-12-13 21:15:29 +01:00
if (vty->error) {
vty->error->del = vty_error_delete;
list_delete(&vty->error);
}
2002-12-13 21:15:29 +01:00
/* OK free vty. */
XFREE(MTYPE_VTY, vty);
if (was_stdio)
vty_stdio_reset(0);
2002-12-13 21:15:29 +01:00
}
/* When time out occur output message then close connection. */
static int vty_timeout(struct thread *thread)
{
struct vty *vty;
vty = THREAD_ARG(thread);
vty->v_timeout = 0;
/* Clear buffer*/
buffer_reset(vty->lbuf);
2002-12-13 21:15:29 +01:00
buffer_reset(vty->obuf);
vty_out(vty, "\nVty connection is timed out.\n");
2002-12-13 21:15:29 +01:00
/* Close connection. */
vty->status = VTY_CLOSE;
vty_close(vty);
return 0;
}
/* Read up configuration file from file_name. */
static void vty_read_file(struct nb_config *config, FILE *confp)
2002-12-13 21:15:29 +01:00
{
int ret;
struct vty *vty;
struct vty_error *ve;
struct listnode *node;
unsigned int line_num = 0;
2002-12-13 21:15:29 +01:00
vty = vty_new();
/* vty_close won't close stderr; if some config command prints
* something it'll end up there. (not ideal; it'd be beter if output
* from a file-load went to logging instead. Also note that if this
* function is called after daemonizing, stderr will be /dev/null.)
*
* vty->fd will be -1 from vty_new()
*/
vty->wfd = STDERR_FILENO;
vty->type = VTY_FILE;
2002-12-13 21:15:29 +01:00
vty->node = CONFIG_NODE;
vty->config = true;
if (config)
vty->candidate_config = config;
else {
vty->private_config = true;
vty->candidate_config = nb_config_new(NULL);
}
2002-12-13 21:15:29 +01:00
/* Execute configuration file */
ret = config_from_file(vty, confp, &line_num);
/* Flush any previous errors before printing messages below */
buffer_flush_all(vty->obuf, vty->wfd);
if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) {
const char *message = NULL;
char *nl;
2002-12-13 21:15:29 +01:00
switch (ret) {
case CMD_ERR_AMBIGUOUS:
message = "Ambiguous command";
break;
case CMD_ERR_NO_MATCH:
message = "No such command";
break;
case CMD_WARNING:
message = "Command returned Warning";
break;
case CMD_WARNING_CONFIG_FAILED:
message = "Command returned Warning Config Failed";
break;
case CMD_ERR_INCOMPLETE:
message = "Command returned Incomplete";
break;
case CMD_ERR_EXEED_ARGC_MAX:
message =
"Command exceeded maximum number of Arguments";
break;
default:
message = "Command returned unhandled error message";
break;
}
for (ALL_LIST_ELEMENTS_RO(vty->error, node, ve)) {
nl = strchr(ve->error_buf, '\n');
if (nl)
*nl = '\0';
flog_err(EC_LIB_VTY, "%s on config line %u: %s",
message, ve->line_num, ve->error_buf);
}
2002-12-13 21:15:29 +01:00
}
/*
* Automatically commit the candidate configuration after
* reading the configuration file.
*/
if (config == NULL) {
struct nb_context context = {};
char errmsg[BUFSIZ] = {0};
context.client = NB_CLIENT_CLI;
context.user = vty;
ret = nb_candidate_commit(&context, vty->candidate_config, true,
"Read configuration file", NULL,
errmsg, sizeof(errmsg));
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
zlog_err(
"%s: failed to read configuration file: %s (%s)",
__func__, nb_err_name(ret), errmsg);
}
2002-12-13 21:15:29 +01:00
vty_close(vty);
}
static FILE *vty_use_backup_config(const char *fullpath)
2002-12-13 21:15:29 +01:00
{
char *fullpath_sav, *fullpath_tmp;
FILE *ret = NULL;
int tmp, sav;
int c;
char buffer[512];
size_t fullpath_sav_sz = strlen(fullpath) + strlen(CONF_BACKUP_EXT) + 1;
fullpath_sav = malloc(fullpath_sav_sz);
strlcpy(fullpath_sav, fullpath, fullpath_sav_sz);
strlcat(fullpath_sav, CONF_BACKUP_EXT, fullpath_sav_sz);
sav = open(fullpath_sav, O_RDONLY);
if (sav < 0) {
2002-12-13 21:15:29 +01:00
free(fullpath_sav);
return NULL;
}
2002-12-13 21:15:29 +01:00
fullpath_tmp = malloc(strlen(fullpath) + 8);
snprintf(fullpath_tmp, strlen(fullpath) + 8, "%s.XXXXXX", fullpath);
2002-12-13 21:15:29 +01:00
/* Open file to configuration write. */
tmp = mkstemp(fullpath_tmp);
if (tmp < 0)
goto out_close_sav;
if (fchmod(tmp, CONFIGFILE_MASK) != 0)
goto out_close;
2002-12-13 21:15:29 +01:00
while ((c = read(sav, buffer, 512)) > 0) {
if (write(tmp, buffer, c) <= 0)
goto out_close;
}
2002-12-13 21:15:29 +01:00
close(sav);
close(tmp);
if (rename(fullpath_tmp, fullpath) == 0)
ret = fopen(fullpath, "r");
else
unlink(fullpath_tmp);
if (0) {
out_close:
close(tmp);
unlink(fullpath_tmp);
out_close_sav:
close(sav);
}
2002-12-13 21:15:29 +01:00
free(fullpath_sav);
free(fullpath_tmp);
return ret;
2002-12-13 21:15:29 +01:00
}
/* Read up configuration file from file_name. */
bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir)
2002-12-13 21:15:29 +01:00
{
char cwd[MAXPATHLEN];
2002-12-13 21:15:29 +01:00
FILE *confp = NULL;
const char *fullpath;
char *tmp = NULL;
bool read_success = false;
2002-12-13 21:15:29 +01:00
/* If -f flag specified. */
if (config_file != NULL) {
if (!IS_DIRECTORY_SEP(config_file[0])) {
if (getcwd(cwd, MAXPATHLEN) == NULL) {
flog_err_sys(
EC_LIB_SYSTEM_CALL,
"%s: failure to determine Current Working Directory %d!",
__func__, errno);
goto tmp_free_and_out;
}
size_t tmp_len = strlen(cwd) + strlen(config_file) + 2;
tmp = XMALLOC(MTYPE_TMP, tmp_len);
snprintf(tmp, tmp_len, "%s/%s", cwd, config_file);
fullpath = tmp;
2002-12-13 21:15:29 +01:00
} else
fullpath = config_file;
2002-12-13 21:15:29 +01:00
confp = fopen(fullpath, "r");
2002-12-13 21:15:29 +01:00
if (confp == NULL) {
flog_warn(
EC_LIB_BACKUP_CONFIG,
"%s: failed to open configuration file %s: %s, checking backup",
__func__, fullpath, safe_strerror(errno));
confp = vty_use_backup_config(fullpath);
if (confp)
flog_warn(EC_LIB_BACKUP_CONFIG,
"using backup configuration file!");
else {
flog_err(
EC_LIB_VTY,
"%s: can't open configuration file [%s]",
__func__, config_file);
goto tmp_free_and_out;
}
2002-12-13 21:15:29 +01:00
}
} else {
host_config_set(config_default_dir);
2002-12-13 21:15:29 +01:00
#ifdef VTYSH
int ret;
struct stat conf_stat;
/* !!!!PLEASE LEAVE!!!!
* This is NEEDED for use with vtysh -b, or else you can get
* a real configuration food fight with a lot garbage in the
* merged configuration file it creates coming from the per
* daemon configuration files. This also allows the daemons
* to start if there default configuration file is not
* present or ignore them, as needed when using vtysh -b to
* configure the daemons at boot - MAG
*/
/* Stat for vtysh Zebra.conf, if found startup and wait for
* boot configuration
*/
if (strstr(config_default_dir, "vtysh") == NULL) {
ret = stat(integrate_default, &conf_stat);
if (ret >= 0) {
read_success = true;
goto tmp_free_and_out;
}
}
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
if (confp == NULL) {
flog_err(
EC_LIB_SYSTEM_CALL,
"%s: failed to open configuration file %s: %s, checking backup",
__func__, config_default_dir,
safe_strerror(errno));
confp = vty_use_backup_config(config_default_dir);
if (confp) {
flog_warn(EC_LIB_BACKUP_CONFIG,
"using backup configuration file!");
fullpath = config_default_dir;
} else {
flog_err(EC_LIB_VTY,
"can't open configuration file [%s]",
config_default_dir);
goto tmp_free_and_out;
}
} else
fullpath = config_default_dir;
}
vty_read_file(config, confp);
read_success = true;
2002-12-13 21:15:29 +01:00
fclose(confp);
2002-12-13 21:15:29 +01:00
host_config_set(fullpath);
tmp_free_and_out:
XFREE(MTYPE_TMP, tmp);
return read_success;
2002-12-13 21:15:29 +01:00
}
/* Small utility function which output log to the VTY. */
void vty_log(const char *level, const char *proto_str, const char *msg,
struct timestamp_control *ctl)
2002-12-13 21:15:29 +01:00
{
unsigned int i;
2002-12-13 21:15:29 +01:00
struct vty *vty;
if (!vtyvec)
return;
2002-12-13 21:15:29 +01:00
for (i = 0; i < vector_active(vtyvec); i++)
2002-12-13 21:15:29 +01:00
if ((vty = vector_slot(vtyvec, i)) != NULL)
if (vty->monitor)
vty_log_out(vty, level, proto_str, msg, ctl);
2002-12-13 21:15:29 +01:00
}
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
/* Async-signal-safe version of vty_log for fixed strings. */
void vty_log_fixed(char *buf, size_t len)
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
{
unsigned int i;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
struct iovec iov[2];
char crlf[4] = "\r\n";
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
/* vty may not have been initialised */
if (!vtyvec)
return;
Fix most compiler warnings in default GCC build. Fix lots of warnings. Some const and type-pun breaks strict-aliasing warnings left but much reduced. * bgp_advertise.h: (struct bgp_advertise_fifo) is functionally identical to (struct fifo), so just use that. Makes it clearer the beginning of (struct bgp_advertise) is compatible with with (struct fifo), which seems to be enough for gcc. Add a BGP_ADV_FIFO_HEAD macro to contain the right cast to try shut up type-punning breaks strict aliasing warnings. * bgp_packet.c: Use BGP_ADV_FIFO_HEAD. (bgp_route_refresh_receive) fix an interesting logic error in (!ok || (ret != BLAH)) where ret is only well-defined if ok. * bgp_vty.c: Peer commands should use bgp_vty_return to set their return. * jhash.{c,h}: Can take const on * args without adding issues & fix warnings. * libospf.h: LSA sequence numbers use the unsigned range of values, and constants need to be set to unsigned, or it causes warnings in ospf6d. * md5.h: signedness of caddr_t is implementation specific, change to an explicit (uint_8 *), fix sign/unsigned comparison warnings. * vty.c: (vty_log_fixed) const on level is well-intentioned, but not going to fly given iov_base. * workqueue.c: ALL_LIST_ELEMENTS_RO tests for null pointer, which is always true for address of static variable. Correct but pointless warning in this case, but use a 2nd pointer to shut it up. * ospf6_route.h: Add a comment about the use of (struct prefix) to stuff 2 different 32 bit IDs into in (struct ospf6_route), and the resulting type-pun strict-alias breakage warnings this causes. Need to use 2 different fields to fix that warning? general: * remove unused variables, other than a few cases where they serve a sufficiently useful documentary purpose (e.g. for code that needs fixing), or they're required dummies. In those cases, try mark them as unused. * Remove dead code that can't be reached. * Quite a few 'no ...' forms of vty commands take arguments, but do not check the argument matches the command being negated. E.g., should 'distance X <prefix>' succeed if previously 'distance Y <prefix>' was set? Or should it be required that the distance match the previously configured distance for the prefix? Ultimately, probably better to be strict about this. However, changing from slack to strict might expose problems in command aliases and tools. * Fix uninitialised use of variables. * Fix sign/unsigned comparison warnings by making signedness of types consistent. * Mark functions as static where their use is restricted to the same compilation unit. * Add required headers * Move constants defined in headers into code. * remove dead, unused functions that have no debug purpose. (cherry picked from commit 7aa9dcef80b2ce50ecaa77653d87c8b84e009c49) Conflicts: bgpd/bgp_advertise.h bgpd/bgp_mplsvpn.c bgpd/bgp_nexthop.c bgpd/bgp_packet.c bgpd/bgp_route.c bgpd/bgp_routemap.c bgpd/bgp_vty.c lib/command.c lib/if.c lib/jhash.c lib/workqueue.c ospf6d/ospf6_lsa.c ospf6d/ospf6_neighbor.h ospf6d/ospf6_spf.c ospf6d/ospf6_top.c ospfd/ospf_api.c zebra/router-id.c zebra/rt_netlink.c zebra/rt_netlink.h
2014-09-19 15:42:23 +02:00
iov[0].iov_base = buf;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
iov[0].iov_len = len;
iov[1].iov_base = crlf;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
iov[1].iov_len = 2;
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
for (i = 0; i < vector_active(vtyvec); i++) {
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
struct vty *vty;
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
if (((vty = vector_slot(vtyvec, i)) != NULL) && vty->monitor)
/* N.B. We don't care about the return code, since
process is
most likely just about to die anyway. */
if (writev(vty->wfd, iov, 2) == -1) {
fprintf(stderr, "Failure to writev: %d\n",
errno);
exit(-1);
}
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * bgp_main.c: (main) The 2nd argument to openzlog has been removed. * isis_main.c: (main) The 2nd argument to openzlog has been removed. * ospf6_main.c: (main) The 2nd argument to openzlog has been removed. Note that stdout logging will no longer be enabled by default when not running as a daemon. * ospf_main.c: (main) The 2nd argument to openzlog has been removed. * rip_main.c: (main) The 2nd argument to openzlog has been removed. * ripng_main.c: (main) The 2nd argument to openzlog has been removed. * main.c: (main) The 2nd argument to openzlog has been removed. So stdout logging will no longer be enabled by default. * irdp_main.c: (irdp_finish) Reduce severity of shutdown message from LOG_WARNING to LOG_INFO. * vtysh.c: Make several functions static instead of global. Added several commands to support destination-specific logging levels. (vtysh_completion) This function is unused, so comment it out. * basic.texi: Document new logging features. Separate basic config commands from basic VTY commands. * log.h: Replace struct zlog flags and maskpri fields with maxlvl array to support individual logging levels for each destination. Remove the 2nd argument to openzlog since the default logging config should be standardized inside the library. Replaced the zlog_set_flag and zlog_reset_flag functions with zlog_set_level. And zlog_set_file now requires an additional log_level argument. Declare zlog_proto_names for use inside command.c in the "show logging" command. Added defines useful for command construction. * log.c: (vzlog) Decide where to send the message based on the individual logging levels configured for each destination. Remove support for ZLOG_STDERR since it was never actually used. Support record-priority for terminal monitors. (zlog_signal,zlog_backtrace_sigsafe) Support destination-specific logging levels. Remove stderr support (was never used). Added support for terminal monitor logging. (_zlog_assert_failed) Increase message severity to LOG_EMERG. (openzlog) Remove 2nd argument since default config should be standardized in library. By default, terminal monitoring is set to debug, and all other logging is disabled. (zlog_set_flag,zlog_reset_flag) Removed. (zlog_set_level) New function to replace zlog_set_flag and zlog_reset_flag. Supports destination-specific logging levels. (zlog_set_file,zlog_reset_file) Support file-specific logging level. (zlog_rotate) Log an error message if fopen fails, and support new file-specific logging level. * command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that command functions will be static instead of global. Remove declarations for config_exit and config_help. Define new macros DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can have deprecated commands in vtysh. Similarly, for completeness, define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED. Also, fix bug in ALIAS_ATTR macro (didn't matter because it was never used). * command.c: Make many functions static instead of global. (facility_name,facility_match,level_match) New functions to support enhanced destination-specific logging levels. (config_write_host) Support new destination-specific logging levels. (config_logmsg) Added new "logmsg" command to help test logging system. (show_logging) Added "show logging" command to show the current configuration of the logging system. (config_log_stdout_level) Support explicit stdout logging level. (no_config_log_stdout) Now takes optional LEVEL arg. (config_log_monitor,config_log_monitor_level,no_config_log_monitor) New commands creating new "log monitor" commands to set terminal monitoring log level. (config_log_file_level) Support explicit file logging level. (config_log_syslog_level) Support explicit syslog logging level. (config_log_facility,no_config_log_facility) Implement new "log facility" command. (cmd_init) Add hooks for new commands: "show logging", "logmsg", "log stdout <level>", "log monitor", "log monitor <level>", "no log monitor", "log file <filename> <level>", "no log file <filename> <level>", "log syslog <level>", "log facility", and "no log facility". * vty.h: Added a "level" argument to vty_log so it can support "log record-priority". Declare new function vty_log_fixed for use in signal handlers. * vty.c: (vty_log,vty_log_out) Added a "level" argument to support "log record-priority" for vty terminal monitors. (vty_down_level) Use config_exit_cmd.func instead of calling config_exit directly (since command functions will now be static instead of global). (vty_log_fixed) New function to send terminal monitor messages from inside a signal handler.
2004-12-07 16:39:31 +01:00
}
}
int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
2002-12-13 21:15:29 +01:00
{
if (exclusive && nb_running_lock(NB_CLIENT_CLI, vty)) {
vty_out(vty, "%% Configuration is locked by other client\n");
return CMD_WARNING;
2002-12-13 21:15:29 +01:00
}
vty->node = CONFIG_NODE;
vty->config = true;
vty->private_config = private_config;
vty->xpath_index = 0;
if (private_config) {
vty->candidate_config = nb_config_dup(running_config);
vty->candidate_config_base = nb_config_dup(running_config);
vty_out(vty,
"Warning: uncommitted changes will be discarded on exit.\n\n");
} else {
vty->candidate_config = vty_shared_candidate_config;
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
vty->candidate_config_base =
nb_config_dup(running_config);
}
return CMD_SUCCESS;
2002-12-13 21:15:29 +01:00
}
void vty_config_exit(struct vty *vty)
2002-12-13 21:15:29 +01:00
{
enum node_type node = vty->node;
struct cmd_node *cnode;
/* unlock and jump up to ENABLE_NODE if -and only if- we're
* somewhere below CONFIG_NODE */
while (node && node != CONFIG_NODE) {
cnode = vector_lookup(cmdvec, node);
node = cnode->parent_node;
}
if (node != CONFIG_NODE)
/* called outside config, e.g. vty_close() in ENABLE_NODE */
return;
while (vty->node != ENABLE_NODE)
/* will call vty_config_node_exit() below */
cmd_exit(vty);
}
int vty_config_node_exit(struct vty *vty)
{
vty->xpath_index = 0;
northbound: KISS always batch yang config (file read), it's faster The backoff code assumed that yang operations always completed quickly. It checked for > 100 YANG modeled commands happening in under 1 second to enable batching. If 100 yang modeled commands always take longer than 1 second batching is never enabled. This is the exact opposite of what we want to happen since batching speeds the operations up. Here are the results for libyang2 code without and with batching. | action | 1K rts | 2K rts | 1K rts | 2K rts | 20k rts | | | nobatch | nobatch | batch | batch | batch | | Add IPv4 | .881 | 1.28 | .703 | 1.04 | 8.16 | | Add Same IPv4 | 28.7 | 113 | .590 | .860 | 6.09 | | Rem 1/2 IPv4 | .376 | .442 | .379 | .435 | 1.44 | | Add Same IPv4 | 28.7 | 113 | .576 | .841 | 6.02 | | Rem All IPv4 | 17.4 | 71.8 | .559 | .813 | 5.57 | (IPv6 numbers are basically the same as iPv4, a couple percent slower) Clearly we need this. Please note the growth (1K to 2K) w/o batching is non-linear and 100 times slower than batched. Notes on code: The use of the new `nb_cli_apply_changes_clear_pending` is to commit any pending changes (including the current one). This is done when the code would not correctly handle a single diff that included the current changes with possible following changes. For example, a "no" command followed by a new value to replace it would be merged into a change, and the code would not deal well with that. A good example of this is BGP neighbor peer-group changing. The other use is after entering a router level (e.g., "router bgp") where the follow-on command handlers expect that router object to now exists. The code eventually needs to be cleaned up to not fail in these cases, but that is for future NB cleanup. Signed-off-by: Christian Hopps <chopps@labn.net>
2021-05-28 21:16:18 +02:00
/* Perform any pending commits. */
(void)nb_cli_pending_commit_check(vty);
lib: introduce configuration back-off timer for YANG-modeled commands When using the default CLI mode, the northbound layer needs to create a separate transaction to process each YANG-modeled command since they are supposed to be applied immediately (there's no candidate configuration nor the "commit" command like in the transactional CLI). The problem is that configuration transactions have an overhead associated to them, in big part because of the use of some heavy libyang functions like `lyd_validate()` and `lyd_diff()`. As of now this overhead is substantial and doesn't scale well when large numbers of transactions need to be performed in sequence. As an example, loading 50k prefix-lists using a single transaction takes about 2 seconds on a modern CPU. Loading the same 50k prefix-lists using 50k transactions can take more than an hour to complete (which is unacceptable by any standard). To fix this problem, some heavy optimization work needs to be done on libyang and on the FRR northbound itself too (e.g. perform partial configuration diffs whenever possible). This, however, should be a long term effort since these optimizations shouldn't be trivial to implement and we're far from having the performance numbers we need. In the meanwhile, this commit introduces a simple but efficient workaround to alleviate the issue. In short, a new back-off timer was introduced in the CLI to monitor and detect when too many YANG-modeled commands are being received at the same time. When a certain threshold is reached (100 YANG-modeled commands within one second), the northbound starts to group all subsequent commands into a single large transaction, which allows them to be processed much faster (e.g. seconds and not hours). It's essentially a protection mechanism that creates dynamically-sized transactions when necessary to prevent performance issues from happening. This mechanism is enabled both when parsing configuration files and when reading commands from a terminal. The downside of this optimization is that, if several YANG-modeled commands are grouped into the same transaction and at least one of them fails, the whole transaction is rejected. This is undesirable since users don't expect transactional behavior when that's not enabled explicitly. To minimize this issue, the CLI will log all commands that were rejected whenever that happens, to make the user aware of what happened and have enough information to fix the problem. Commands that fail due to parsing errors or CLI-level validations in general are rejected separately. Again, this proposed workaround is intended to be temporary. The goal is to provided a quick fix to issues like #6658 while we work on better long-term solutions. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2020-07-02 19:43:36 +02:00
lib: add support for confirmed commits Confirmed commits allow the user to request an automatic rollback to the previous configuration if the commit operation is not confirmed within a number of minutes. This is particularly useful when the user is accessing the CLI through the network (e.g. using SSH) and any configuration change might cause an unexpected loss of connectivity between the user and the managed device (e.g. misconfiguration of a routing protocol). By using a confirmed commit, the user can rest assured the connectivity will be restored after the given timeout expires, avoiding the need to access the router physically to fix the problem. When "commit confirmed TIMEOUT" is used, a new "commit" command is expected to confirm the previous commit before the given timeout expires. If "commit confirmed TIMEOUT" is used while there's already a confirmed-commit in progress, the confirmed-commit timeout is reset to the new value. In the current implementation, if other users perform commits while there's a confirmed-commit in progress, all commits are rolled back when the confirmed-commit timeout expires. It's recommended to use the "configure exclusive" configuration mode to prevent unexpected outcomes when using confirmed commits. When an user exits from the configuration mode while there's a confirmed-commit in progress, the commit is automatically rolled back and the user is notified about it. In the future we might want to prompt the user if he or she really wants to exit from the configuration mode when there's a pending confirmed commit. Needless to say, confirmed commit only work for configuration commands converted to the new northbound model. vtysh support will be implemented at a later time. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2018-12-06 23:37:05 +01:00
/* Check if there's a pending confirmed commit. */
if (vty->t_confirmed_commit_timeout) {
vty_out(vty,
"exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n");
lib: add support for confirmed commits Confirmed commits allow the user to request an automatic rollback to the previous configuration if the commit operation is not confirmed within a number of minutes. This is particularly useful when the user is accessing the CLI through the network (e.g. using SSH) and any configuration change might cause an unexpected loss of connectivity between the user and the managed device (e.g. misconfiguration of a routing protocol). By using a confirmed commit, the user can rest assured the connectivity will be restored after the given timeout expires, avoiding the need to access the router physically to fix the problem. When "commit confirmed TIMEOUT" is used, a new "commit" command is expected to confirm the previous commit before the given timeout expires. If "commit confirmed TIMEOUT" is used while there's already a confirmed-commit in progress, the confirmed-commit timeout is reset to the new value. In the current implementation, if other users perform commits while there's a confirmed-commit in progress, all commits are rolled back when the confirmed-commit timeout expires. It's recommended to use the "configure exclusive" configuration mode to prevent unexpected outcomes when using confirmed commits. When an user exits from the configuration mode while there's a confirmed-commit in progress, the commit is automatically rolled back and the user is notified about it. In the future we might want to prompt the user if he or she really wants to exit from the configuration mode when there's a pending confirmed commit. Needless to say, confirmed commit only work for configuration commands converted to the new northbound model. vtysh support will be implemented at a later time. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2018-12-06 23:37:05 +01:00
nb_cli_confirmed_commit_rollback(vty);
nb_cli_confirmed_commit_clean(vty);
}
(void)nb_running_unlock(NB_CLIENT_CLI, vty);
if (vty->candidate_config) {
if (vty->private_config)
nb_config_free(vty->candidate_config);
vty->candidate_config = NULL;
}
if (vty->candidate_config_base) {
nb_config_free(vty->candidate_config_base);
vty->candidate_config_base = NULL;
}
vty->config = false;
return 1;
}
2002-12-13 21:15:29 +01:00
/* Master of the threads. */
static struct thread_master *vty_master;
2002-12-13 21:15:29 +01:00
static void vty_event_serv(enum event event, int sock)
2002-12-13 21:15:29 +01:00
{
struct thread *vty_serv_thread = NULL;
2002-12-13 21:15:29 +01:00
switch (event) {
case VTY_SERV:
vty_serv_thread = thread_add_read(vty_master, vty_accept,
NULL, sock, NULL);
vector_set_index(Vvty_serv_thread, sock, vty_serv_thread);
2002-12-13 21:15:29 +01:00
break;
#ifdef VTYSH
case VTYSH_SERV:
vty_serv_thread = thread_add_read(vty_master, vtysh_accept,
NULL, sock, NULL);
vector_set_index(Vvty_serv_thread, sock, vty_serv_thread);
2002-12-13 21:15:29 +01:00
break;
#endif /* VTYSH */
default:
assert(!"vty_event_serv() called incorrectly");
}
}
static void vty_event(enum event event, struct vty *vty)
{
switch (event) {
#ifdef VTYSH
2002-12-13 21:15:29 +01:00
case VTYSH_READ:
thread_add_read(vty_master, vtysh_read, vty, vty->fd,
&vty->t_read);
break;
case VTYSH_WRITE:
thread_add_write(vty_master, vtysh_write, vty, vty->wfd,
&vty->t_write);
2002-12-13 21:15:29 +01:00
break;
#endif /* VTYSH */
case VTY_READ:
thread_add_read(vty_master, vty_read, vty, vty->fd,
&vty->t_read);
2002-12-13 21:15:29 +01:00
/* Time out treatment. */
if (vty->v_timeout) {
THREAD_OFF(vty->t_timeout);
thread_add_timer(vty_master, vty_timeout, vty,
vty->v_timeout, &vty->t_timeout);
}
2002-12-13 21:15:29 +01:00
break;
case VTY_WRITE:
thread_add_write(vty_master, vty_flush, vty, vty->wfd,
&vty->t_write);
2002-12-13 21:15:29 +01:00
break;
case VTY_TIMEOUT_RESET:
THREAD_OFF(vty->t_timeout);
if (vty->v_timeout)
thread_add_timer(vty_master, vty_timeout, vty,
vty->v_timeout, &vty->t_timeout);
2002-12-13 21:15:29 +01:00
break;
default:
assert(!"vty_event() called incorrectly");
2002-12-13 21:15:29 +01:00
}
}
DEFUN_NOSH (config_who,
2002-12-13 21:15:29 +01:00
config_who_cmd,
"who",
"Display who is on vty\n")
{
unsigned int i;
2002-12-13 21:15:29 +01:00
struct vty *v;
for (i = 0; i < vector_active(vtyvec); i++)
2002-12-13 21:15:29 +01:00
if ((v = vector_slot(vtyvec, i)) != NULL)
vty_out(vty, "%svty[%d] connected from %s.\n",
v->config ? "*" : " ", i, v->address);
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
/* Move to vty configuration mode. */
DEFUN_NOSH (line_vty,
2002-12-13 21:15:29 +01:00
line_vty_cmd,
"line vty",
"Configure a terminal line\n"
"Virtual terminal\n")
{
vty->node = VTY_NODE;
return CMD_SUCCESS;
}
/* Set time out value. */
static int exec_timeout(struct vty *vty, const char *min_str,
const char *sec_str)
2002-12-13 21:15:29 +01:00
{
unsigned long timeout = 0;
/* min_str and sec_str are already checked by parser. So it must be
all digit string. */
if (min_str) {
timeout = strtol(min_str, NULL, 10);
timeout *= 60;
}
if (sec_str)
timeout += strtol(sec_str, NULL, 10);
vty_timeout_val = timeout;
vty->v_timeout = timeout;
vty_event(VTY_TIMEOUT_RESET, vty);
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
DEFUN (exec_timeout_min,
exec_timeout_min_cmd,
"exec-timeout (0-35791)",
2002-12-13 21:15:29 +01:00
"Set timeout value\n"
"Timeout value in minutes\n")
{
int idx_number = 1;
return exec_timeout(vty, argv[idx_number]->arg, NULL);
2002-12-13 21:15:29 +01:00
}
DEFUN (exec_timeout_sec,
exec_timeout_sec_cmd,
"exec-timeout (0-35791) (0-2147483)",
2002-12-13 21:15:29 +01:00
"Set the EXEC timeout\n"
"Timeout in minutes\n"
"Timeout in seconds\n")
{
int idx_number = 1;
int idx_number_2 = 2;
return exec_timeout(vty, argv[idx_number]->arg,
argv[idx_number_2]->arg);
2002-12-13 21:15:29 +01:00
}
DEFUN (no_exec_timeout,
no_exec_timeout_cmd,
"no exec-timeout",
NO_STR
"Set the EXEC timeout\n")
{
return exec_timeout(vty, NULL, NULL);
}
/* Set vty access class. */
DEFUN (vty_access_class,
vty_access_class_cmd,
"access-class WORD",
"Filter connections based on an IP access list\n"
"IP access list\n")
{
int idx_word = 1;
2002-12-13 21:15:29 +01:00
if (vty_accesslist_name)
XFREE(MTYPE_VTY, vty_accesslist_name);
vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[idx_word]->arg);
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
/* Clear vty access class. */
DEFUN (no_vty_access_class,
no_vty_access_class_cmd,
"no access-class [WORD]",
NO_STR
"Filter connections based on an IP access list\n"
"IP access list\n")
{
int idx_word = 2;
const char *accesslist = (argc == 3) ? argv[idx_word]->arg : NULL;
if (!vty_accesslist_name
|| (argc == 3 && strcmp(vty_accesslist_name, accesslist))) {
vty_out(vty, "Access-class is not currently applied to vty\n");
return CMD_WARNING_CONFIG_FAILED;
2002-12-13 21:15:29 +01:00
}
XFREE(MTYPE_VTY, vty_accesslist_name);
vty_accesslist_name = NULL;
return CMD_SUCCESS;
}
/* Set vty access class. */
DEFUN (vty_ipv6_access_class,
vty_ipv6_access_class_cmd,
"ipv6 access-class WORD",
IPV6_STR
"Filter connections based on an IP access list\n"
"IPv6 access list\n")
{
int idx_word = 2;
2002-12-13 21:15:29 +01:00
if (vty_ipv6_accesslist_name)
XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[idx_word]->arg);
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
/* Clear vty access class. */
DEFUN (no_vty_ipv6_access_class,
no_vty_ipv6_access_class_cmd,
"no ipv6 access-class [WORD]",
NO_STR
IPV6_STR
"Filter connections based on an IP access list\n"
"IPv6 access list\n")
{
int idx_word = 3;
const char *accesslist = (argc == 4) ? argv[idx_word]->arg : NULL;
2002-12-13 21:15:29 +01:00
if (!vty_ipv6_accesslist_name
|| (argc == 4 && strcmp(vty_ipv6_accesslist_name, accesslist))) {
vty_out(vty,
"IPv6 access-class is not currently applied to vty\n");
return CMD_WARNING_CONFIG_FAILED;
2002-12-13 21:15:29 +01:00
}
XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
vty_ipv6_accesslist_name = NULL;
return CMD_SUCCESS;
}
/* vty login. */
DEFUN (vty_login,
vty_login_cmd,
"login",
"Enable password checking\n")
{
no_password_check = 0;
return CMD_SUCCESS;
}
DEFUN (no_vty_login,
no_vty_login_cmd,
"no login",
NO_STR
"Enable password checking\n")
{
no_password_check = 1;
return CMD_SUCCESS;
}
DEFUN (service_advanced_vty,
service_advanced_vty_cmd,
"service advanced-vty",
"Set up miscellaneous service\n"
"Enable advanced mode vty interface\n")
{
host.advanced = 1;
return CMD_SUCCESS;
}
DEFUN (no_service_advanced_vty,
no_service_advanced_vty_cmd,
"no service advanced-vty",
NO_STR
"Set up miscellaneous service\n"
"Enable advanced mode vty interface\n")
{
host.advanced = 0;
return CMD_SUCCESS;
}
DEFUN_NOSH (terminal_monitor,
2002-12-13 21:15:29 +01:00
terminal_monitor_cmd,
"terminal monitor",
"Set terminal line parameters\n"
"Copy debug output to the current terminal line\n")
{
vty->monitor = 1;
return CMD_SUCCESS;
}
DEFUN_NOSH (terminal_no_monitor,
2002-12-13 21:15:29 +01:00
terminal_no_monitor_cmd,
"terminal no monitor",
"Set terminal line parameters\n"
NO_STR
"Copy debug output to the current terminal line\n")
{
vty->monitor = 0;
return CMD_SUCCESS;
}
DEFUN_NOSH (no_terminal_monitor,
no_terminal_monitor_cmd,
"no terminal monitor",
NO_STR
"Set terminal line parameters\n"
"Copy debug output to the current terminal line\n")
{
return terminal_no_monitor(self, vty, argc, argv);
}
DEFUN_NOSH (show_history,
2002-12-13 21:15:29 +01:00
show_history_cmd,
"show history",
SHOW_STR
"Display the session command history\n")
{
int index;
for (index = vty->hindex + 1; index != vty->hindex;) {
if (index == VTY_MAXHIST) {
index = 0;
continue;
}
2002-12-13 21:15:29 +01:00
if (vty->hist[index] != NULL)
vty_out(vty, " %s\n", vty->hist[index]);
2002-12-13 21:15:29 +01:00
index++;
}
return CMD_SUCCESS;
}
/* vty login. */
DEFPY (log_commands,
log_commands_cmd,
"[no] log commands",
NO_STR
"Logging control\n"
"Log all commands\n")
{
if (no) {
if (do_log_commands_perm) {
vty_out(vty,
"Daemon started with permanent logging turned on for commands, ignoring\n");
return CMD_WARNING;
}
do_log_commands = false;
} else
do_log_commands = true;
return CMD_SUCCESS;
}
2002-12-13 21:15:29 +01:00
/* Display current configuration. */
static int vty_config_write(struct vty *vty)
{
vty_out(vty, "line vty\n");
2002-12-13 21:15:29 +01:00
if (vty_accesslist_name)
vty_out(vty, " access-class %s\n", vty_accesslist_name);
2002-12-13 21:15:29 +01:00
if (vty_ipv6_accesslist_name)
vty_out(vty, " ipv6 access-class %s\n",
vty_ipv6_accesslist_name);
2002-12-13 21:15:29 +01:00
/* exec-timeout */
if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
vty_out(vty, " exec-timeout %ld %ld\n", vty_timeout_val / 60,
vty_timeout_val % 60);
2002-12-13 21:15:29 +01:00
/* login */
if (no_password_check)
vty_out(vty, " no login\n");
if (do_log_commands)
vty_out(vty, "log commands\n");
vty_out(vty, "!\n");
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
static int vty_config_write(struct vty *vty);
2002-12-13 21:15:29 +01:00
struct cmd_node vty_node = {
.name = "vty",
.node = VTY_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-line)# ",
.config_write = vty_config_write,
2002-12-13 21:15:29 +01:00
};
/* Reset all VTY status. */
void vty_reset(void)
2002-12-13 21:15:29 +01:00
{
unsigned int i;
2002-12-13 21:15:29 +01:00
struct vty *vty;
struct thread *vty_serv_thread;
for (i = 0; i < vector_active(vtyvec); i++)
2002-12-13 21:15:29 +01:00
if ((vty = vector_slot(vtyvec, i)) != NULL) {
buffer_reset(vty->lbuf);
buffer_reset(vty->obuf);
vty->status = VTY_CLOSE;
vty_close(vty);
2002-12-13 21:15:29 +01:00
}
for (i = 0; i < vector_active(Vvty_serv_thread); i++)
2002-12-13 21:15:29 +01:00
if ((vty_serv_thread = vector_slot(Vvty_serv_thread, i))
!= NULL) {
THREAD_OFF(vty_serv_thread);
vector_slot(Vvty_serv_thread, i) = NULL;
2002-12-13 21:15:29 +01:00
close(i);
}
2002-12-13 21:15:29 +01:00
vty_timeout_val = VTY_TIMEOUT_DEFAULT;
XFREE(MTYPE_VTY, vty_accesslist_name);
XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2002-12-13 21:15:29 +01:00
}
2005-02-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * buffer.h: Make the struct buffer and struct buffer_data structures private by moving them inside buffer.c. Add comments for all functions. Rename buffer_write as buffer_put (to be more consistent with the buffer_putc and buffer_putstr functions). Declare a new buffer_write function that is used to write data to a file descriptor and/or add it to the buffer queue. Remove unused function buffer_flush_vty_all. Create a new enum typedef buffer_status_t to be used as the return code for all buffer_flush* functions and buffer_write. * buffer.c: The struct buffer and struct buffer_data declarations are now private to this file. In conjunction with that, remove some unnecessary fields: struct buffer (alloc, unused_head, unused_tail, length), struct buffer_data (prev). (buffer_data_new) Removed: functionality incorporated into buffer_add. (buffer_data_free) Removed: use a macro BUFFER_DATA_FREE instead. (buffer_new) Use calloc instead of malloc + memset(zero). Supply an appropriate default size if the specified size is 0. (buffer_free) Eliminate code duplication by calling buffer_reset to free the contents of the buffer (and remove unused code related to unused_head). (buffer_empty,buffer_putc,buffer_putstr) Aesthetic change (make more compact). (buffer_reset) Use macro BUFFER_DATA_FREE. No need to set alloc and length to 0 (these fields have been removed). (buffer_add) Fix scope to be static. Call XMALLOC directly instead of calling removed buffer_data_new function. Simplify the logic (since it's now a singly-linked list instead of doubly-linked). (buffer_write) Renamed to buffer_put. Change to void, since return code of 1 was meaningless. No need to adjust length field, since it has been removed. (buffer_putw,buffer_flush,buffer_flush_vty_all,buffer_flush_vty) Remove unused functions. (buffer_flush_all) Rewrite using buffer_flush_available to eliminate a possible failure mode if IOV_MAX is less than the number of buffers on the queue. (buffer_flush_window) Incorporate logic from buffer_flush_vty. Log an error message if there is a writev error. (buffer_flush_available) Be more paranoid: check for case where buffer is already empty. Use new ERRNO_IO_RETRY macro, and use new enum for return codes. Simplify deletion logic (since it's now a singly-linked list). (buffer_write) New function for use with non-blocking I/O. * vty.h: Replace the struct vty sb_buffer field with a fixed-size (5-character) sb_buf field and an sb_len field, since using a struct buffer was inappropriate for this task. Add some useful comments about telnet window size negotiation. * vty.c: Include <arpa/telnet.h> (no longer included by zebra.h). Remove VTY_OBUF_SIZE (instead use buffer_new default size). Make telnet_backward_char and telnet_space_char static const. (vty_out) Replace buffer_write with buffer_put. (vty_log_out) Check for I/O errors. If fatal, close the vty session. Consolidate 3 separate writes into a single write call. (vty_will_echo,vty_command,vty_next_line,vty_previous_line, vty_end_config,vty_describe_fold,vty_clear_buf,vty_serv_sock_addrinfo, vty_serv_sock_family,vty_serv_un,vty_use_backup_config,exec_timeout, vty_config_write,vty_save_cwd) Fix scope to static. (vty_new) Let buffer_new use its default buffer size. (vty_write) Fix signature: 2nd arg should be const char *. Replaced buffer_write with buffer_put. (vty_telnet_option) Fix minor bug (window height or width greater than 255 was broken). Use sb_buf and sb_len instead of removed sb_buffer (which was being used improperly). (vty_read) On error, use ERRNO_IO_RETRY to decide whether it's fatal. If the error is fatal, call buffer_reset so vty_close does not attempt to flush the data. Use new sb_buf and sb_len instead of sb_buffer to store the SB negotiation string. (vty_flush) When vty->lines is 0, call buffer_flush_available instead of buffer_flush_window. Look at the return code from buffer_flush to detect I/O errors (and in that case, log an error message and close the vty). (vty_create) Fix scope to static. Initialize sb_len to 0 instead of creating sb_buffer. (vty_accept) Set socket nonblocking. (vtysh_accept) Use new set_nonblocking function instead of calling fcntl directly. (vtysh_flush) New function called from vtysh_read (after command execution) and from vtysh_write. This flushes the buffer and reacts appropriately to the return code (by closing the vty or scheduling further flushes). (vtysh_read) Check whether error is fatal using ERRNO_IO_RETRY. If not, just try again later. Otherwise, call buffer_reset before calling vty_close (to avoid trying to flush the buffer in vty_close). Fix logic to allow case where a command does not arrive atomically in a single read call by checking for the terminating NUL char. (vtysh_write) Use new vtysh_flush helper function. (vty_close) No need to call buffer_empty, just call buffer_flush_all in any case (it will check whether the buffer is empty). Do not free sb_buffer (since it has been removed). (vty_log_fixed) Use writev instead of write. * zebra.h: Do not include <arpa/telnet.h>, since this is used only by lib/vty.c.
2005-02-23 16:12:34 +01:00
static void vty_save_cwd(void)
2002-12-13 21:15:29 +01:00
{
char *c;
c = getcwd(vty_cwd, sizeof(vty_cwd));
2002-12-13 21:15:29 +01:00
if (!c) {
/*
* At this point if these go wrong, more than likely
* the whole world is coming down around us
* Hence not worrying about it too much.
*/
if (!chdir(SYSCONFDIR)) {
flog_err_sys(EC_LIB_SYSTEM_CALL,
"Failure to chdir to %s, errno: %d",
SYSCONFDIR, errno);
exit(-1);
}
if (getcwd(vty_cwd, sizeof(vty_cwd)) == NULL) {
flog_err_sys(EC_LIB_SYSTEM_CALL,
"Failure to getcwd, errno: %d", errno);
exit(-1);
}
}
2002-12-13 21:15:29 +01:00
}
char *vty_get_cwd(void)
2002-12-13 21:15:29 +01:00
{
return vty_cwd;
}
int vty_shell(struct vty *vty)
{
return vty->type == VTY_SHELL ? 1 : 0;
}
int vty_shell_serv(struct vty *vty)
{
return vty->type == VTY_SHELL_SERV ? 1 : 0;
}
void vty_init_vtysh(void)
2002-12-13 21:15:29 +01:00
{
vtyvec = vector_init(VECTOR_MIN_SIZE);
}
/* Install vty's own commands like `who' command. */
void vty_init(struct thread_master *master_thread, bool do_command_logging)
2002-12-13 21:15:29 +01:00
{
/* For further configuration read, preserve current directory. */
vty_save_cwd();
2002-12-13 21:15:29 +01:00
vtyvec = vector_init(VECTOR_MIN_SIZE);
vty_master = master_thread;
atexit(vty_stdio_atexit);
2002-12-13 21:15:29 +01:00
/* Initilize server thread vector. */
Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE);
2002-12-13 21:15:29 +01:00
/* Install bgp top node. */
install_node(&vty_node);
2002-12-13 21:15:29 +01:00
install_element(VIEW_NODE, &config_who_cmd);
install_element(VIEW_NODE, &show_history_cmd);
install_element(CONFIG_NODE, &line_vty_cmd);
install_element(CONFIG_NODE, &service_advanced_vty_cmd);
install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
install_element(CONFIG_NODE, &show_history_cmd);
install_element(CONFIG_NODE, &log_commands_cmd);
if (do_command_logging) {
do_log_commands = true;
do_log_commands_perm = true;
}
2002-12-13 21:15:29 +01:00
install_element(ENABLE_NODE, &terminal_monitor_cmd);
install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
install_element(ENABLE_NODE, &no_terminal_monitor_cmd);
2002-12-13 21:15:29 +01:00
install_default(VTY_NODE);
install_element(VTY_NODE, &exec_timeout_min_cmd);
install_element(VTY_NODE, &exec_timeout_sec_cmd);
install_element(VTY_NODE, &no_exec_timeout_cmd);
install_element(VTY_NODE, &vty_access_class_cmd);
install_element(VTY_NODE, &no_vty_access_class_cmd);
install_element(VTY_NODE, &vty_login_cmd);
install_element(VTY_NODE, &no_vty_login_cmd);
install_element(VTY_NODE, &vty_ipv6_access_class_cmd);
install_element(VTY_NODE, &no_vty_ipv6_access_class_cmd);
}
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
void vty_terminate(void)
{
memset(vty_cwd, 0x00, sizeof(vty_cwd));
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
if (vtyvec && Vvty_serv_thread) {
vty_reset();
vector_free(vtyvec);
vector_free(Vvty_serv_thread);
vtyvec = NULL;
Vvty_serv_thread = NULL;
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
}
}