summaryrefslogtreecommitdiffstats
path: root/lib/vty.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vty.c')
-rw-r--r--lib/vty.c1467
1 files changed, 533 insertions, 934 deletions
diff --git a/lib/vty.c b/lib/vty.c
index d5d07676..831ce721 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1,4 +1,4 @@
-/* VTY top level
+/* VTY external interface
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*
* Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
@@ -21,36 +21,76 @@
* 02111-1307, USA.
*/
-#include "zebra.h"
-#include <stdbool.h>
+#include "misc.h"
#include "lib/version.h"
-#include "vty_io.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <unistd.h>
+
#include "vty.h"
-#include "uty.h"
+#include "vty_local.h"
+#include "vty_io.h"
+#include "vty_io_file.h"
+#include "vty_command.h"
#include "vty_cli.h"
+#include "vty_log.h"
+#include "vio_fifo.h"
+#include "log_local.h"
#include "list_util.h"
#include "command.h"
-#include "command_queue.h"
+#include "command_local.h"
#include "command_execute.h"
+#include "command_parse.h"
#include "memory.h"
-#include "log.h"
#include "mqueue.h"
+#include "qstring.h"
+#include "qpath.h"
+#include "network.h"
+
+/*==============================================================================
+ * The vty family comprises:
+ *
+ * vty -- level visible from outside the vty/command/log family
+ * and within those families.
+ *
+ * vty_common.h -- definitions used by both external and internal users
+ * vty_local.h -- definitions used within the family only
+ *
+ * vty_io -- top level of the vio handling
+ *
+ * vty_command -- functions called by the command family
+ * vty_log -- functions called by the log family
+ *
+ * vty_cli -- terminal command line handling
+ * vty_io_term -- terminal (telnet) I/O
+ * vty_io_vsh -- vtysh I/O
+ * vty_io_file -- file I/O
+ * vty_io_shell -- system shell I/O
+ *
+ * vty_io_basic -- common low level I/O handling
+ * encapsulates the differences between qpselect and legacy
+ * thread/select worlds.
+ *
+ * vio_lines -- for terminal: handles width, CRLF, line counting etc.
+ * vio_fifo -- for all vty types, indefinite size buffer
+ * qiovec -- using writev() to output contents of buffers
+ */
/*==============================================================================
- * Variables etc. (see uty.h)
+ * Variables etc. (see vty_local.h)
*/
/* The mutex and related debug counters */
qpt_mutex_t vty_mutex ;
-#if VTY_DEBUG
-
int vty_lock_count = 0 ;
-int vty_assert_fail = 0 ;
+#if VTY_DEBUG
+int vty_assert_fail = 0 ;
#endif
/* For thread handling -- initialised in vty_init */
@@ -59,43 +99,30 @@ struct thread_master* vty_master = NULL ;
/* In the qpthreads world, have nexus for the CLI and one for the Routeing
* Engine. Some commands are processed directly in the CLI, most have to
* be sent to the Routeing Engine.
+ *
+ * If not in the qpthreads world, vty_cli_nexus == vty_cmd_nexus == NULL.
+ *
+ * If in the qpthreads world these vty_cli_nexus == vty_cmd_nexus if not
+ * actually running pthreaded.
*/
-qpn_nexus vty_cli_nexus = NULL ;
-qpn_nexus vty_cmd_nexus = NULL ;
+bool vty_nexus ; /* true <=> in the qpthreads world */
+bool vty_multi_nexus ; /* true <=> more than one qpthread */
+
+qpn_nexus vty_cli_nexus = NULL ;
+qpn_nexus vty_cmd_nexus = NULL ;
/* List of all known vio */
-vty_io vio_list_base = NULL ;
+vty_io vio_live_list = NULL ;
/* List of all vty which are in monitor state. */
-vty_io vio_monitors_base = NULL ;
-
-/* List of all vty which are on death watch */
-vty_io vio_death_watch = NULL ;
-
-/* Vty timeout value -- see "exec timeout" command */
-unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
-
-/* Vty access-class command */
-char *vty_accesslist_name = NULL;
-
-/* Vty access-class for IPv6. */
-char *vty_ipv6_accesslist_name = NULL;
+vty_io vio_monitor_list = NULL ;
-/* Current directory -- initialised in vty_init() */
-static char *vty_cwd = NULL;
+/* List of child processes in our care */
+vio_child vio_childer_list = NULL ;
-/* Configure lock -- only one vty may be in CONFIG_NODE or above ! */
-bool vty_config = 0 ;
-
-/* Login password check override. */
-bool no_password_check = 0;
-
-/* Restrict unauthenticated logins? */
-const bool restricted_mode_default = 0 ;
- bool restricted_mode = 0 ;
-
-/* Watch-dog timer. */
-union vty_watch_dog vty_watch_dog = { NULL } ;
+/* See vty_child_signal_nexus_set() */
+qpt_mutex_t vty_child_signal_mutex ;
+qpn_nexus vty_child_signal_nexus = NULL ;
/*------------------------------------------------------------------------------
* VTYSH stuff
@@ -107,9 +134,12 @@ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG ;
/*------------------------------------------------------------------------------
* Prototypes
*/
-static void uty_reset (bool final, const char* why) ;
+static void uty_reset (const char* why, bool curtains) ;
static void uty_init_commands (void) ;
-static void vty_save_cwd (void) ;
+
+//static bool vty_terminal (struct vty *);
+//static bool vty_shell_server (struct vty *);
+//static bool vty_shell_client (struct vty *);
/*------------------------------------------------------------------------------
* Tracking the initialisation state.
@@ -143,23 +173,24 @@ static enum vty_init_state vty_init_state ;
extern void
vty_init (struct thread_master *master_thread)
{
- VTY_LOCK() ; /* Does nothing if !qpthreads_enabled */
VTY_ASSERT_CLI_THREAD() ; /* True if !qpthreads_enabled */
+ VTY_LOCK() ; /* Does nothing if !qpthreads_enabled */
assert(vty_init_state == vty_init_pending) ;
vty_master = master_thread; /* Local pointer to the master thread */
- vty_save_cwd (); /* need cwd for config reading */
+ vio_live_list = NULL ; /* no VTYs yet */
+ vio_childer_list = NULL ;
- vio_list_base = NULL ; /* no VTYs yet */
- vio_monitors_base = NULL ;
- vio_death_watch = NULL ;
-
- vty_cli_nexus = NULL ; /* not running qnexus-wise */
+ vty_nexus = false ; /* not running qnexus-wise */
+ vty_multi_nexus = false ; /* not more than one thread either */
+ vty_cli_nexus = NULL ;
vty_cmd_nexus = NULL ;
- vty_watch_dog.anon = NULL ; /* no watch dog */
+ vty_child_signal_nexus = NULL ; /* none, yet */
+
+ uty_init_monitor() ;
uty_init_commands() ; /* install nodes */
@@ -190,10 +221,14 @@ vty_init_r (qpn_nexus cli, qpn_nexus cmd)
{
assert(vty_init_state == vty_init_1st_stage) ;
- vty_cli_nexus = cli ;
- vty_cmd_nexus = cmd ;
+ vty_nexus = true ;
+ vty_multi_nexus = (cli != cmd) ;
+ vty_cli_nexus = cli ;
+ vty_cmd_nexus = cmd ;
+
+ qpt_mutex_init(vty_mutex, qpt_mutex_recursive);
- qpt_mutex_init(&vty_mutex, qpt_mutex_recursive);
+ qpt_mutex_init(vty_child_signal_mutex, qpt_mutex_quagga);
vty_init_state = vty_init_2nd_stage ;
} ;
@@ -214,7 +249,7 @@ vty_init_vtysh (void)
/*------------------------------------------------------------------------------
* Start the VTY going.
*
- * This starts the listeners for VTY_TERM and VTY_SHELL_SERV.
+ * This starts the listeners for VTY_TERMINAL and VTY_SHELL_SERVER.
*
* Also starts the watch dog.
*
@@ -222,14 +257,12 @@ vty_init_vtysh (void)
* any threads are started -- so is, implicitly, in the CLI thread.
*
* NB: may be called once and once only.
- *
- * NB: MUST be in the CLI thread (if any).
*/
extern void
vty_start(const char *addr, unsigned short port, const char *path)
{
- VTY_LOCK() ;
VTY_ASSERT_CLI_THREAD() ;
+ VTY_LOCK() ;
assert( (vty_init_state == vty_init_1st_stage)
|| (vty_init_state == vty_init_2nd_stage) ) ;
@@ -249,40 +282,49 @@ extern void
vty_reset()
{
vty_reset_because("Reset") ;
-}
+} ;
/*------------------------------------------------------------------------------
- * Reset all VTY status
- *
- * This is done in response to SIGHUP -- and runs in the CLI thread.
+ * Reset all VTY.
*
- * Half closes all VTY, leaving the death watch to tidy up once all output
- * and any command in progress have completed.
+ * This is done in response to SIGHUP/SIGINT -- and runs in the CLI pthread
+ * (if there is one).
*
- * Closes all listening sockets.
+ * Stops any command loop and closes all VTY, "final". Issues the "why"
+ * message just before closing the base output.
*
- * TODO: revoke ?
+ * Note that if a command loop is currently executing a command in the
+ * Routing Engine pthread, then when that completes the command loop will stop
+ * and close the VTY. So completion of the close depends on the CLI pthread
+ * continuing to run and consume messages. The Routing Engine will act on
+ * the SIGHUP/SIGINT/SIGTERM when it consumes a message sent to it, so any
+ * currently executing command will complete, before any further action is
+ * taken.
*
- * NB: old code discarded all output and hard closed all the VTY...
+ * Closes all listening sockets.
*/
extern void
vty_reset_because(const char* why)
{
- VTY_LOCK() ;
VTY_ASSERT_CLI_THREAD() ;
+ VTY_LOCK() ;
+
+ if (vty_init_state != vty_init_reset)
+ {
+ assert(vty_init_state == vty_init_started) ;
- assert(vty_init_state == vty_init_started) ;
+ uty_reset(why, false) ; /* not curtains */
- uty_reset(0, why) ; /* not final ! */
+ vty_init_state = vty_init_reset ;
+ } ;
- vty_init_state = vty_init_reset ;
VTY_UNLOCK() ;
-}
+} ;
/*------------------------------------------------------------------------------
- * Restart the VTY, following a vty_reset().
+ * Restart the VTY, following a vty_reset()/vty_reset_because().
*
- * This starts the listeners for VTY_TERM and VTY_SHELL_SERV, again.
+ * This starts the listeners for VTY_TERMINAL and VTY_SHELL_SERVER, again.
*
* NB: may be called once, and once only, *after* a vty_reset().
*
@@ -296,7 +338,7 @@ struct vty_restart_args
} ;
MQB_ARGS_SIZE_OK(vty_restart_args) ;
-static void uty_restart_action(mqueue_block mqb, mqb_flag_t flag) ;
+static void vty_restart_action(mqueue_block mqb, mqb_flag_t flag) ;
static void uty_restart(const char *addr, unsigned short port,
const char *path) ;
extern void
@@ -308,14 +350,14 @@ vty_restart(const char *addr, unsigned short port, const char *path)
*
* Otherwise, construct and dispatch message to do a uty_restart.
*/
- if (!vty_cli_nexus)
+ if (!vty_nexus)
uty_restart(addr, port, path) ;
else
{
mqueue_block mqb ;
struct vty_restart_args* args ;
- mqb = mqb_init_new(NULL, uty_restart_action, vty_cli_nexus) ;
+ mqb = mqb_init_new(NULL, vty_restart_action, vty_cli_nexus) ;
args = mqb_get_args(mqb) ;
if (addr != NULL)
@@ -330,7 +372,7 @@ vty_restart(const char *addr, unsigned short port, const char *path)
else
args->path = NULL ;
- mqueue_enqueue(vty_cli_nexus->queue, mqb, 0) ;
+ mqueue_enqueue(vty_cli_nexus->queue, mqb, mqb_priority) ;
} ;
VTY_UNLOCK() ;
@@ -338,7 +380,7 @@ vty_restart(const char *addr, unsigned short port, const char *path)
/* Deal with the uty_restart message */
static void
-uty_restart_action(mqueue_block mqb, mqb_flag_t flag)
+vty_restart_action(mqueue_block mqb, mqb_flag_t flag)
{
struct vty_restart_args* args ;
args = mqb_get_args(mqb) ;
@@ -388,89 +430,131 @@ uty_restart(const char *addr, unsigned short port, const char *path)
extern void
vty_terminate (void)
{
+ VTY_ASSERT_CLI_THREAD() ;
+
if ( (vty_init_state == vty_init_pending)
|| (vty_init_state == vty_init_terminated) )
- return ; /* nothing to do ! */
+ return ; /* nothing to do ! */
VTY_LOCK() ;
- VTY_ASSERT_CLI_THREAD() ;
assert( (vty_init_state > vty_init_pending)
&& (vty_init_state < vty_init_terminated) ) ;
- uty_reset(1, "Shut down") ; /* final reset */
+ uty_reset("Shut down", true) ; /* curtains */
+
+ vty_child_close_register() ;
VTY_UNLOCK() ;
- qpt_mutex_destroy(&vty_mutex, 0);
+ qpt_mutex_destroy(vty_mutex, 0);
+ qpt_mutex_destroy(vty_child_signal_mutex, 0);
vty_init_state = vty_init_terminated ;
}
/*------------------------------------------------------------------------------
- * Reset -- final or for SIGHUP
+ * Reset -- for SIGHUP/SIGINT or at final curtain.
+ *
+ * Closes listeners and resets the vty timeout and access lists.
+ *
+ * Closes all vty "final" -- see uty_close(). Before can close the vty must
+ * stop any related command loop -- see uty_cmd_loop_stop():
+ *
+ * * at "not-curtains" this is called in the *CLI* pthread, with all message
+ * and event handling is still running.
+ *
+ * This is called *before* a message is sent to the Routing Engine pthread
+ * to inform it that a SIGHUP/SIGINT/SIGTERM has been seen.
+ *
+ * It is possible that the command loop for a given vty cannot be stopped
+ * immediately and must be left to continue, until it sees the CMD_STOP
+ * vio->signal which will be set.
+ *
+ * * at "curtains" the system is being terminated, all threads have been
+ * joined, so is implicity in the CLI thread, but all message and event
+ * handling has stopped
+ *
+ * At "curtains" it is always possible to stop any command loop.
+ *
+ * This is part of vty_terminate -- see above.
+ *
+ * Close down is then a two step process:
*
- * Closes listeners.
+ * 1. vty_reset()/vty_reset_because() -- which immediately closes everything
+ * that does not have to wait for a command loop to stop, and anything
+ * that remains will be closed, automatically, as soon as possible.
*
- * Closes (final) or half closes (SIGHUP) all VTY, and revokes any outstanding
- * commands.
+ * 2. vty_terminate() -- which sweeps up and closes anything that remains
+ * to be closed, and which the automatic mechanism has not got to yet.
*
- * Resets the vty timeout and access lists.
+ * So, for each vty, if uty_cmd_loop_stop() does stop the command loop, then:
*
- * When reach final reset it should not be possible for there to be any
- * commands still in progress. If there are, they are simply left on the
- * death-watch list... there is no pressing need to do anything more radical,
- * and the presence of anything on the death watch is grounds for some debug
- * activity !
+ * * the close of the vty proceeds immediately.
+ *
+ * Otherwise:
+ *
+ * * the CMD_STOP vio->signal has been set and the vty is left open.
+ *
+ * Note that the command loop *must* be running in the vty_cmd_nexus
+ * -- see uty_cmd_loop_stop().
+ *
+ * * nothing further will happen until the Routing Engine collects the
+ * CMD_STOP vio->signal, and sends a message to pass the command loop
+ * back to the CLI pthread, to deal with the CMD_STOP.
+ *
+ * Before passing the command loop back, the Routing Engine will release
+ * the config symbol of power. So, if the Routing Engine goes on to
+ * re-read the configuration, it does not have to wait for the CLI to get
+ * round to stopping the vty.
+ *
+ * * when the CLI pthread receives the command loop back, it will collect the
+ * CMD_STOP (again) stop the command loop and close the vty.
+ *
+ * * when the Routing Engine picks up any SIGHUP/SIGTERM/etc message, it
+ * will either re-read the configuration or vty_terminate().
+ *
+ * The Routing Engine will not do this until after it has come out
+ * of the command loop, after dealing with the vio->signal, as above.
*/
static void
-uty_reset (bool curtains, const char* why)
+uty_reset (const char* why, bool curtains)
{
vty_io vio ;
vty_io next ;
- VTY_ASSERT_LOCKED() ;
- VTY_ASSERT_CLI_THREAD() ;
+ VTY_ASSERT_CLI_THREAD_LOCKED() ;
uty_close_listeners() ;
- next = sdl_head(vio_list_base) ;
+ next = sdl_head(vio_live_list) ;
while (next != NULL)
{
vio = next ;
next = sdl_next(vio, vio_list) ;
- if (vio->type == VTY_TERM)
- cq_revoke(vio->vty) ;
-
- if (why != NULL)
- vio->close_reason = why ;
+ /* Save the close reason for later, unless one is already set. */
+ if ((why != NULL) && (vio->close_reason == NULL))
+ vio->close_reason = XSTRDUP(MTYPE_TMP, why) ;
- if (curtains)
+ /* Stop the command loop -- if not already stopped.
+ *
+ * If command loop is running, it will be signalled to stop, soonest.
+ */
+ if (uty_cmd_loop_stop(vio, curtains))
uty_close(vio) ;
- else
- uty_half_close(vio, why) ;
} ;
- vty_timeout_val = VTY_TIMEOUT_DEFAULT;
-
- if (vty_accesslist_name)
- {
- XFREE(MTYPE_VTY, vty_accesslist_name);
- vty_accesslist_name = NULL;
- }
+ host.vty_timeout_val = VTY_TIMEOUT_DEFAULT;
- if (vty_ipv6_accesslist_name)
- {
- XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
- vty_ipv6_accesslist_name = NULL;
- }
+ XFREE(MTYPE_HOST, host.vty_accesslist_name) ;
+ /* sets host.vty_accesslist_name = NULL */
- if (curtains && vty_cwd)
- XFREE (MTYPE_TMP, vty_cwd);
+ XFREE(MTYPE_HOST, host.vty_ipv6_accesslist_name);
+ /* sets host.vty_ipv6_accesslist_name = NULL */
if (curtains)
- uty_watch_dog_stop() ; /* and final death watch run */
+ uty_watch_dog_stop() ;
} ;
/*==============================================================================
@@ -484,59 +568,78 @@ uty_reset (bool curtains, const char* why)
/*------------------------------------------------------------------------------
* Create a new VTY of the given type
*
- * The type may NOT be: VTY_TERM or VTY_SHELL_SERV
+ * The type may NOT be: VTY_TERMINAL or VTY_SHELL_SERVER
+ *
+ * Appears only to be used by vtysh !! TODO ????
*/
-extern struct vty *
-vty_open(enum vty_type type)
+extern vty
+vty_open(vty_type_t type, node_type_t node)
{
struct vty* vty ;
VTY_LOCK() ;
- vty = uty_new(type, -1) ; /* fails for VTY_TERM or VTY_SHELL_SERV */
+ vty = uty_new(type, node) ;
VTY_UNLOCK() ;
return vty ;
} ;
-/*------------------------------------------------------------------------------
- * Close the given VTY
- */
-extern void
-vty_close (struct vty *vty)
-{
- VTY_LOCK() ;
- uty_close(vty->vio) ;
- VTY_UNLOCK() ;
-}
-
/*==============================================================================
* General VTY output.
*
- * This is mostly used during command execution, to output the results of the
- * command.
+ * This is used during command execution, to output the results of commands.
*
* All these end up in uty_vout -- see vty_io.
*/
/*------------------------------------------------------------------------------
* VTY output -- cf fprintf !
+ *
+ * This is for command output, which may later be suppressed
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed (see errno)
*/
extern int
-vty_out (struct vty *vty, const char *format, ...)
+vty_out(struct vty *vty, const char *format, ...)
{
- int result;
+ int ret ;
+ va_list args ;
VTY_LOCK() ;
- va_list args;
- va_start (args, format);
- result = uty_vout(vty, format, args);
- va_end (args);
+
+ va_start (args, format) ;
+ ret = vio_fifo_vprintf(vty->vio->obuf, format, args) ;
+ va_end (args) ;
+
VTY_UNLOCK() ;
- return result;
+ return ret ;
+}
+
+/*------------------------------------------------------------------------------
+ * VTY output -- cf write
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed (see errno)
+ */
+extern int
+vty_write(struct vty *vty, const void* buf, int n)
+{
+ VTY_LOCK() ;
+
+ vio_fifo_put_bytes(vty->vio->obuf, buf, n) ;
+
+ VTY_UNLOCK() ;
+ return 0 ;
}
/*------------------------------------------------------------------------------
* VTY output -- output a given numnber of spaces
+ *
+ * This is for command output, which may be suppressed
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed (see errno)
*/
/* 1 2 3 4 */
@@ -544,14 +647,19 @@ vty_out (struct vty *vty, const char *format, ...)
const char vty_spaces_string[] = " " ;
CONFIRM(VTY_MAX_SPACES == (sizeof(vty_spaces_string) - 1)) ;
-extern void
+extern int
vty_out_indent(struct vty *vty, int indent)
{
- while (indent > 0)
+ int ret ;
+
+ ret = 0 ;
+ while ((indent > 0) && (ret >= 0))
{
- vty_out(vty, VTY_SPACES(indent)) ;
+ ret = vty_out(vty, VTY_SPACES(indent)) ;
indent -= VTY_MAX_SPACES ;
}
+
+ return ret ;
} ;
/*------------------------------------------------------------------------------
@@ -565,9 +673,9 @@ vty_time_print (struct vty *vty, int cr)
quagga_timestamp(0, buf, sizeof(buf)) ;
if (cr)
- vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ vty_out(vty, "%s\n", buf);
else
- vty_out (vty, "%s ", buf);
+ vty_out(vty, "%s ", buf);
return;
}
@@ -575,474 +683,116 @@ vty_time_print (struct vty *vty, int cr)
/*------------------------------------------------------------------------------
* Say hello to vty interface.
*/
-void
+extern void
vty_hello (struct vty *vty)
{
- VTY_LOCK() ;
-
-#ifdef QDEBUG
- uty_out (vty, "%s%s", debug_banner, VTY_NEWLINE);
-#endif
- if (host.motdfile)
- {
- FILE *f;
- char buf[4096];
+ qpath path ;
+ const char* string ;
- f = fopen (host.motdfile, "r");
- if (f)
- {
- while (fgets (buf, sizeof (buf), f))
- {
- char *s;
- /* work backwards to ignore trailing isspace() */
- for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
- s--);
- *s = '\0';
- uty_out (vty, "%s%s", buf, VTY_NEWLINE);
- }
- fclose (f);
- }
- else
- uty_out (vty, "MOTD file %s not found%s", host.motdfile, VTY_NEWLINE);
- }
- else if (host.motd)
- uty_out (vty, "%s", host.motd);
-
- VTY_UNLOCK() ;
-}
-
-/*------------------------------------------------------------------------------
- * Clear the contents of the command output FIFO etc.
- */
-extern void
-vty_out_clear(struct vty* vty)
-{
VTY_LOCK() ;
- uty_out_clear(vty->vio) ;
- VTY_UNLOCK() ;
-} ;
-
-/*==============================================================================
- * Command Execution
- */
-
-/*------------------------------------------------------------------------------
- * Execute command -- adding to history is not empty or just comment
- *
- * This is for VTY_TERM type VTY.
- *
- * Outputs diagnostics if fails to parse.
- *
- * Returns: command return code
- */
-extern enum cmd_return_code
-uty_command(struct vty *vty)
-{
- enum cmd_return_code ret;
-
- VTY_ASSERT_LOCKED() ;
- VTY_ASSERT_CLI_THREAD() ;
- assert(vty->vio->type == VTY_TERM) ;
+ path = (host.motdfile != NULL) ? qpath_dup(host.motdfile) : NULL ;
+ string = host.motd ;
- /* Parse the command and add to history (if not empty) */
- ret = cmd_parse_command(vty,
- cmd_parse_completion + cmd_parse_do + cmd_parse_tree) ;
- if (ret != CMD_EMPTY)
- uty_cli_hist_add (vty->vio, vty->buf) ;
-
- /* If parsed and not empty, dispatch */
- if (ret == CMD_SUCCESS)
- {
-#ifdef CONSUMED_TIME_CHECK
- RUSAGE_T before;
- RUSAGE_T after;
- unsigned long realtime, cputime;
-
- GETRUSAGE(&before);
-#endif /* CONSUMED_TIME_CHECK */
-
- ret = cmd_dispatch(vty, cmd_may_queue) ;
-
-#ifdef CONSUMED_TIME_CHECK
- GETRUSAGE(&after);
- if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
- CONSUMED_TIME_CHECK)
- /* Warn about CPU hog that must be fixed. */
- uzlog(NULL, LOG_WARNING,
- "SLOW COMMAND: command took %lums (cpu time %lums): %s",
- realtime/1000, cputime/1000, vty->buf) ;
-#endif /* CONSUMED_TIME_CHECK */
- } ;
-
- /* Deal with the return code */
- switch (ret)
- {
- case CMD_ERR_AMBIGUOUS:
- uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
- break;
+ VTY_UNLOCK() ;
- case CMD_ERR_NO_MATCH:
- uty_out (vty, "%% Unknown command.%s", VTY_NEWLINE) ;
- break;
+ if (qdebug)
+ vty_out (vty, "%s\n", debug_banner);
- case CMD_ERR_INCOMPLETE:
- uty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
- break;
+ if (path != NULL)
+ vty_cat_file(vty, path, "motd file") ;
+ else if (string != NULL)
+ vty_out(vty, "%s", string);
- default:
- break ;
- } ;
+ /* This "\n" is a bit magic... if the motd file does not end in a "\n",
+ * then this makes sure that we start on a new line.
+ *
+ * Similarly, if the motd string doesn't end '\n', then this makes sure.
+ *
+ * This will also trim trailing space from the end of the motd message.
+ *
+ * Generally these will end in '\n', so this produces the extra blank line
+ * before the cheerful "User authentication" message, which is the most
+ * likely next line.
+ */
+ vty_out(vty, "\n") ;
- return ret ;
+ qpath_free(path) ;
} ;
/*------------------------------------------------------------------------------
- * Authentication of vty
+ * "cat" file to vty
*
- * During AUTH_NODE and AUTH_ENABLE_NODE, when a command line is dispatched by
- * any means this function is called.
*
- * Note that if the AUTH_NODE password fails too many times, the terminal is
- * closed.
- *
- * Returns: command return code
*/
-extern enum cmd_return_code
-uty_auth (struct vty *vty, const char *buf, enum cli_do cli_do)
+extern cmd_return_code_t
+vty_cat_file(vty vty, qpath path, const char* desc)
{
- char *passwd = NULL;
- enum node_type next_node = 0;
- int fail;
- char *crypt (const char *, const char *);
- enum cmd_return_code ret ;
-
- vty_io vio = vty->vio ;
-
- VTY_ASSERT_LOCKED() ;
- VTY_ASSERT_CLI_THREAD() ;
-
- /* What to do ?
- *
- * In fact, all the exotic command terminators simply discard any input
- * and return.
- */
- switch (cli_do)
- {
- case cli_do_nothing:
- case cli_do_ctrl_c:
- case cli_do_ctrl_z:
- return CMD_SUCCESS ;
+ int fd ;
+ void* buf ;
- case cli_do_command:
- break ;
+ fd = uty_fd_file_open(qpath_string(path), vfd_io_read | vfd_io_blocking, 0) ;
- case cli_do_ctrl_d:
- case cli_do_eof:
- return uty_cmd_close(vty, "End") ;
-
- default:
- zabort("unknown or invalid cli_do") ;
- } ;
-
- /* Ordinary command dispatch -- see if password is OK. */
- switch (vty->node)
- {
- case AUTH_NODE:
- if (host.encrypt)
- passwd = host.password_encrypt;
- else
- passwd = host.password;
- if (host.advanced)
- next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
- else
- next_node = VIEW_NODE;
- break;
-
- case AUTH_ENABLE_NODE:
- if (host.encrypt)
- passwd = host.enable_encrypt;
- else
- passwd = host.enable;
- next_node = ENABLE_NODE;
- break;
-
- default:
- zabort("unknown node type") ;
- }
-
- if (passwd)
+ if (fd < 0)
{
- if (host.encrypt)
- fail = strcmp (crypt(buf, passwd), passwd);
- else
- fail = strcmp (buf, passwd);
- }
- else
- fail = 1;
+ vty_out (vty, "Cannot open %s file '%s': %s (%s)\n", desc,
+ qpath_string(path), errtostr(errno, 0).str,
+ errtoname(errno, 0).str) ;
+ return CMD_WARNING;
+ } ;
- ret = CMD_SUCCESS ;
+ enum { buffer_size = 32 * 1024 } ;
+ buf = XMALLOC(MTYPE_TMP, buffer_size) ;
- if (! fail)
- {
- vio->fail = 0;
- vty->node = next_node; /* Success ! */
- }
- else
+ while (1)
{
- vio->fail++;
- if (vio->fail >= 3)
- {
- if (vty->node == AUTH_NODE)
- {
- ret = uty_cmd_close(vty, "Bad passwords, too many failures!%s") ;
- }
- else
- {
- /* AUTH_ENABLE_NODE */
- vio->fail = 0;
- uty_out (vty, "%% Bad enable passwords, too many failures!%s",
- VTY_NEWLINE);
- vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
-
- ret = CMD_WARNING ;
- }
- }
- }
-
- return ret ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Command line "exit" command -- aka "quit"
- *
- * Falls back one NODE level.
- *
- * Returns: command return code
- */
-extern enum cmd_return_code
-vty_cmd_exit(struct vty* vty)
-{
- enum cmd_return_code ret ;
+ int r ;
- VTY_LOCK() ;
+ r = readn(fd, buf, buffer_size) ;
- ret = CMD_SUCCESS ;
- switch (vty->node)
- {
- case VIEW_NODE:
- case ENABLE_NODE:
- case RESTRICTED_NODE:
- if (vty_shell (vty))
- exit (0);
+ if (r > 0)
+ vty_write(vty, buf, r) ; // TODO push ??
else
- ret = uty_cmd_close(vty, "Exit") ;
- break;
- case CONFIG_NODE:
- uty_config_unlock (vty, ENABLE_NODE);
- break;
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case BGP_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case MASC_NODE:
- case RMAP_NODE:
- case VTY_NODE:
- vty->node = CONFIG_NODE ;
- break;
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- vty->node = BGP_NODE ;
- break;
- case KEYCHAIN_KEY_NODE:
- vty->node = KEYCHAIN_NODE ;
- break;
- default:
- break;
- }
-
- VTY_UNLOCK() ;
- return ret ;
-}
-
-/*------------------------------------------------------------------------------
- * Command line "end" command
- *
- * Falls back to ENABLE_NODE.
- *
- * Returns: command return code
- */
-extern enum cmd_return_code
-vty_cmd_end(struct vty* vty)
-{
- VTY_LOCK() ;
+ {
+ if (r == 0)
+ break ;
- switch (vty->node)
- {
- case VIEW_NODE:
- case ENABLE_NODE:
- case RESTRICTED_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- uty_config_unlock (vty, ENABLE_NODE);
- break;
- default:
- break;
- }
+ // TODO error handling ....
+ } ;
+ } ;
- VTY_UNLOCK() ;
- return CMD_SUCCESS ;
-} ;
+ XFREE(MTYPE_TMP, buf) ;
+ close(fd) ;
-/*------------------------------------------------------------------------------
- * Result of command is to close the input.
- *
- * Posts the reason for the close.
- *
- * Returns: CMD_CLOSE
- */
-extern enum cmd_return_code
-uty_cmd_close(struct vty *vty, const char* reason)
-{
- vty->vio->close_reason = reason ;
- return CMD_CLOSE ;
+ return CMD_SUCCESS;
} ;
/*------------------------------------------------------------------------------
- * Command line ^C action.
- *
- * Ignores contents of command line (including not adding to history).
- *
- * Fall back to ENABLE_NODE if in any one of a number of nodes.
- *
- * Resets the history pointer.
- *
- * Returns: command return code
+ * Clear the contents of the command output FIFO etc.
*/
-extern enum cmd_return_code
-uty_stop_input(struct vty *vty)
+extern void
+vty_out_clear(vty vty)
{
- vty_io vio = vty->vio ;
-
- VTY_ASSERT_LOCKED() ;
-
- switch (vty->node)
- {
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- uty_config_unlock (vty, ENABLE_NODE) ;
- break;
- default:
- /* Unknown node, we have to ignore it. */
- break;
- }
-
- /* Set history pointer to the latest one. */
- vio->hp = vio->hindex;
-
- return CMD_SUCCESS ;
+ VTY_LOCK() ;
+ uty_out_clear(vty->vio) ;
+ VTY_UNLOCK() ;
} ;
-/*------------------------------------------------------------------------------
- * Command ^Z action.
- *
- * Ignores contents of command line (including not adding to history).
- *
- * Fall back to ENABLE_NODE if in any one of a number of nodes.
+/*==============================================================================
+ * Deal with SIGCHLD "event".
*
- * Returns: command return code
+ * NB: if there is a nexus to be signalled, we do that *before* attempting to
+ * lock the VTY -- because in that case the VTY will be locked by that
+ * nexus !
*/
-extern enum cmd_return_code
-uty_end_config (struct vty *vty)
+extern void
+vty_sigchld(void)
{
- VTY_ASSERT_LOCKED() ;
-
- switch (vty->node)
- {
- case VIEW_NODE:
- case ENABLE_NODE:
- case RESTRICTED_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- uty_config_unlock (vty, ENABLE_NODE) ;
- break;
- default:
- /* Unknown node, we have to ignore it. */
- break;
- }
-
- return CMD_SUCCESS ;
-}
+ vty_child_signal_nexus_signal() ;
-/*------------------------------------------------------------------------------
- * Command ^D action -- when nothing else on command line.
- *
- * Same as "exit" command.
- *
- * Returns: command return code
- */
-extern enum cmd_return_code
-uty_down_level (struct vty *vty)
-{
- return vty_cmd_exit(vty) ;
+ VTY_LOCK() ;
+ uty_sigchld() ;
+ VTY_UNLOCK() ;
} ;
/*==============================================================================
@@ -1066,18 +816,19 @@ uty_down_level (struct vty *vty)
* run directly in the thread -- no commands are queued.
*/
-static FILE * vty_use_backup_config (char *fullpath) ;
-static void vty_read_file (FILE *confp, struct cmd_element* first_cmd,
- bool ignore_warnings) ;
+static int vty_use_backup_config (qpath path) ;
+static void vty_read_config_file (int conf_fd, const char* name,
+ cmd_command first_cmd, bool ignore_warnings,
+ bool full_lex) ;
/*------------------------------------------------------------------------------
* Read the given configuration file.
*/
extern void
-vty_read_config (char *config_file,
- char *config_default)
+vty_read_config (const char *config_file,
+ const char *config_default)
{
- vty_read_config_first_cmd_special(config_file, config_default, NULL, 1);
+ vty_read_config_first_cmd_special(config_file, config_default, NULL, true);
}
/*------------------------------------------------------------------------------
@@ -1098,15 +849,14 @@ vty_read_config (char *config_file,
* command.
*/
extern void
-vty_read_config_first_cmd_special(char *config_file,
- char *config_default,
- struct cmd_element* first_cmd,
+vty_read_config_first_cmd_special(const char *config_file,
+ const char *config_default,
+ cmd_command first_cmd,
bool ignore_warnings)
{
- char cwd[MAXPATHLEN];
- FILE *confp = NULL;
- char *fullpath;
- char *tmp = NULL;
+ const char *name ;
+ qpath path ;
+ int conf_fd ;
/* Deal with VTYSH_ENABLED magic */
if (VTYSH_ENABLED && (config_file == NULL))
@@ -1132,7 +882,7 @@ vty_read_config_first_cmd_special(char *config_file,
{
ret = stat (integrate_default, &conf_stat);
if (ret >= 0)
- return;
+ return; /* TODO leaves host.config_file NULL */
}
} ;
@@ -1140,130 +890,115 @@ vty_read_config_first_cmd_special(char *config_file,
if (config_file == NULL)
config_file = config_default ;
- if (! IS_DIRECTORY_SEP (config_file[0]))
- {
- getcwd (cwd, sizeof(cwd)) ;
- tmp = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (config_file) + 2) ;
- sprintf (tmp, "%s/%s", cwd, config_file);
- fullpath = tmp;
- }
- else
- {
- tmp = NULL ;
- fullpath = config_file;
- } ;
+ path = qpath_make(config_file, host.cwd) ;
+ name = qpath_string(path) ;
/* try to open the configuration file */
- confp = fopen (fullpath, "r");
+ conf_fd = uty_fd_file_open(name, vfd_io_read, 0) ;
- if (confp == NULL)
+ if (conf_fd < 0)
{
fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
- __func__, fullpath, errtostr(errno, 0).str);
+ __func__, name, errtostr(errno, 0).str) ;
- confp = vty_use_backup_config (fullpath);
- if (confp)
+ conf_fd = vty_use_backup_config (path);
+ if (conf_fd >= 0)
fprintf (stderr, "WARNING: using backup configuration file!\n");
else
{
fprintf (stderr, "can't open backup configuration file [%s%s]\n",
- fullpath, CONF_BACKUP_EXT);
+ name, CONF_BACKUP_EXT);
exit(1);
}
} ;
-#ifdef QDEBUG
- fprintf(stderr, "Reading config file: %s\n", fullpath);
-#endif
+ if (qdebug)
+ fprintf(stderr, "Reading config file: %s\n", name);
- vty_read_file (confp, first_cmd, ignore_warnings);
- fclose (confp);
+ vty_read_config_file(conf_fd, name, first_cmd, ignore_warnings, false);
- host_config_set (fullpath);
+ cmd_host_config_set(path) ;
-#ifdef QDEBUG
- fprintf(stderr, "Finished reading config file\n");
-#endif
+ qpath_free(path) ;
- if (tmp)
- XFREE (MTYPE_TMP, tmp);
+ if (qdebug)
+ fprintf(stderr, "Finished reading config file\n");
}
/*------------------------------------------------------------------------------
* Try to use a backup configuration file.
*
- * Having failed to open the file "<fullpath>", if there is a file called
- * "<fullpath>.sav" that can be opened for reading, then:
+ * Having failed to open the file "<path>", if there is a file called
+ * "<path>.sav" that can be opened for reading, then:
*
* - make a copy of that file
- * - call it "<fullpath>"
+ * - call it "<path>"
* - return an open FILE
*
- * Returns: NULL => no "<fullpath>.sav", or faild doing any of the above
- * otherwise, returns FILE* for open file.
+ * Returns: < 0 => no "<path>.sav", or failed doing any of the above
+ * >= 0 otherwise, fd file.
*/
-static FILE *
-vty_use_backup_config (char *fullpath)
+static int
+vty_use_backup_config (qpath path)
{
- char *tmp_path ;
- struct stat buf;
- int ret, tmp, sav;
- int c;
- char buffer[4096] ;
-
- enum { xl = 32 } ;
- tmp_path = malloc(strlen(fullpath) + xl) ;
+ qpath temp ;
+ char* name ;
+ int sav_fd, tmp_fd, err ;
+ bool ok ;
/* construct the name "<fullname>.sav", and try to open it. */
- confirm(xl > sizeof(CONF_BACKUP_EXT)) ;
- sprintf (tmp_path, "%s%s", fullpath, CONF_BACKUP_EXT) ;
+ temp = qpath_dup(path) ;
+ qpath_extend_str(temp, CONF_BACKUP_EXT) ;
- sav = -1 ;
- if (stat (tmp_path, &buf) != -1)
- sav = open (tmp_path, O_RDONLY);
+ sav_fd = -1 ;
+ tmp_fd = -1 ;
- if (sav < 0)
- {
- free (tmp_path);
- return NULL;
- } ;
+ sav_fd = uty_fd_file_open(qpath_string(temp),
+ vfd_io_read | vfd_io_blocking, 0) ;
/* construct a temporary file and copy "<fullpath.sav>" to it. */
- confirm(xl > sizeof(".XXXXXX"))
- sprintf (tmp_path, "%s%s", fullpath, ".XXXXXX") ;
+ qpath_extend_str(temp, ".XXXXXX") ;
+ name = qpath_char_string(temp) ;
- /* Open file to configuration write. */
- tmp = mkstemp (tmp_path);
- if (tmp < 0)
- {
- free (tmp_path);
- close(sav);
- return NULL;
- }
+ if (sav_fd >= 0)
+ tmp_fd = mkstemp(name) ;
+
+ ok = ((sav_fd >= 0) && (tmp_fd >= 0)) ;
- while((c = read (sav, buffer, sizeof(buffer))) > 0)
- write (tmp, buffer, c);
+ if (ok)
+ ok = (copyn(tmp_fd, sav_fd) == 0) ;
- close (sav);
- close (tmp);
+ err = errno ;
- /* Make sure that have the required file status */
- if (chmod(tmp_path, CONFIGFILE_MASK) != 0)
+ if (tmp_fd >= 0)
+ close(tmp_fd) ;
+ if (sav_fd >= 0)
+ close(sav_fd) ;
+
+ /* If now OK, then have copied the .sav to the temporary file. */
+
+ if (ok)
{
- unlink (tmp_path);
- free (tmp_path);
- return NULL;
- }
+ /* Make sure that have the required file status */
+ ok = chmod(name, CONFIGFILE_MASK) == 0 ;
+
+ /* Finally, make a link with the original name */
+ if (ok)
+ ok = link(name, qpath_string(path)) == 0 ;
+
+ err = errno ;
+ } ;
- /* Make <fullpath> be a name for the new file just created. */
- ret = link (tmp_path, fullpath) ;
+ if (tmp_fd >= 0) /* if made a temporary, done with it now */
+ unlink(name) ;
- /* Discard the temporary, now */
- unlink (tmp_path) ;
- free (tmp_path) ;
+ qpath_free(temp) ; /* done with the qpath */
- /* If link was successful, try to open -- otherwise, failed. */
- return (ret == 0) ? fopen (fullpath, "r") : NULL ;
+ if (ok)
+ return uty_fd_file_open(qpath_string(path), vfd_io_read, 0) ;
+
+ errno = err ;
+ return -1 ;
} ;
/*------------------------------------------------------------------------------
@@ -1287,143 +1022,40 @@ vty_use_backup_config (char *fullpath)
* so all commands are executed directly.
*/
static void
-vty_read_file (FILE *confp, struct cmd_element* first_cmd, bool ignore_warnings)
+vty_read_config_file(int fd, const char* name, cmd_command first_cmd,
+ bool ignore_warnings, bool full_lex)
{
- enum cmd_return_code ret ;
- struct vty *vty ;
+ cmd_return_code_t ret ;
+ vty vty ;
qtime_t taking ;
- /* Set up configuration file reader VTY -- which buffers all output */
- vty = vty_open(VTY_CONFIG_READ);
- vty->node = CONFIG_NODE;
-
- /* Make sure we have a suitable buffer, and set vty->buf to point at
- * it -- same like other command execution.
- */
- qs_need(&vty->vio->clx, VTY_BUFSIZ) ;
- vty->buf = qs_chars(&vty->vio->clx) ;
-
- taking = qt_get_monotonic() ;
-
- /* Execute configuration file */
- ret = config_from_file (vty, confp, first_cmd, &vty->vio->clx,
- ignore_warnings) ;
-
- taking = (qt_get_monotonic() - taking) / (QTIME_SECOND / 1000) ;
+ vty = vty_config_read_open(fd, name, full_lex) ;
- zlog_info("Finished reading configuration in %d.%dsecs%s",
- (int)(taking / 1000), (int)(taking % 1000),
- (ret == CMD_SUCCESS) ? "." : " -- FAILED") ;
-
- VTY_LOCK() ;
-
- if (ret != CMD_SUCCESS)
+ if (vty_cmd_config_loop_prepare(vty))
{
- fprintf (stderr, "%% while processing line %u of the configuration:\n"
- "%s", vty->lineno, vty->buf) ;
-
- switch (ret)
- {
- case CMD_WARNING:
- fprintf (stderr, "%% Warning...\n");
- break;
-
- case CMD_ERROR:
- fprintf (stderr, "%% Error...\n");
- break;
-
- case CMD_ERR_AMBIGUOUS:
- fprintf (stderr, "%% Ambiguous command.\n");
- break;
-
- case CMD_ERR_NO_MATCH:
- fprintf (stderr, "%% There is no such command.\n");
- break;
-
- case CMD_ERR_INCOMPLETE:
- fprintf (stderr, "%% Incomplete command.\n");
- break;
-
- default:
- fprintf(stderr, "%% (unknown cause %d)\n", ret) ;
- break ;
- } ;
-
- uty_out_fflush(vty->vio, stderr) ; /* flush command output buffer */
+ taking = qt_get_monotonic() ;
- exit (1);
- } ;
-
- uty_close(vty->vio) ;
- VTY_UNLOCK() ;
-} ;
+ ret = cmd_read_config(vty, first_cmd, ignore_warnings) ;
-/*==============================================================================
- * Configuration node/state handling
- *
- * At most one VTY may hold the configuration symbol of power at any time.
- */
+ taking = (qt_get_monotonic() - taking) / (QTIME_SECOND / 1000) ;
-/*------------------------------------------------------------------------------
- * Attempt to gain the configuration symbol of power
- *
- * If succeeds, set the given node.
- *
- * Returns: true <=> now own the symbol of power.
- */
-extern bool
-vty_config_lock (struct vty *vty, enum node_type node)
-{
- bool result;
-
- VTY_LOCK() ;
-
- if (vty_config == 0)
+ zlog_info("Finished reading configuration '%s' in %d.%d secs%s",
+ name, (int)(taking / 1000), (int)(taking % 1000),
+ (ret == CMD_SUCCESS) ? "." : " -- FAILED") ;
+ }
+ else
{
- vty->vio->config = 1 ;
- vty_config = 1 ;
+ /* This should be impossible -- before reading the configuration,
+ * all other vty are closed.
+ */
+ zlog_err("%s: Failed to gain config capability !", __func__) ;
+ ret = CMD_ERROR ;
} ;
- result = vty->vio->config;
-
- if (result)
- vty->node = node ;
-
- VTY_UNLOCK() ;
+ vty_cmd_loop_exit(vty) ; /* the vty is released */
- return result;
-}
-
-/*------------------------------------------------------------------------------
- * Give back the configuration symbol of power -- if own it.
- *
- * Set the given node -- which must be <= MAX_NON_CONFIG_NODE
- */
-extern void
-vty_config_unlock (struct vty *vty, enum node_type node)
-{
- VTY_LOCK() ;
- uty_config_unlock(vty, node);
- VTY_UNLOCK() ;
-}
-
-/*------------------------------------------------------------------------------
- * Give back the configuration symbol of power -- if own it.
- *
- * Set the given node -- which must be <= MAX_NON_CONFIG_NODE
- */
-extern void
-uty_config_unlock (struct vty *vty, enum node_type node)
-{
- VTY_ASSERT_LOCKED() ;
- if ((vty_config == 1) && (vty->vio->config == 1))
- {
- vty->vio->config = 0;
- vty_config = 0;
- }
-
- assert(node <= MAX_NON_CONFIG_NODE) ;
- vty->node = node ;
+ if (ret != CMD_SUCCESS)
+ exit(1) ;
} ;
/*==============================================================================
@@ -1440,24 +1072,26 @@ DEFUN_CALL (config_who,
VTY_LOCK() ;
- vio = vio_list_base ;
- while (vio != NULL) /* TODO: show only VTY_TERM ??? */
+ vio = vio_live_list ; /* once locked */
+
+ while (vio != NULL) /* TODO: show only VTY_TERM ??? */
{
- uty_out (vty, "%svty[%d] connected from %s.%s",
- vio->config ? "*" : " ",
- i, uty_get_name(vio), VTY_NEWLINE);
+ vty_out(vty, "%svty[%d] connected from %s.\n",
+ vio->vty->config ? "*" : " ", i, uty_get_name(vio)) ;
vio = sdl_next(vio, vio_list) ;
} ;
+
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
/* Move to vty configuration mode. */
-DEFUN_CALL (line_vty,
- line_vty_cmd,
- "line vty",
- "Configure a terminal line\n"
- "Virtual terminal\n")
+DEFUN_ATTR (line_vty,
+ line_vty_cmd,
+ "line vty",
+ "Configure a terminal line\n"
+ "Virtual terminal\n",
+ CMD_ATTR_DIRECT + CMD_ATTR_NODE + VTY_NODE)
{
VTY_LOCK() ;
vty->node = VTY_NODE;
@@ -1465,7 +1099,11 @@ DEFUN_CALL (line_vty,
return CMD_SUCCESS;
}
-/* Set time out value. */
+/*------------------------------------------------------------------------------
+ * Set time out value.
+ *
+ * Affects this and any future VTY_TERMINAL or VTY_SHELL_SERVER type VTY.
+ */
static int
exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
{
@@ -1483,10 +1121,9 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
if (sec_str)
timeout += strtol (sec_str, NULL, 10);
- vty_timeout_val = timeout;
+ host.vty_timeout_val = timeout;
- if (vty_term(vty) || vty_shell_serv(vty))
- uty_sock_set_timer(&vty->vio->sock, timeout) ;
+ uty_set_timeout(vty->vio, timeout) ; /* update own timeout, if required */
VTY_UNLOCK() ;
return CMD_SUCCESS;
@@ -1529,10 +1166,9 @@ DEFUN_CALL (vty_access_class,
{
VTY_LOCK() ;
- if (vty_accesslist_name)
- XFREE(MTYPE_VTY, vty_accesslist_name);
+ XFREE(MTYPE_HOST, host.vty_accesslist_name);
- vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+ host.vty_accesslist_name = XSTRDUP(MTYPE_HOST, argv[0]);
VTY_UNLOCK() ;
return CMD_SUCCESS;
@@ -1546,23 +1182,25 @@ DEFUN_CALL (no_vty_access_class,
"Filter connections based on an IP access list\n"
"IP access list\n")
{
- int result = CMD_SUCCESS;
+ cmd_return_code_t ret ;
VTY_LOCK() ;
- if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
+
+ if ((argc == 0) || ( (host.vty_accesslist_name != NULL) &&
+ (strcmp(host.vty_accesslist_name, argv[0]) == 0) ))
{
- uty_out (vty, "Access-class is not currently applied to vty%s",
- VTY_NEWLINE);
- result = CMD_WARNING;
+ XFREE(MTYPE_HOST, host.vty_accesslist_name);
+ /* sets host.vty_accesslist_name = NULL */
+ ret = CMD_SUCCESS ;
}
else
{
- XFREE(MTYPE_VTY, vty_accesslist_name);
- vty_accesslist_name = NULL;
- }
+ vty_out(vty, "Access-class is not currently applied to vty\n") ;
+ ret = CMD_WARNING;
+ } ;
VTY_UNLOCK() ;
- return result;
+ return ret;
}
#ifdef HAVE_IPV6
@@ -1575,10 +1213,10 @@ DEFUN_CALL (vty_ipv6_access_class,
"IPv6 access list\n")
{
VTY_LOCK() ;
- if (vty_ipv6_accesslist_name)
- XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
- vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+ XFREE(MTYPE_HOST, host.vty_ipv6_accesslist_name);
+
+ host.vty_ipv6_accesslist_name = XSTRDUP(MTYPE_HOST, argv[0]);
VTY_UNLOCK() ;
return CMD_SUCCESS;
@@ -1593,26 +1231,25 @@ DEFUN_CALL (no_vty_ipv6_access_class,
"Filter connections based on an IP access list\n"
"IPv6 access list\n")
{
- int result = CMD_SUCCESS;
+ cmd_return_code_t ret ;
VTY_LOCK() ;
- if (! vty_ipv6_accesslist_name ||
- (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
+ if ((argc == 0) || ( (host.vty_ipv6_accesslist_name != NULL) &&
+ (strcmp(host.vty_ipv6_accesslist_name, argv[0]) == 0) ))
{
- uty_out (vty, "IPv6 access-class is not currently applied to vty%s",
- VTY_NEWLINE);
- result = CMD_WARNING;
+ XFREE(MTYPE_HOST, host.vty_ipv6_accesslist_name);
+ /* sets host.vty_ipv6_accesslist_name = NULL */
+ ret = CMD_SUCCESS ;
}
else
{
- XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
-
- vty_ipv6_accesslist_name = NULL;
- }
+ vty_out(vty, "IPv6 access-class is not currently applied to vty\n") ;
+ ret = CMD_WARNING;
+ } ;
VTY_UNLOCK() ;
- return CMD_SUCCESS;
+ return ret;
}
#endif /* HAVE_IPV6 */
@@ -1623,7 +1260,7 @@ DEFUN_CALL (vty_login,
"Enable password checking\n")
{
VTY_LOCK() ;
- no_password_check = 0;
+ host.no_password_check = false ;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1635,7 +1272,7 @@ DEFUN_CALL (no_vty_login,
"Enable password checking\n")
{
VTY_LOCK() ;
- no_password_check = 1;
+ host.no_password_check = true ;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1647,7 +1284,7 @@ DEFUN_CALL (vty_restricted_mode,
"Restrict view commands available in anonymous, unauthenticated vty\n")
{
VTY_LOCK() ;
- restricted_mode = 1;
+ host.restricted_mode = true;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1659,7 +1296,7 @@ DEFUN_CALL (vty_no_restricted_mode,
"Enable password checking\n")
{
VTY_LOCK() ;
- restricted_mode = 0;
+ host.restricted_mode = false;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1671,7 +1308,7 @@ DEFUN_CALL (service_advanced_vty,
"Enable advanced mode vty interface\n")
{
VTY_LOCK() ;
- host.advanced = 1;
+ host.advanced = true;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1684,7 +1321,7 @@ DEFUN_CALL (no_service_advanced_vty,
"Enable advanced mode vty interface\n")
{
VTY_LOCK() ;
- host.advanced = 0;
+ host.advanced = false;
VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1727,26 +1364,10 @@ DEFUN_CALL (show_history,
SHOW_STR
"Display the session command history\n")
{
- int index;
-
VTY_LOCK() ;
- for (index = vty->vio->hindex + 1; index != vty->vio->hindex;)
- {
- qstring line ;
-
- if (index == VTY_MAXHIST)
- {
- index = 0;
- continue;
- }
-
- line = vector_get_item(&vty->vio->hist, index) ;
- if (line != NULL)
- uty_out (vty, " %s%s", line->char_body, VTY_NEWLINE);
-
- index++;
- }
+ if (vty->type == VTY_TERMINAL)
+ uty_cli_hist_show(vty->vio->vin->cli) ;
VTY_UNLOCK() ;
return CMD_SUCCESS;
@@ -1760,35 +1381,40 @@ DEFUN_CALL (show_history,
static int
vty_config_write (struct vty *vty)
{
- vty_out (vty, "line vty%s", VTY_NEWLINE);
+ vty_io vio ;
+
+ VTY_LOCK() ; /* while accessing the host.xx */
+
+ vio = vty->vio ;
- if (vty_accesslist_name)
- vty_out (vty, " access-class %s%s",
- vty_accesslist_name, VTY_NEWLINE);
+ uty_out (vio, "line vty\n");
- if (vty_ipv6_accesslist_name)
- vty_out (vty, " ipv6 access-class %s%s",
- vty_ipv6_accesslist_name, VTY_NEWLINE);
+ if (host.vty_accesslist_name)
+ uty_out (vio, " access-class %s\n", host.vty_accesslist_name);
+
+ if (host.vty_ipv6_accesslist_name)
+ uty_out (vio, " ipv6 access-class %s\n", host.vty_ipv6_accesslist_name);
/* exec-timeout */
- if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
- vty_out (vty, " exec-timeout %ld %ld%s",
- vty_timeout_val / 60,
- vty_timeout_val % 60, VTY_NEWLINE);
+ if (host.vty_timeout_val != VTY_TIMEOUT_DEFAULT)
+ uty_out (vio, " exec-timeout %ld %ld\n", host.vty_timeout_val / 60,
+ host.vty_timeout_val % 60);
/* login */
- if (no_password_check)
- vty_out (vty, " no login%s", VTY_NEWLINE);
+ if (host.no_password_check)
+ uty_out (vio, " no login\n");
- if (restricted_mode != restricted_mode_default)
+ if (host.restricted_mode != restricted_mode_default)
{
if (restricted_mode_default)
- vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
+ uty_out (vio, " no anonymous restricted\n");
else
- vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
+ uty_out (vio, " anonymous restricted\n");
}
- vty_out (vty, "!%s", VTY_NEWLINE);
+ uty_out (vio, "!\n");
+
+ VTY_UNLOCK() ;
return CMD_SUCCESS;
}
@@ -1798,96 +1424,68 @@ vty_config_write (struct vty *vty)
*/
/*------------------------------------------------------------------------------
- * Save cwd
- *
- * This is done early in the morning so that any future operations on files
- * can use the original cwd if required.
+ * Get cwd as at start-up. Never changed -- so no locking required.
*/
-static void
-vty_save_cwd (void)
+extern qpath
+vty_getcwd (qpath qp)
{
- char cwd[MAXPATHLEN];
- char *c;
-
- c = getcwd (cwd, MAXPATHLEN);
+ VTY_LOCK() ;
- if (!c)
- {
- chdir (SYSCONFDIR);
- getcwd (cwd, MAXPATHLEN);
- }
+ qp = qpath_copy(qp, host.cwd) ;
- vty_cwd = XSTRDUP(MTYPE_TMP, cwd) ;
-} ;
+ VTY_UNLOCK() ;
-/*------------------------------------------------------------------------------
- * Get cwd as at start-up. Never changed -- so no locking required.
- */
-char *
-vty_get_cwd ()
-{
- return vty_cwd;
+return qp ;
}
/*==============================================================================
- * Access functions for VTY values, where locking is or might be required.
+ * Access functions for vio values, where locking is or might be required.
*/
+#if 0
-bool
-vty_shell (struct vty *vty)
+static bool
+vty_is_terminal(struct vty *vty)
{
bool result;
VTY_LOCK() ;
- result = (vty->vio->type == VTY_SHELL) ;
+ result = uty_is_terminal(vty) ;
VTY_UNLOCK() ;
return result;
}
-bool
-vty_term(struct vty *vty)
+static bool
+vty_is_shell_server (struct vty *vty)
{
bool result;
VTY_LOCK() ;
- result = (vty->vio->type == VTY_TERM);
+ result = uty_is_shell_server(vty) ;
VTY_UNLOCK() ;
return result;
}
-bool
-vty_shell_serv (struct vty *vty)
+static bool
+vty_is_shell_client (struct vty *vty)
{
bool result;
VTY_LOCK() ;
- result = (vty->vio->type == VTY_SHELL_SERV);
+ result = uty_is_shell_client(vty) ;
VTY_UNLOCK() ;
return result;
}
-enum node_type
-vty_get_node(struct vty *vty)
-{
- int result;
- VTY_LOCK() ;
- result = vty->node;
- VTY_UNLOCK() ;
- return result;
-}
+#endif
-void
-vty_set_node(struct vty *vty, enum node_type node)
+/*------------------------------------------------------------------------------
+ * When terminal length is set, change the current CLI setting, if required.
+ */
+extern void
+vty_set_lines(vty vty, int lines)
{
VTY_LOCK() ;
- vty->node = node;
- VTY_UNLOCK() ;
-}
-void
-vty_set_lines(struct vty *vty, int lines)
-{
- VTY_LOCK() ;
- vty->vio->lines = lines;
- vty->vio->lines_set = 1 ;
- uty_set_height(vty->vio) ;
+ if (vty->type == VTY_TERMINAL)
+ uty_cli_set_lines(vty->vio->vin->cli, lines, true) ;
+
VTY_UNLOCK() ;
}
@@ -1989,7 +1587,8 @@ DEFUN (delay_secs,
a = (rand() % 4) + 1 ;
} ;
- *q++ = '\n' ;
+ if (n != 0)
+ *q++ = '\n' ;
*q++ = '\0' ;
vty_out(vty, buf) ;