diff options
Diffstat (limited to 'lib/vty.c')
-rw-r--r-- | lib/vty.c | 1467 |
1 files changed, 533 insertions, 934 deletions
@@ -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) ; |