summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Hall <chris.hall@highwayman.com>2011-02-13 22:53:14 +0000
committerChris Hall <chris.hall@highwayman.com>2011-02-13 22:53:14 +0000
commit64be6d766a65dc0749d17f5023d714678e9c96a6 (patch)
treef97e04068600d0851687b58d25ff198d1eb6cc73
parent8443ca08672e0cf5b779f59db9d556dadf763de7 (diff)
downloadquagga-ex10p.tar.bz2
quagga-ex10p.tar.xz
Initial commit to seed the "pipework" branchex10p
This is a major revision of the command processing, in order to support new lexical level for command lines, plus all the necessary I/O redirection for the pipes. This is version 0.99.15ex10p. This supports: < filename <+ filename .... > filename .... >> filename .... >* Also contains all lexical level handling of '...', "...." and \x in order to allow use of '>' et al if required. Updated command line completion and help is a work in progress.
-rw-r--r--lib/command_common.h221
-rw-r--r--lib/command_execute.c460
-rw-r--r--lib/command_local.h161
-rw-r--r--lib/elstring.c269
-rw-r--r--lib/vty_command.c863
-rw-r--r--lib/vty_command.h61
-rw-r--r--lib/vty_common.h129
-rw-r--r--lib/vty_io_vsh.c369
-rw-r--r--lib/vty_io_vsh.h55
-rw-r--r--lib/vty_local.h193
-rw-r--r--lib/zconfig.h28
11 files changed, 2809 insertions, 0 deletions
diff --git a/lib/command_common.h b/lib/command_common.h
new file mode 100644
index 00000000..0f7c4123
--- /dev/null
+++ b/lib/command_common.h
@@ -0,0 +1,221 @@
+/* Command handler node_type stuff -- header
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_COMMAND_COMMON_H
+#define _ZEBRA_COMMAND_COMMON_H
+
+#include "misc.h"
+#include "vector.h"
+
+/*------------------------------------------------------------------------------
+ * These are the command levels/contexts.
+ *
+ * NB: this is the order in which configuration is written to the
+ * configuration file.
+ */
+enum node_type
+{
+ NULL_NODE = 0, /* For when need "not a node" */
+
+ AUTH_NODE, /* VTY login -> VIEW_NODE */
+ RESTRICTED_NODE, /* if no login required, may use this node */
+ VIEW_NODE, /* aka user EXEC */
+ AUTH_ENABLE_NODE, /* enable login -> ENABLE_NODE */
+ ENABLE_NODE, /* aka privileged EXEC */
+
+ MIN_DO_SHORTCUT_NODE = ENABLE_NODE,
+ /* May not "do xxx" at any node lower */
+ MAX_NON_CONFIG_NODE = ENABLE_NODE,
+ /* May not be higher than this without owning
+ * the configuration symbol of power */
+
+ CONFIG_NODE, /* aka global configuration mode */
+
+ MIN_CONFIG_NODE = CONFIG_NODE,
+ /* May not change context to any node lower */
+
+ SERVICE_NODE, /* unused ! */
+ DEBUG_NODE, /* debug config write only */
+ AAA_NODE, /* unused ! */
+ KEYCHAIN_NODE, /* see: keychain.c */
+ KEYCHAIN_KEY_NODE, /* see: keychain.c -- child of KEYCHAIN_NODE */
+ INTERFACE_NODE, /* interface commands */
+ ZEBRA_NODE, /* router zebra commands */
+ TABLE_NODE, /* rtm_table config write -- see zserv.c */
+ RIP_NODE, /* router rip commands */
+ RIPNG_NODE, /* router ripng commands */
+ BGP_NODE, /* router bgp commands */
+ BGP_VPNV4_NODE, /* address-family vpnv4 -- child of BGP_NODE */
+ BGP_IPV4_NODE, /* address-family ipv4 (unicast) -- child of BGP_NODE */
+ BGP_IPV4M_NODE, /* address-family ipv4 multicast -- child of BGP_NODE */
+ BGP_IPV6_NODE, /* address-family ipv6 (unicast) -- child of BGP_NODE */
+ BGP_IPV6M_NODE, /* address-family ipv6 multicast -- child of BGP_NODE */
+ OSPF_NODE, /* router ospf commands */
+ OSPF6_NODE, /* router ospf6 commands */
+ ISIS_NODE, /* router isis commands */
+ MASC_NODE, /* unused ! RFC 2909 Multicast Address-Set Claim */
+ IRDP_NODE, /* unused ! ICMP Router Discovery Protocol */
+ IP_NODE, /* zebra_ip_config write only -- see zebra_vty.c */
+ ACCESS_NODE, /* access list config write only -- see filter.c */
+ PREFIX_NODE, /* prefix list config write only -- see plist.c */
+ ACCESS_IPV6_NODE, /* access list config write only -- see filter.c */
+ PREFIX_IPV6_NODE, /* prefix list config write only -- see plist.c */
+ AS_LIST_NODE, /* AS list config write only -- see bgp_filter.c */
+ COMMUNITY_LIST_NODE, /* Community list config write only -- see bgp_vty.c */
+ RMAP_NODE, /* route-map commands */
+ SMUX_NODE, /* SNMP config write only -- see smux.c */
+ DUMP_NODE, /* BGP dump config write only -- see bgp_dump.c */
+ FORWARDING_NODE, /* forwarding config write -- see zserv.c */
+ PROTOCOL_NODE, /* protocol config write -- see zebra_vty.c */
+ VTY_NODE, /* line vty commands */
+} ;
+typedef enum node_type node_type_t ;
+
+/*------------------------------------------------------------------------------
+ * Return values for command handling.
+ *
+ * NB: when a command is executed it may return CMD_SUCCESS, CMD_WARNING
+ * or CMD_ERROR.
+ *
+ * In all cases any output required (including any warning or error
+ * messages) must already have been output.
+ *
+ * CMD_WARNING will stop configuration reader, unless ignore warning
+ * option is set.
+ *
+ * CMD_ERROR will always stop the configuration reader.
+ *
+ * If there is no output and either CMD_WARNING or CMD_ERROR, then will
+ * output a general warning message.
+ *
+ * All other return codes are for use within the command handler.
+ */
+enum cmd_return_code
+{
+ CMD_SUCCESS = 0,
+ CMD_WARNING = 1,
+ CMD_ERROR,
+
+ CMD_IO_ERROR, /* I/O -- failed :-( */
+
+ CMD_SUCCESS_DAEMON, /* parser: success & command is for vtysh ? */
+
+ CMD_CLOSE, /* command: used by "exit" */
+
+ CMD_EMPTY, /* parser: nothing to execute */
+ CMD_WAITING, /* I/O: waiting for more input */
+ CMD_EOF, /* I/O: nothing more to come */
+
+ CMD_ERR_PARSING, /* parser: general parser error */
+ CMD_ERR_NO_MATCH, /* parser: command/argument not recognised */
+ CMD_ERR_AMBIGUOUS, /* parser: more than on command matches */
+ CMD_ERR_INCOMPLETE,
+
+
+ CMD_COMPLETE_FULL_MATCH, /* cmd_completion returns */
+ CMD_COMPLETE_MATCH,
+ CMD_COMPLETE_LIST_MATCH,
+ CMD_COMPLETE_ALREADY
+} ;
+
+typedef enum cmd_return_code cmd_return_code_t ;
+
+/*------------------------------------------------------------------------------
+ * Structure for each node -- root of all commands for the node.
+ *
+ * See install_node().
+ */
+struct vty ; /* Forward reference */
+
+struct cmd_node
+{
+ node_type_t node ; /* who we are */
+
+ const char* prompt ; /* prompt string for vty */
+
+ bool config_to_vtysh ; /* configuration goes to vtysh ? */
+
+ node_type_t parent ; /* parent when parsing commands */
+ node_type_t exit_to ; /* where to go on "exit" */
+ node_type_t end_to ; /* where to go on "end", "^C" or "^Z" */
+
+ int (*config_write) (struct vty*) ; /* configuration write function */
+
+ vector_t cmd_vector; /* Vector of this node's commands. */
+} ;
+
+typedef struct cmd_node cmd_node_t ;
+typedef struct cmd_node* cmd_node ;
+
+/*------------------------------------------------------------------------------
+ * Command elements -- contents of the node's cmd_vector
+ */
+enum cmd_attr
+{
+ CMD_ATTR_SIMPLE = 0, /* bit significant */
+ CMD_ATTR_DEPRECATED = BIT(0),
+ CMD_ATTR_HIDDEN = BIT(1),
+ CMD_ATTR_DIRECT = BIT(2),
+};
+typedef enum cmd_attr cmd_attr_t ;
+
+/* Structure of command element. */
+
+struct cmd_command ;
+typedef struct cmd_command* cmd_command ;
+
+typedef const char* const argv_t[] ;
+
+#define DEFUN_CMD_ARG_UNUSED __attribute__ ((unused))
+#define DEFUN_CMD_FUNCTION(name) \
+ enum cmd_return_code name (cmd_command self DEFUN_CMD_ARG_UNUSED, \
+ struct vty* vty DEFUN_CMD_ARG_UNUSED, \
+ int argc DEFUN_CMD_ARG_UNUSED, \
+ argv_t argv DEFUN_CMD_ARG_UNUSED)
+
+typedef DEFUN_CMD_FUNCTION((cmd_function)) ;
+
+struct cmd_item ; /* Defined in command_parse.h */
+
+struct cmd_command
+{
+ const char* string ; /* Command specification by string. */
+ cmd_function* func ;
+ const char* doc ; /* Documentation of this command. */
+ int daemon ; /* Daemon to which this command belong. */
+ cmd_attr_t attr ; /* Command attributes */
+
+ vector items ; /* Vector of pointers to cmd_item(s) */
+
+ uint nt_min ; /* excluding [option](s) */
+ uint nt ; /* count of all items */
+ uint nt_max ; /* "infinite" if .vararg */
+
+ struct cmd_item* vararg ; /* if there is a vararg item */
+
+ char* r_string ;
+ char* r_doc ;
+
+//char* config ; /* Configuration string */
+//vector subconfig ; /* Sub configuration string */
+};
+
+#endif /* _ZEBRA_COMMAND_COMMON_H */
diff --git a/lib/command_execute.c b/lib/command_execute.c
new file mode 100644
index 00000000..cbf260b9
--- /dev/null
+++ b/lib/command_execute.c
@@ -0,0 +1,460 @@
+/* Command Line Execution
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Recast and extended: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "misc.h"
+
+#include "command_local.h"
+#include "command_parse.h"
+#include "command_execute.h"
+#include "command_queue.h"
+#include "vty_common.h"
+#include "vty_command.h"
+#include "memory.h"
+
+/*==============================================================================
+ * Construct and destroy cmd_exec object.
+ *
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Construct cmd_exec object and initialise.
+ *
+ * The following are set by uty_cmd_prepare() which is called after something
+ * has been pushed/popped on the vin/vout stacks, and before any command
+ * execution starts:
+ *
+ * - parse_type
+ * - reflect_enabled
+ * - out_enabled
+ *
+ * to reflect the then current VTY state.
+ */
+extern cmd_exec
+cmd_exec_new(vty vty)
+{
+ cmd_exec exec ;
+
+ exec = XCALLOC(MTYPE_CMD_EXEC, sizeof(struct cmd_exec)) ;
+
+ /* Zeroising has set:
+ *
+ * vty = X -- set below
+ *
+ * line = NULL -- no command line, yet
+ * to_do = cmd_do_nothing
+ *
+ * parse_type = cmd_parse_standard
+ *
+ * reflect_enabled = false -- not enabled
+ * out_enabled = false -- not enabled
+ *
+ * parsed all zeros -- empty parsed object (embedded)
+ *
+ * state = exec_null
+ * locus = NULL -- not significant in exec_null
+ * ret = CMD_SUCCESS
+ *
+ * cq = NULL -- no mqb (qpthreads)
+ * -- no thread (legacy thread)
+ */
+ confirm(cmd_do_nothing == 0) ;
+ confirm(cmd_parse_standard == 0) ;
+ confirm(CMD_PARSED_INIT_ALL_ZEROS) ;
+ confirm(exec_null == 0) ;
+ confirm(CMD_SUCCESS == 0) ;
+
+ exec->vty = vty ;
+
+ return exec ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Destroy cmd_exec object.
+ */
+extern cmd_exec
+cmd_exec_free(cmd_exec exec)
+{
+ cmd_parsed_reset(exec->parsed, keep_it) ;
+
+
+
+ XFREE(MTYPE_CMD_EXEC, exec) ;
+
+ return NULL ;
+} ;
+
+
+/*==============================================================================
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Set new node.
+ *
+ * If old node >= CONFIG_NODE, and new node < CONFIG_NODE, give up the config
+ * symbol of power.
+ *
+ * Returns: CMD_SUCCESS -- OK
+ * CMD_CLOSE -- if new node == NODE_NULL
+ */
+static cmd_return_code_t
+cmd_set_node(vty vty, node_type_t node)
+{
+ if ((vty->node >= MIN_CONFIG_NODE) && (node < MIN_CONFIG_NODE))
+ vty_config_unlock(vty, node) ;
+ else
+ vty->node = node ;
+
+ return (vty->node != NULL_NODE) ? CMD_SUCCESS : CMD_CLOSE ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command line "end" command
+ *
+ * Falls back to the current node's end_to node. If leaves configuration
+ * mode, give away the configuration symbol of power.
+ *
+ * Generally, for all configuration nodes end -> NODE_ENABLE (releasing the
+ * configuration lock), and all other nodes end does nothing.
+ *
+ * Returns: CMD_SUCCESS -- OK
+ * CMD_CLOSE -- if new node == NODE_NULL
+ */
+extern cmd_return_code_t
+cmd_end(vty vty)
+{
+ return cmd_set_node(vty, cmd_node_end_to(vty->node)) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command line "exit" command -- aka "quit"
+ *
+ * Falls back to the current node's exit_to node. If leaves configuration
+ * mode, give away the configuration symbol of power.
+ *
+ * Generally:
+ *
+ * - for all configuration nodes > NODE_CONFIG exit -> parent node.
+ *
+ * - for NODE_CONFIG exit -> ENABLE_NODE (and release configuration symbol
+ * of power)
+ *
+ * - for all nodes < NODE_CONFIG -> close the VTY
+ *
+ * Returns: CMD_SUCCESS -- OK
+ * CMD_CLOSE -- if new node == NODE_NULL
+ */
+extern cmd_return_code_t
+cmd_exit(vty vty)
+{
+ return cmd_set_node(vty, cmd_node_exit_to(vty->node)) ;
+} ;
+
+/*==============================================================================
+ *
+ */
+/*------------------------------------------------------------------------------
+ * Parse and execute a command.
+ *
+ * The command is given by vty->buf and vty->node.
+ *
+ * Uses vty->parsed.
+ *
+ * -- use exact/completion parsing, as required.
+ *
+ * -- parse in current node and in ancestors, as required
+ *
+ * If does not find in any ancestor, return error from current node.
+ *
+ * -- implement the "do" shortcut, as required
+ *
+ * If qpthreads_enabled, then may queue the command rather than execute it
+ * here.
+ *
+ * The vty->node may be changed during the execution of the command, and may
+ * be returned changed once the command has completed.
+ *
+ * NB: expects to have free run of everything in the vty structure (except
+ * the contents of the vty_io sub-structure) until the command completes.
+ */
+#if 0
+extern enum cmd_return_code
+cmd_execute_command(struct vty *vty,
+ cmd_parse_type_t type, struct cmd_command **cmd)
+{
+ enum cmd_return_code ret ;
+
+ /* Try to parse in vty->node or, if required, ancestors thereof. */
+ ret = cmd_parse_command(vty->exec->parsed, vty->line, vty->node, type) ;
+
+ if (cmd != NULL)
+ *cmd = vty->exec->parsed->cmd ; /* for vtysh */
+
+ if (ret == CMD_SUCCESS)
+ ret = cmd_dispatch(vty, cmd_may_queue) ;
+
+ return ret ;
+} ;
+#endif
+
+/*------------------------------------------------------------------------------
+ * Read configuration from file.
+ *
+ * In the qpthreads world this assumes that it is running with the vty
+ * locked, and that all commands are to be executed directly.
+ *
+ * If the 'first_cmd' argument is not NULL it is the address of the first
+ * command that is expected to appear. If the first command is not this, then
+ * the 'first_cmd' is called with argv == NULL (and argc == 0) to signal the
+ * command is being invoked by default.
+ *
+ * Command processing continues while CMD_SUCCESS is returned by the command
+ * parser and command execution.
+ *
+ * If 'ignore_warning' is set, then any CMD_WARNING returned by command
+ * execution is converted to CMD_SUCCESS. Note that any CMD_WARNING returned
+ * by command parsing (or in execution of any default 'first_cmd').
+ *
+ * Returns: cmd_return_code for last command
+ * vty->buf is last line processed
+ * vty->lineno is number of last line processed (1 is first)
+ *
+ * If the file is empty, will return CMD_SUCCESS.
+ *
+ * If
+ *
+ * If return code is not CMD_SUCCESS, the the output buffering contains the
+ * output from the last command attempted.
+ */
+extern cmd_return_code_t
+cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
+{
+ cmd_exec exec = vty->exec ;
+ cmd_parsed parsed = exec->parsed ;
+ cmd_return_code_t ret;
+
+ while (1)
+ {
+ /* Need a command line, pops pipes as required */
+ ret = vty_cmd_fetch_line(vty) ; /* sets exec->line */
+
+ if (ret != CMD_SUCCESS)
+ break ; /* stop on any and all problems */
+
+ /* Parse the command line we now have */
+ cmd_tokenise(parsed, exec->line) ;
+ ret = cmd_parse_command(parsed, vty->node,
+ exec->parse_type | cmd_parse_execution) ;
+
+ if (ret == CMD_EMPTY)
+ continue ; /* easy if empty line */
+
+ if (ret != CMD_SUCCESS)
+ break ; /* stop on *any* parsing issue */
+
+ /* Special handling before first active line. */
+ if (first_cmd != NULL)
+ {
+ if (first_cmd != parsed->cmd)
+ {
+ ret = (*first_cmd->func)(first_cmd, vty, 0, NULL) ;
+ if (ret != CMD_SUCCESS)
+ break ; /* stop on *any* issue with "default" */
+ } ;
+ first_cmd = NULL ;
+ } ;
+
+ /* reflection now..... */
+ if (exec->reflect_enabled)
+ vty_cmd_reflect_line(vty) ;
+
+ /* Pipe work, if any */
+ if ((parsed->parts & cmd_parts_pipe) != 0)
+ {
+ ret = cmd_open_pipes(vty) ;
+ if (ret != CMD_SUCCESS)
+ break ;
+ } ;
+
+ /* Command execution, if any */
+ if ((parsed->parts & cmd_part_command) != 0)
+ {
+ ret = cmd_execute(vty) ;
+
+ if (ret != CMD_SUCCESS)
+ {
+ /* If ignoring warnings, treat CMD_WARNING as CMD_SUCCESS */
+ if (ignore_warning && (ret == CMD_WARNING))
+ ret = CMD_SUCCESS ;
+
+ /* Treat CMD_CLOSE as CMD_SUCCESS */
+ else if (ret == CMD_CLOSE)
+ ret = CMD_SUCCESS ;
+
+ /* Everything else -> stop */
+ else
+ break ;
+ } ;
+ } ;
+
+ /* When we get here the last command was CMD_SUCCESS !
+ * (Or CMD_WARNING and ignore_warning.)
+ *
+ * Deals with closing out pipe(s) if required.
+ */
+ vty_cmd_success(vty) ;
+ } ;
+
+ /* Deal with any errors */
+ if (ret == CMD_EOF)
+ return CMD_SUCCESS ;
+
+ return ret ;
+} ;
+
+/*==============================================================================
+ */
+static qstring cmd_get_pipe_file_name(cmd_parsed parsed, uint ti, uint nt) ;
+
+
+/*------------------------------------------------------------------------------
+ * Open in and/or out pipes
+ *
+ * * Returns:
+ *
+ * - OK -- CMD_SUCCESS
+ * - error -- CMD_ERROR, etc
+ */
+extern cmd_return_code_t
+cmd_open_pipes(vty vty)
+{
+ cmd_exec exec = vty->exec ;
+ cmd_parsed parsed = exec->parsed ;
+ cmd_return_code_t ret ;
+
+ ret = CMD_SUCCESS ;
+
+ /* Deal with any in pipe stuff */
+ if ((parsed->parts & cmd_part_in_pipe) != 0)
+ {
+ if ((parsed->in_pipe & cmd_pipe_file) != 0)
+ {
+ qstring name ;
+ name = cmd_get_pipe_file_name(parsed, parsed->first_in_pipe,
+ parsed->num_in_pipe) ;
+
+ ret = vty_cmd_open_in_pipe_file(vty, name,
+ (parsed->in_pipe & cmd_pipe_reflect) != 0) ;
+
+ qs_reset(name, free_it) ;
+ }
+ else if ((parsed->in_pipe & cmd_pipe_shell) != 0)
+ {
+ }
+ else
+ zabort("invalid in pipe state") ;
+
+ if (ret != CMD_SUCCESS)
+ return ret ;
+ } ;
+
+ /* Deal with any out pipe stuff */
+ if ((parsed->parts & cmd_part_out_pipe) != 0)
+ {
+ if ((parsed->out_pipe & cmd_pipe_file) != 0)
+ {
+ qstring name ;
+ name = cmd_get_pipe_file_name(parsed, parsed->first_out_pipe,
+ parsed->num_out_pipe) ;
+
+ ret = vty_cmd_open_out_pipe_file(vty, name,
+ ((parsed->out_pipe & cmd_pipe_append) != 0)) ;
+
+ qs_reset(name, free_it) ;
+ }
+ else if ((parsed->out_pipe & cmd_pipe_shell) != 0)
+ {
+ ret = vty_cmd_open_out_dev_null(vty) ;
+ }
+ else if ((parsed->out_pipe & cmd_pipe_dev_null) != 0)
+ {
+ ret = vty_cmd_open_out_dev_null(vty) ;
+ }
+ else
+ zabort("invalid out pipe state") ;
+
+ if (ret != CMD_SUCCESS)
+ return ret ;
+ } ;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get pipe file name
+ *
+ * Returns a brand new qstring that must be discarded after use.
+ *
+ * Pro tem this just gets the token value !! TODO
+ */
+static qstring
+cmd_get_pipe_file_name(cmd_parsed parsed, uint ti, uint nt)
+{
+ cmd_token t ;
+
+ assert(nt == 2) ;
+
+ t = cmd_token_get(parsed->tokens, ti + 1) ;
+
+ return qs_copy(NULL, t->qs) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command Execution
+ *
+ * Returns:
+ *
+ * - have command ready for execution -- CMD_SUCCESS
+ * - reached end of command stream -- CMD_CLOSE
+ * - encounter error of some kind -- CMD_WARNING, CMD_ERROR, etc
+ */
+extern cmd_return_code_t
+cmd_execute(vty vty)
+{
+ cmd_parsed parsed = vty->exec->parsed ;
+ cmd_command cmd = parsed->cmd ;
+ cmd_return_code_t ret ;
+ node_type_t onode ;
+
+ onode = vty->node ;
+ vty->node = parsed->cnode ;
+
+ ret = (*(cmd->func))(cmd, vty, cmd_arg_vector_argc(parsed),
+ cmd_arg_vector_argv(parsed)) ;
+
+ if (((parsed->parts & cmd_part_do) != 0) && (vty->node == ENABLE_NODE))
+ vty->node = onode ;
+
+ return ret ;
+} ;
diff --git a/lib/command_local.h b/lib/command_local.h
new file mode 100644
index 00000000..321ed33e
--- /dev/null
+++ b/lib/command_local.h
@@ -0,0 +1,161 @@
+/* Command handler -- header for stuff used within command/vty
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_COMMAND_LOCAL_H
+#define _ZEBRA_COMMAND_LOCAL_H
+
+#include "command_common.h" /* First and foremost ! */
+
+#include "vty_local.h"
+#include "vector.h"
+
+/*==============================================================================
+ * This is for access to some things in command.c which are not required
+ * by external users, who use command.h.
+ *
+ * This is for use within the command/vty family.
+ *
+ * Should not be used with command.h ! (Except in command.c itself.)
+ *
+ * This may duplicate things published in command.h, but also includes things
+ * which are not intended for "external" use.
+ */
+
+/*------------------------------------------------------------------------------
+ * Host configuration variable
+ */
+typedef unsigned long int name_gen_t ;
+
+struct host
+{
+ /* Host name of this router. */
+ char* name ;
+ bool name_set ; /* set by command */
+ name_gen_t name_gen ; /* incremented each time name changes */
+
+ /* Password for vty interface. */
+ char* password;
+ bool password_encrypted ;
+
+ /* Enable password */
+ char* enable;
+ bool enable_encrypted ;
+
+ /* System wide terminal lines default */
+ int lines;
+
+ /* Log filename. */
+ char* logfile;
+
+ /* config file name of this host */
+ char* config_file ;
+
+ /* Flags for services */
+ bool advanced;
+ bool encrypt;
+
+ /* Banner configuration. */
+ const char* motd;
+ char* motdfile;
+
+ /* Someone has the config symbol of power */
+ bool config ;
+
+ /* Allow VTY to start without password */
+ bool no_password_check ;
+
+ /* Restrict unauthenticated logins? */
+ bool restricted_mode ;
+
+ /* Vty timeout value -- see "exec timeout" command */
+ unsigned long vty_timeout_val ;
+
+ /* Vty access-class command */
+ char* vty_accesslist_name ;
+
+ /* Vty access-class for IPv6. */
+ char* vty_ipv6_accesslist_name ;
+
+ /* Current directory -- initialised in vty_init() */
+ char* vty_cwd ;
+} ;
+
+enum
+{
+ restricted_mode_default = false,
+} ;
+
+/* Structure declared in command.c */
+extern struct host host ;
+
+/*------------------------------------------------------------------------------
+ * Command qualifiers
+ */
+enum cmd_do
+{
+ cmd_do_nothing = 0, /* no action required */
+
+ cmd_do_command = 1, /* dispatch the current command line */
+
+ cmd_do_ctrl_c, /* received ^c */
+ cmd_do_ctrl_d, /* received ^d */
+ cmd_do_ctrl_z, /* received ^z */
+
+ cmd_do_eof, /* hit "EOF" */
+
+ cmd_do_count, /* number of different cli_do_xxx */
+
+ cmd_do_mask = 0x0F,
+ cmd_do_auth = 0x10,
+ cmd_do_auth_enable = 0x20,
+} ;
+
+CONFIRM(cmd_do_count <= (cmd_do_mask + 1)) ;
+
+typedef enum cmd_do cmd_do_t ;
+
+/*------------------------------------------------------------------------------
+ * Vector of nodes -- defined in command.c, declared here so the parser can
+ * reach it.
+ */
+extern vector node_vector ;
+
+/*----------------------------------------------------------------------------*/
+
+#define MSG_CMD_ERR_AMBIGUOUS "Ambiguous command"
+#define MSG_CMD_ERR_NO_MATCH "Unrecognised command"
+#define MSG_CMD_ERR_NO_MATCH_old "There is no matched command"
+
+/*==============================================================================
+ * Functions in command.c
+ */
+
+extern const char* cmd_host_name(bool fresh) ;
+extern char *host_config_file(void);
+extern void host_config_set(const char* file_name);
+
+extern const char* cmd_prompt(node_type_t node) ;
+
+extern node_type_t cmd_node_parent(node_type_t node) ;
+extern node_type_t cmd_node_exit_to(node_type_t node) ;
+extern node_type_t cmd_node_end_to(node_type_t node) ;
+
+#endif /* _ZEBRA_COMMAND_LOCAL_H */
diff --git a/lib/elstring.c b/lib/elstring.c
new file mode 100644
index 00000000..41fc88ed
--- /dev/null
+++ b/lib/elstring.c
@@ -0,0 +1,269 @@
+/* Length/String string handling
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <ctype.h>
+
+#include "elstring.h"
+#include "memory.h"
+
+/*==============================================================================
+ * Create and free
+ */
+
+/*------------------------------------------------------------------------------
+ * Create a new elstring
+ */
+extern elstring
+els_new(void)
+{
+ return XCALLOC(MTYPE_TMP, sizeof(elstring_t)) ;
+
+ confirm(ELSTRING_INIT_ALL_ZEROS) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Initialise or create a new elstring
+ */
+extern elstring
+els_init_new(elstring els)
+{
+ if (els == NULL)
+ els = els_new() ;
+ else
+ memset(els, 0, sizeof(elstring_t)) ;
+
+ confirm(ELSTRING_INIT_ALL_ZEROS) ;
+
+ return els ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Release dynamically allocated elstring.
+ *
+ * Returns NULL.
+ *
+ * NB: it is the callers responsibility to free the contents of the elstring.
+ * if that is required, before freeing the elstring itself.
+ */
+extern elstring
+els_free(elstring els)
+{
+ if (els != NULL)
+ XFREE(MTYPE_TMP, els) ;
+
+ return NULL ;
+} ;
+
+/*==============================================================================
+ * Various comparisons
+ */
+
+/*------------------------------------------------------------------------------
+ * Compare two elstrings -- returns the usual -ve, 0, +ve cmp result.
+ *
+ * NULL elstring is treated as empty.
+ */
+extern int
+els_cmp(elstring a, elstring b)
+{
+ const uchar* ap ;
+ const uchar* bp ;
+ ulen al, bl ;
+ ulen n ;
+
+ ap = els_body(a) ; /* NULL if a is NULL */
+ bp = els_body(b) ;
+ al = els_len(a) ; /* zero if a is NULL */
+ bl = els_len(b) ;
+
+ n = (al <= bl) ? al : bl ; /* min(al, bl) */
+
+ while (n)
+ {
+ int d = *ap++ - *bp++ ;
+ if (d != 0)
+ return d ;
+ --n ;
+ } ;
+
+ return al < bl ? -1 : (al == bl) ? 0 : +1 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Compare elstring against word.
+ *
+ * Returns: -1 => elstring and word match to end of elstring
+ * 0 => elstring and word match completely
+ * +1 => elstring and word do not match
+ *
+ * NULLs are treated as empty strings.
+ *
+ * An empty elstring will completely match an empty word.
+ * An empty elstring will partly match any non-empty word.
+ */
+extern int
+els_cmp_word(elstring a, const char* w)
+{
+ const uchar* ap, * ep ;
+ ulen al, wl ;
+
+ al = els_len(a) ; /* zero if a is NULL */
+ wl = (w != NULL) ? strlen(w) : 0 ; /* zero if w is NULL */
+
+ if (al > wl)
+ return +1 ; /* no match if longer */
+
+ if (al == 0)
+ return (wl == 0) ? 0 : -1 ; /* exact or partial if empty */
+
+ ap = els_body_nn(a) ;
+
+ /* Neither string is empty */
+
+ if (*ap != *w)
+ return +1 ; /* quick out if no match for 1st char */
+
+ ep = ap + al - 1 ;
+ while (ap < ep)
+ {
+ if (*++ap != *++w)
+ return 1 ;
+ } ;
+
+ return al == wl ? 0 : -1 ; /* full or partial match */
+} ;
+
+/*------------------------------------------------------------------------------
+ * Compare significant parts of two qstrings -- returns the usual -ve, 0, +ve
+ * cmp result.
+ *
+ * By significant, mean excluding leading/trailing isspace() and treating
+ * multiple isspace() as single isspace().
+ *
+ * Compares the 'len' portions of the strings.
+ *
+ * NULL elstring is treated as empty.
+ */
+extern int
+els_cmp_sig(elstring a, elstring b)
+{
+ cpp_t ap ;
+ cpp_t bp ;
+
+ /* Set up pointers and dispense with leading and trailing isspace()
+ *
+ * Dummy up if NULL
+ */
+ els_cpp(ap, a) ; /* NULL if a is NULL */
+
+ while ((ap->p < ap->e) && isspace(*ap->p))
+ ++ap->p ;
+ while ((ap->p < ap->e) && isspace(*(ap->e - 1)))
+ --ap->e ;
+
+ els_cpp(bp, b) ;
+
+ while ((bp->p < bp->e) && isspace(*bp->p))
+ ++bp->p ;
+ while ((bp->p < bp->e) && isspace(*(bp->e - 1)))
+ --bp->e ;
+
+ /* Now set about finding the first difference */
+ while ((ap->p != ap->e) && (bp->p != bp->e))
+ {
+ if (isspace(*ap->p) && isspace(*bp->p))
+ {
+ do { ++ap->p ; } while (isspace(*ap->p)) ;
+ do { ++bp->p ; } while (isspace(*bp->p)) ;
+ } ;
+
+ if (*ap->p != *bp->p)
+ return (*ap->p < *bp->p) ? -1 : +1 ;
+
+ ++ap->p ;
+ ++bp->p ;
+ } ;
+
+ /* No difference before ran out of one or both */
+ if (ap->p != ap->e)
+ return +1 ;
+ else if (bp->p != bp->e)
+ return -1 ;
+ else
+ return 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Are two elstrings equal ? -- returns true if strings equal.
+ */
+extern bool
+els_equal(elstring a, elstring b)
+{
+ const uchar* ap ;
+ const uchar* bp ;
+ ulen n ;
+
+ n = els_len(b) ; /* zero if b is NULL */
+ if (n != els_len(a))
+ return false ;
+
+ ap = els_body(a) ; /* NULL if a is NULL */
+ bp = els_body(b) ;
+
+ while (n)
+ {
+ if (*ap++ != *bp++)
+ return false ;
+ --n ;
+ } ;
+
+ return true ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Is 'b' a leading substring of 'a' ? -- returns true if it is.
+ *
+ * If 'b' is empty it is always a leading substring.
+ */
+extern bool
+els_substring(elstring a, elstring b)
+{
+ const uchar* ap ;
+ const uchar* bp ;
+ ulen n ;
+
+ n = els_len(b) ; /* zero if b is NULL */
+ if (n > els_len(a))
+ return false ;
+
+ ap = els_body(a) ;
+ bp = els_body(b) ;
+
+ while (n)
+ {
+ if (*ap++ != *bp++)
+ return false ;
+ --n ;
+ } ;
+
+ return true ;
+} ;
+
diff --git a/lib/vty_command.c b/lib/vty_command.c
new file mode 100644
index 00000000..26a9ec6a
--- /dev/null
+++ b/lib/vty_command.c
@@ -0,0 +1,863 @@
+/* VTY for command execution
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "misc.h"
+#include "stdio.h"
+
+#include "vty_command.h"
+#include "command_local.h"
+#include "command_queue.h"
+#include "command_execute.h"
+#include "command_parse.h"
+#include "vty_local.h"
+#include "vty_io.h"
+#include "vty_cli.h"
+#include "vio_fifo.h"
+#include "vty_io_file.h"
+#include "list_util.h"
+#include "qstring.h"
+
+/*==============================================================================
+ * Variables etc.
+ */
+
+/*------------------------------------------------------------------------------
+ * Prototypes
+ */
+static void uty_show_error_location(vio_vf vf) ;
+static void vty_cmd_failed(vty vty, cmd_return_code_t ret) ;
+
+/*==============================================================================
+ * There are two command loops -- cmd_read_config() and cq_process(). These
+ * functions support those command loops:
+ *
+ * * uty_cmd_prepare()
+ *
+ * After opening or closing a vin/vout object, the state of the execution
+ * context must be set to reflect the current top of the vin/vout stack.
+ *
+ * * uty_cmd_dispatch_line()
+ *
+ * This is for command lines which come from "push" sources, eg the
+ * Telnet VTY CLI or the VTYSH.
+ *
+ * Hands command line over to the vty_cli_nexus message queue.
+ *
+ * NB: from this point onwards, the vio is vio->cmd_running !
+ *
+ * * vty_cmd_fetch_line()
+ *
+ * This is for command lines which are "pulled" by one of the command
+ * execution loops, eg files and pipes. If not in cmd_read_config())
+ * can return CMD_WAITING.
+ *
+ * * vty_cmd_open_in_pipe_file()
+ * * vty_cmd_open_in_pipe_shell()
+ * * vty_cmd_open_out_pipe_file()
+ * * vty_cmd_open_out_pipe_shell()
+ *
+ * These do the I/O side of the required opens, pushing the new vty_vf
+ * onto the vin/vout stack.
+ *
+ * * vty_cmd_success()
+ *
+ * When a command returns success, this is called either to push all
+ * buffered output to the current vout, or to discard all buffered
+ * output (which is what cmd_read_config() does).
+ *
+ * If required, pops any vout(s).
+ *
+ * * vty_cmd_loop_exit()
+ *
+ * When a command has completed, successfully or otherwise, this is
+ * called to deal with any errors and return control to.
+ *
+ *
+ *
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * After opening or closing a vin/vout object, update the vty->exec context.
+ */
+extern void
+uty_cmd_prepare(vty_io vio)
+{
+ cmd_exec exec = vio->vty->exec ;
+
+ exec->parse_type = vio->vin->parse_type ;
+
+ exec->out_enabled = vio->vout->out_enabled ;
+ exec->reflect_enabled = vio->vin->reflect_enabled &&
+ vio->vout->out_enabled ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * This pushes the command line into the vty_cli_message queue, where it will
+ * be parsed and executed etc.
+ *
+ * NB: from this moment on, vio->cmd_running is true, so even if the vty is
+ * closed, it cannot be fully closed and then reaped until the flag
+ * is cleared.
+ *
+ * While vio->cmd_running the command side is responsible for the vty
+ * and the vty->exec stuff.
+ */
+extern cmd_return_code_t
+uty_cmd_dispatch(vty_io vio, cmd_do_t to_do, qstring line)
+{
+ VTY_ASSERT_LOCKED() ;
+
+ vio->cmd_running = true ;
+ uty_cmd_prepare(vio) ; /* make sure */
+
+ cq_dispatch(vio->vty, to_do, line) ;
+
+ return CMD_WAITING ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Handle a "special" command -- anything not cmd_do_command
+ */
+extern cmd_return_code_t
+vty_cmd_special(vty vty)
+{
+ cmd_return_code_t ret ;
+
+ ret = CMD_SUCCESS ;
+ /* All other nodes... */
+ switch (vty->exec->to_do)
+ {
+ case cmd_do_nothing:
+ break ;
+
+ case cmd_do_eof:
+ ret = CMD_CLOSE ;
+ break ;
+
+ case cmd_do_command:
+ zabort("invalid cmd_do_command") ;
+ break ;
+
+ case cmd_do_ctrl_d:
+ zabort("invalid cmd_do_ctrl_d") ;
+ break ;
+
+ case cmd_do_ctrl_c:
+ case cmd_do_ctrl_z:
+ ret = cmd_end(vty) ;
+ break ;
+
+ default: /* must now be cmd_do_auth or cmd_do_auth_enable */
+ VTY_LOCK() ;
+ ret = uty_cli_auth(vty->vio->vin->cli) ;
+ VTY_UNLOCK() ;
+ } ;
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Fetch the next command line to be executed.
+ *
+ * If possible, get another command line to execute -- pops pipes as required
+ * and reflects command line when have one, if required.
+ *
+ * Action depends on the type of the current input:
+ *
+ * VIN_NONE invalid
+ *
+ * VIN_TERM ) return CMD_EOF
+ * VIN_VTYSH )
+ *
+ * VIN_FILE )
+ * VIN_PIPE ) fetch another line if can.
+ * VIN_CONFIG )
+ *
+ * VIN_DEV_NULL nothing: return CMD_EOF
+ *
+ * Returns: CMD_SUCCESS => OK -- have a line ready to be processed.
+ *
+ * vty->exec->line points at the line.
+ *
+ * or: CMD_EOF => nothing to fetch -- note that if pops back to the
+ * VIN_TERM or VIN_VTYSH level, then will return
+ * CMD_EOF.
+ *
+ * If was VIN_TERM or VIN_VTYSH, signals CMD_EOF to
+ * exit from the command loop.
+ *
+ * or: CMD_WAITING => OK -- but waiting for command line to arrive.
+ *
+ * or: ....
+ */
+extern cmd_return_code_t
+vty_cmd_fetch_line(vty vty)
+{
+ cmd_return_code_t ret ;
+ vty_io vio ;
+ qstring* p_line ;
+
+ VTY_LOCK() ;
+
+ vio = vty->vio ; /* once locked */
+ p_line = &vty->exec->line ;
+
+ *p_line = NULL ;
+ vty->exec->to_do = cmd_do_nothing ;
+
+ while (1)
+ {
+ vio_vf vf ;
+
+ vf = vio->vin ;
+
+ if (vf->vin_state != vf_open)
+ {
+ switch (vf->vin_state)
+ {
+ case vf_closed:
+ case vf_eof:
+ ret = CMD_EOF ;
+ break ;
+
+ case vf_error:
+ ret = CMD_IO_ERROR ;
+ break ;
+
+ case vf_closing:
+ ret = CMD_CLOSE ;
+ break ;
+
+ default:
+ zabort("invalid vf->vin_state") ;
+ break ;
+ } ;
+ break ;
+ } ;
+
+ switch (vf->vin_type)
+ {
+ case VIN_NONE:
+ zabort("invalid VIN_NONE") ;
+ break ;
+
+ case VIN_TERM:
+ case VIN_VTYSH:
+ case VIN_DEV_NULL:
+ ret = CMD_EOF ;
+ break ;
+
+ /* fall through */
+
+ case VIN_FILE:
+ case VIN_PIPE:
+ case VIN_CONFIG:
+ ret = uty_file_fetch_command_line(vf, p_line) ;
+
+ if (ret == CMD_SUCCESS)
+ {
+ vty->exec->to_do = cmd_do_command ;
+ }
+ else if ((ret == CMD_EOF) && (vio->vin_depth > 0))
+ {
+ uty_vin_close(vio) ;
+ uty_cmd_prepare(vio) ;
+ continue ;
+ } ;
+ break ;
+
+ default:
+ zabort("unknown vin_type") ;
+ } ;
+
+ break ;
+ } ;
+
+ VTY_UNLOCK() ;
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Reflect the command line to the current vio->obuf.
+ *
+ * Advances the end_mark past the reflected line, so that output (in particular
+ * error stuff) is separate.
+ */
+extern void
+vty_cmd_reflect_line(vty vty)
+{
+ vio_fifo obuf ;
+ qstring line ;
+
+ VTY_LOCK() ;
+
+ obuf = vty->vio->obuf ; /* once locked */
+ line = vty->exec->line ;
+
+ vio_fifo_put_bytes(obuf, qs_char_nn(line), qs_len_nn(line)) ;
+ vio_fifo_put_byte(obuf, '\n') ;
+
+ uty_out_accept(vty->vio) ;
+
+ VTY_UNLOCK() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Open the given file as in in pipe, if possible.
+ *
+ * Puts error messages to vty if fails.
+ */
+extern cmd_return_code_t
+vty_cmd_open_in_pipe_file(vty vty, qstring name, bool reflect)
+{
+ cmd_return_code_t ret ;
+
+ VTY_LOCK() ;
+
+ ret = uty_file_read_open(vty->vio, name, reflect) ;
+
+ if (ret == CMD_SUCCESS)
+ uty_cmd_prepare(vty->vio) ;
+
+ VTY_UNLOCK() ;
+
+ return ret ;
+} ;
+
+extern cmd_return_code_t
+vty_cmd_open_in_pipe_shell(vty vty)
+{
+ return CMD_SUCCESS ;
+} ;
+
+extern cmd_return_code_t
+vty_cmd_open_out_pipe_file(vty vty, qstring name, bool append)
+{
+ cmd_return_code_t ret ;
+
+ VTY_LOCK() ;
+
+ ret = uty_file_write_open(vty->vio, name, append) ;
+
+ if (ret == CMD_SUCCESS)
+ uty_cmd_prepare(vty->vio) ;
+
+ VTY_UNLOCK() ;
+
+ return ret ;
+} ;
+
+extern cmd_return_code_t
+vty_cmd_open_out_dev_null(vty vty)
+{
+ vio_vf vf ;
+
+ VTY_LOCK() ;
+
+ vf = uty_vf_new(vty->vio, "dev_null", -1, vfd_none, vfd_io_none) ;
+ uty_vout_open(vty->vio, vf, VOUT_DEV_NULL, NULL, NULL, 0) ;
+
+ vf->out_enabled = false ;
+
+ VTY_UNLOCK() ;
+ return CMD_SUCCESS ;
+} ;
+
+extern cmd_return_code_t
+vty_cmd_open_out_pipe_shell(vty vty)
+{
+ return CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command has completed successfully.
+ *
+ * An output generated by the command is now pushed if exec->out_enabled,
+ * or discarded.
+ *
+ * If the vin_depth < vout_depth, then close vouts until the depth is equal.
+ */
+extern cmd_return_code_t
+vty_cmd_success(vty vty)
+{
+ vty_io vio ;
+
+ VTY_LOCK() ;
+ vio = vty->vio ; /* once locked */
+
+ if (!vio_fifo_empty_tail(vio->obuf))
+ {
+ if (vty->exec->out_enabled)
+ uty_cmd_out_push(vio) ;
+ else
+ uty_out_clear(vio) ;
+ } ;
+
+ /* Deal with closing out pipe on individual command */
+ while (vio->vout_depth > vio->vin_depth)
+ {
+ uty_vout_close(vio, false) ; /* ignore failures TODO */
+ uty_cmd_prepare(vio) ; /* set new state */
+ } ;
+
+ VTY_UNLOCK() ;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * If there is anything after the end_mark, push it to be written, now.
+ *
+ * See uty_cmd_out_push() below.
+ */
+extern void
+vty_cmd_out_push(vty vty)
+{
+ VTY_LOCK() ;
+ uty_cmd_out_push(vty->vio) ;
+ VTY_UNLOCK() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * If there is anything after the end_mark, push it to be written, now.
+ *
+ * For most outputs we kick the I/O side so that the pselect processing deals
+ * with the required write. For VOUT_STDERR and VOUT_STDOUT, output goes
+ * directly to standard I/O.
+ *
+ * Advances the end_mark past the stuff pushed.
+ *
+ * NB: takes no notice of vf->out_enabled... this is used when outputting
+ * any error messages when reading the configuration file.
+ *
+ * TODO: worry about closing state !
+ */
+extern void
+uty_cmd_out_push(vty_io vio)
+{
+ cmd_return_code_t ret ;
+ vio_vf vf ;
+
+ vf = vio->vout ;
+
+ assert(vio->obuf == vf->obuf) ;
+
+ uty_out_accept(vio) ; /* advance the end mark */
+
+ if (vf->vout_state != vf_open)
+ {
+ switch (vf->vout_state)
+ {
+ case vf_closed:
+ case vf_eof:
+ ret = CMD_EOF ; /* TODO what's to do ? */
+ break ;
+
+ case vf_error:
+ ret = CMD_IO_ERROR ;
+ break ;
+
+ case vf_closing:
+ ret = CMD_CLOSE ; /* TODO continue with output ? */
+ break ;
+
+ default:
+ zabort("invalid vf->vout_state") ;
+ break ;
+ } ;
+
+ return ; /* TODO errors ?? */
+ } ;
+
+ switch (vio->vout->vout_type)
+ {
+ case VOUT_NONE:
+ zabort("invalid vout_none") ;
+ break ;
+
+ case VOUT_TERM:
+ uty_cli_out_push(vf->cli) ;
+ break ;
+
+ case VOUT_VTYSH:
+ /* Kick the writer */
+ break ;
+
+ case VOUT_FILE:
+ uty_file_out_push(vf) ;
+ break ;
+
+ case VOUT_PIPE:
+ /* Kick the writer */
+ break ;
+
+ case VOUT_CONFIG:
+ /* Kick the writer */
+ break ;
+
+ case VOUT_DEV_NULL:
+ uty_out_clear(vio) ; /* clear fifo, keep end mark */
+ break ;
+
+ case VOUT_STDOUT:
+ vio_fifo_fwrite(vio->obuf, stdout) ;
+ break ;
+
+ case VOUT_STDERR:
+ vio_fifo_fwrite(vio->obuf, stderr) ;
+ break ;
+
+ default:
+ zabort("unknown vout_type") ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The command loop has exited, with the given return code.
+ *
+ * There are a number of return codes that are treated as success. On any
+ * of those, does vty_cmd_success() (which has no effect if already done).
+ *
+ * If not a success return code, then close down any pipe-work, and create
+ * suitable error message.
+ *
+ * If is any form of success, returns CMD_SUCCESS -- otherwise returns the
+ * return code as given.
+ */
+extern cmd_return_code_t
+vty_cmd_loop_exit(vty vty, cmd_return_code_t ret)
+{
+ bool close ;
+
+ /* Deal with the several names of success and the many names of failure.
+ */
+ close = false ;
+
+ switch(ret)
+ {
+ case CMD_CLOSE:
+ case CMD_EOF:
+ close = true ;
+ fall_through ;
+
+ case CMD_SUCCESS:
+ case CMD_EMPTY:
+ ret = vty_cmd_success(vty) ;
+ break ;
+
+ default:
+ /* If not CMD_SUCCESS, the treat as some sort of error:
+ *
+ * * close down all pipes -- leaving just the vin_base/vout_base.
+ * * create error messages in the vout_base.
+ */
+ vty_cmd_failed(vty, ret) ;
+ break ;
+ } ;
+
+ /* They think it's all over... */
+
+ VTY_LOCK() ;
+
+ vty->vio->cmd_running = false ;
+
+ if (vty->vio->vin->vin_type == VIN_TERM)
+ uty_cli_done_command(vty->vio->vin->cli, vty->node) ;
+
+ /* ... it is now. */
+
+ if (close)
+ uty_close(vty->vio, false, NULL) ;
+
+ VTY_UNLOCK() ;
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Dealing with error of some kind.
+ *
+ * Error is reported on the vout_base. Whatever the command has written
+ * so far will be appended to the reporting of the error location.
+ *
+ * If there is only one vout, then:
+ *
+ * - if is VOUT_TERM, then need to wipe the command line. The failing
+ * line will be the last output line on screen (unless monitor output,
+ * which can do nothing about).
+ *
+ * - if is VOUT_VTYSH, then the failing line will be the last output line
+ * on the screen.
+ *
+ * - if is VOUT_xxx, then nothing will have been reflected.
+ *
+ * In any event, need to separate out any output from the failing command,
+ * so that can report error location and type, before showing the error
+ * message(s).
+ *
+ * NB: does not expect to see all the possible CMD_XXX return codes (see
+ * below), but treats all as a form of error !
+ */
+static void
+vty_cmd_failed(vty vty, cmd_return_code_t ret)
+{
+ vty_io vio ;
+ vio_fifo tbuf ;
+ ulen eloc ;
+
+ VTY_LOCK() ;
+ vio = vty->vio ; /* once locked */
+
+ /* Copy command output to temporary, and remove from the obuf.
+ *
+ * Any command output should be messages explaining the error, and we want
+ * those (a) on the base vout, and (b) after description of where the error
+ * occurred.
+ */
+ tbuf = vio_fifo_copy_tail(NULL, vio->obuf) ;
+ vio_fifo_back_to_end_mark(vio->obuf, true) ;
+
+ /* Can now close everything in the vout stack, so all further output
+ * is to the vout_base.
+ */
+ uty_vout_close_stack(vio, false) ; /* not "final" */
+
+ /* Process the vin stack to generate the error location(s) */
+ uty_show_error_location(vio->vin) ;
+
+ if (vio->vin->vin_type == VIN_TERM)
+ eloc = uty_cli_prompt_len(vio->vin->cli) ;
+ else
+ eloc = 0 ;
+
+ /* Can now close everything in the vin stack */
+ uty_vin_close_stack(vio) ;
+
+ /* Now any additional error message if required */
+ switch (ret)
+ {
+ qstring qs ;
+
+ case CMD_WARNING:
+ if (vio_fifo_empty(tbuf))
+ uty_out(vio, "%% WARNING: non-specific warning\n") ;
+ break ;
+
+ case CMD_ERROR:
+ if (vio_fifo_empty(tbuf))
+ uty_out(vio, "%% ERROR: non-specific error\n") ;
+ break ;
+
+ case CMD_IO_ERROR:
+ break ;
+
+ case CMD_ERR_PARSING:
+ qs = qs_set_fill(NULL, eloc + vio->vty->exec->parsed->eloc, "....") ;
+ uty_out(vio, "%s^\n%% %s\n", qs_string(qs),
+ vio->vty->exec->parsed->emess) ;
+ qs_reset(qs, free_it) ;
+ break ;
+
+ case CMD_ERR_NO_MATCH:
+ uty_out(vio, "%% Unknown command.\n") ;
+ break;
+
+ case CMD_ERR_AMBIGUOUS:
+ uty_out(vio, "%% Ambiguous command.\n");
+ break;
+
+ case CMD_ERR_INCOMPLETE:
+ uty_out(vio, "%% Command incomplete.\n");
+ break;
+
+ case CMD_SUCCESS:
+ case CMD_SUCCESS_DAEMON:
+ case CMD_CLOSE:
+ case CMD_EMPTY:
+ case CMD_WAITING:
+ case CMD_EOF:
+ case CMD_COMPLETE_FULL_MATCH:
+ case CMD_COMPLETE_MATCH:
+ case CMD_COMPLETE_LIST_MATCH:
+ case CMD_COMPLETE_ALREADY:
+ default:
+ uty_out(vio, "%% Unexpected return code (%d).\n", (int)ret) ;
+ break ;
+ } ;
+
+ /* Now stick the tbuf onto the end of the output & discard tbuf. */
+ vio_fifo_copy(vio->obuf, tbuf) ;
+ vio_fifo_reset(tbuf, free_it) ;
+
+ uty_cmd_out_push(vio) ;
+
+ VTY_UNLOCK() ;
+} ;
+
+static void
+uty_show_error_location(vio_vf vf)
+{
+ vio_vf vf_next ;
+
+ /* Recurse until hit end of the vin stack */
+ vf_next = ssl_next(vf, vin_next) ;
+
+ if (vf_next != NULL)
+ uty_show_error_location(vf_next) ;
+ else
+ assert(vf == vf->vio->vin_base) ;
+
+ /* On the way back, add the error location for each vin entry */
+ switch (vf->vin_type)
+ {
+ case VIN_NONE:
+ zabort("invalid VIN_NONE") ;
+ break ;
+
+ case VIN_TERM:
+ /* Wipe the current command line */
+// uty_term_show_error_location(vf, loc) ;
+ break ;
+
+ case VIN_VTYSH:
+ break ;
+
+ case VIN_FILE:
+
+ case VIN_PIPE:
+
+ case VIN_CONFIG:
+ uty_out(vf->vio, "%% on line %d of %s:\n", vf->line_number, vf->name) ;
+ uty_out(vf->vio, "%s\n", qs_make_string(vf->cl)) ;
+ break ;
+
+ case VIN_DEV_NULL:
+ break ;
+
+ default:
+ zabort("unknown vin_type") ;
+ } ;
+} ;
+
+/*==============================================================================
+ * Configuration node/state handling
+ *
+ * At most one VTY may hold the configuration symbol of power at any time.
+ */
+
+/*------------------------------------------------------------------------------
+ * 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 (!host.config)
+ {
+ vty->config = true ;
+ host.config = true ;
+ } ;
+
+ result = vty->config;
+
+ if (result)
+ vty->node = node ;
+
+ VTY_UNLOCK() ;
+
+ 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, node_type_t node)
+{
+ VTY_ASSERT_LOCKED() ;
+
+ if (host.config && vty->config)
+ {
+ vty->config = false ;
+ host.config = false ;
+ }
+
+ assert(node <= MAX_NON_CONFIG_NODE) ;
+ vty->node = node ;
+} ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*------------------------------------------------------------------------------
+ * Result of command is to close the input.
+ *
+ * Posts the reason for the close.
+ *
+ * Returns: CMD_CLOSE
+ */
+extern cmd_return_code_t
+uty_cmd_close(vty_io vio, const char* reason)
+{
+ vio->close_reason = qs_set(NULL, reason) ;
+ return CMD_CLOSE ;
+} ;
+
+
diff --git a/lib/vty_command.h b/lib/vty_command.h
new file mode 100644
index 00000000..7b13721d
--- /dev/null
+++ b/lib/vty_command.h
@@ -0,0 +1,61 @@
+/* VTY for command execution
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VTY_COMMAND_H
+#define _ZEBRA_VTY_COMMAND_H
+
+#include "misc.h"
+
+#include "command_local.h"
+#include "vty_local.h"
+#include "vty_io.h"
+
+extern cmd_return_code_t uty_cmd_dispatch(vty_io vio, cmd_do_t to_do,
+ qstring line) ;
+extern cmd_return_code_t vty_cmd_fetch_line(vty vty) ;
+extern cmd_return_code_t vty_cmd_special(vty vty) ;
+extern void vty_cmd_reflect_line(vty vty) ;
+extern void vty_cmd_out_push(vty vty) ;
+extern void uty_cmd_out_push(vty_io vio) ;
+
+extern cmd_return_code_t vty_cmd_open_in_pipe_file(vty vty, qstring name,
+ bool reflect) ;
+extern cmd_return_code_t vty_cmd_open_in_pipe_shell(vty vty) ;
+extern cmd_return_code_t vty_cmd_open_out_pipe_file(vty vty, qstring name,
+ bool append) ;
+extern cmd_return_code_t vty_cmd_open_out_dev_null(vty vty) ;
+extern cmd_return_code_t vty_cmd_open_out_pipe_shell(vty vty) ;
+extern cmd_return_code_t vty_cmd_success(vty vty) ;
+extern cmd_return_code_t vty_cmd_loop_exit(vty vty, cmd_return_code_t ret) ;
+
+extern void uty_cmd_prepare(vty_io vio) ;
+
+extern cmd_return_code_t uty_cmd_close(vty_io vio, const char* reason) ;
+
+extern bool vty_config_lock (vty vty, node_type_t node);
+extern void vty_config_unlock (vty vty, node_type_t node);
+extern void uty_config_unlock (vty vty, node_type_t node) ;
+
+
+
+#endif /* _ZEBRA_VTY_COMMAND_H */
diff --git a/lib/vty_common.h b/lib/vty_common.h
new file mode 100644
index 00000000..7c0929b8
--- /dev/null
+++ b/lib/vty_common.h
@@ -0,0 +1,129 @@
+/* VTY top level
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VTY_COMMON_H
+#define _ZEBRA_VTY_COMMON_H
+
+#include "misc.h"
+#include "qstring.h"
+#include "command_common.h"
+
+/*==============================================================================
+ * These are things required by:
+ *
+ * vty.h -- which is used by all "external" code.
+ *
+ * command_local.h -- which is used by all "internal" code.
+ *
+ * This allows some things not to be published to "external" code.
+ */
+
+/*==============================================================================
+ * VTY Types and the VTY structure.
+ *
+ * The "struct vty" is used extensively across the Quagga daemons, where it
+ * has two functions relating to command handling as:
+ *
+ * 1) a "file handle" for output produced by commands
+ *
+ * 2) the holder of some context -- notably the current command "node" -- for
+ * command execution to use
+ *
+ * The bulk of "struct vty" is, therefore, private to vty.c et al and is
+ * factored out into the "struct vty_io" -- opaque to users of the struct vty.
+ *
+ * There is also context used when parsing and executing commands which is
+ * private to command.c et al, and is factored out into the "struct execution"
+ * -- also opaque to users of the struct vty.
+ */
+enum vty_type /* Command output */
+{
+ VTY_TERMINAL, /* a telnet terminal server */
+ VTY_SHELL_SERVER, /* a vty_shell server */
+
+ VTY_SHELL_CLIENT, /* a vty_shell client */
+
+ VTY_CONFIG_READ, /* configuration file reader */
+
+ VTY_STDOUT, /* stdout */
+ VTY_STDERR, /* stderr */
+} ;
+typedef enum vty_type vty_type_t ;
+
+/* Most of the contents of the vty structure live in two opaque structures,
+ * which are forward referenced here.
+ */
+struct vty_io ;
+struct cmd_execution ;
+
+/* All command execution functions take a vty argument, and this is it.
+ */
+typedef struct vty* vty ;
+struct vty
+{
+ vty_type_t type ;
+
+ /*----------------------------------------------------------------------
+ * The following are the context in which commands are executed.
+ *
+ * While a command has the vty in its hands, it can access and change these
+ * because they are not touched by the CLI thread until the command has
+ * completed.
+ */
+
+ /* Node status of this vty. */
+ node_type_t node ;
+
+ /* For current referencing point of interface, route-map, access-list
+ * etc...
+ *
+ * NB: this value is private to the command execution, which is assumed
+ * to all be in the one thread... so no lock required.
+ */
+ void* index ;
+
+ /* For multiple level index treatment such as key chain and key.
+ *
+ * NB: this value is private to the command execution, which is assumed
+ * to all be in the one thread... so no lock required.
+ */
+ void* index_sub ;
+
+ /* In configure mode (owner of the symbol of power) */
+ bool config;
+
+ /*----------------------------------------------------------------------------
+ * The current cmd_exec environment -- used in command_execute.c et al
+ *
+ * This is accessed freely by the command handling code while
+ * vio->cmd_running.
+ */
+ struct cmd_exec* exec ; /* one per vty */
+
+ /*----------------------------------------------------------------------
+ * The following is used inside vty.c etc only -- under VTY_LOCK.
+ */
+ struct vty_io* vio ; /* one per vty */
+} ;
+
+#endif /* _ZEBRA_VTY_COMMON_H */
diff --git a/lib/vty_io_vsh.c b/lib/vty_io_vsh.c
new file mode 100644
index 00000000..7b24b871
--- /dev/null
+++ b/lib/vty_io_vsh.c
@@ -0,0 +1,369 @@
+/* VTY IO SHELL -- VTY Shell I/O
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "zebra.h"
+
+#include "vty.h"
+#include "vty_io.h"
+#include "vty_cli.h"
+#include "qstring.h"
+#include "keystroke.h"
+
+#include "memory.h"
+
+#include "prefix.h"
+#include "filter.h"
+#include "privs.h"
+#include "sockunion.h"
+#include "network.h"
+
+#include <arpa/telnet.h>
+#include <sys/un.h> /* for VTYSH */
+#include <sys/socket.h>
+
+#define VTYSH_DEBUG 0
+
+#if 0
+
+/*------------------------------------------------------------------------------
+ * Create new vty of type VTY_SHELL_SERV -- ie attached to a vtysh session.
+ *
+ * Returns: new vty
+ */
+static struct vty *
+uty_new_shell_serv(int sock_fd)
+{
+ struct vty *vty ;
+ vty_io vio ;
+
+ VTY_ASSERT_LOCKED() ;
+
+ /* Allocate new vty structure and set up default values. */
+ vty = uty_new (VTY_SHELL_SERV, sock_fd) ;
+ vio = vty->vio ;
+
+ /* Set the action functions */
+ if (vty_nexus)
+ {
+ vio->sock.action.read.qnexus = vtysh_read_qnexus ;
+ vio->sock.action.write.qnexus = vty_write_qnexus ;
+ vio->sock.action.timer.qnexus = NULL ;
+ }
+ else
+ {
+ vio->sock.action.read.thread = vtysh_read_thread ;
+ vio->sock.action.write.thread = vty_write_thread ;
+ vio->sock.action.timer.thread = NULL ;
+ } ;
+
+ vty->node = VIEW_NODE;
+
+ /* Kick start the CLI etc. */
+ uty_sock_set_readiness(&vio->sock, write_ready) ;
+
+ return vty;
+} ;
+
+
+/*------------------------------------------------------------------------------
+ * Open a VTY_SHEL_SERV listener socket (UNIX domain).
+ *
+ * Returns: < 0 => failed
+ * >= 0 => OK
+ */
+static int
+uty_serv_vtysh(const char *path)
+{
+ int ret;
+ int sock, sa_len, path_len ;
+ struct sockaddr_un sa_un ;
+ mode_t old_mask;
+ struct zprivs_ids_t ids;
+
+ VTY_ASSERT_LOCKED() ;
+
+ /* worry about the path length */
+ path_len = strlen(path) + 1 ;
+ if (path_len >= (int)sizeof(sa_un.sun_path))
+ {
+ uzlog(NULL, LOG_ERR, "path too long for unix stream socket: '%s'", path);
+ return -1 ;
+ } ;
+
+ /* First of all, unlink existing socket */
+ unlink (path);
+
+ /* Make UNIX domain socket. */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ uzlog(NULL, LOG_ERR, "Cannot create unix stream socket: %s",
+ errtoa(errno, 0).str) ;
+ return -1 ;
+ }
+
+ /* Bind to the required path */
+ memset (&sa_un, 0, sizeof(sa_un));
+ sa_un.sun_family = AF_UNIX;
+ strncpy (sa_un.sun_path, path, sizeof(sa_un.sun_path) - 1);
+
+ sa_len = SUN_LEN(&sa_un) ;
+
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ sa_un.sun_len = sa_len ;
+#endif
+
+ old_mask = umask (0007);
+
+ ret = bind (sock, (struct sockaddr *) &sa_un, sa_len) ;
+ if (ret < 0)
+ uzlog(NULL, LOG_ERR, "Cannot bind path %s: %s", path, errtoa(errno, 0).str);
+
+ if (ret >= 0)
+ ret = set_nonblocking(sock);
+
+ if (ret >= 0)
+ {
+ ret = listen (sock, 5);
+ if (ret < 0)
+ uzlog(NULL, LOG_ERR, "listen(fd %d) failed: %s", sock,
+ errtoa(errno, 0).str) ;
+ } ;
+
+ zprivs_get_ids(&ids);
+
+ if (ids.gid_vty > 0)
+ {
+ /* set group of socket */
+ if ( chown (path, -1, ids.gid_vty) )
+ uzlog (NULL, LOG_ERR, "uty_serv_vtysh: could chown socket, %s",
+ errtoa(errno, 0).str) ;
+ }
+
+ umask (old_mask);
+
+ /* Give up now if failed along the way */
+ if (ret < 0)
+ {
+ close (sock) ;
+ return -1 ;
+ } ;
+
+ /* Socket is open -- set VTY Term listener going */
+ uty_serv_start_listener(sock, VTY_SHELL_SERV) ;
+
+ return 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Accept action -- create and dispatch VTY_SHELL_SERV
+ */
+static int
+uty_accept_shell_serv (vty_listener listener)
+{
+ int sock_fd ;
+ int ret ;
+ int client_len ;
+ struct sockaddr_un client ;
+
+ VTY_ASSERT_LOCKED() ;
+
+ client_len = sizeof(client);
+ memset (&client, 0, client_len);
+
+ sock_fd = accept(listener->sock.fd, (struct sockaddr *) &client,
+ (socklen_t *) &client_len) ;
+
+ if (sock_fd < 0)
+ {
+ uzlog (NULL, LOG_WARNING, "can't accept vty shell socket : %s",
+ errtoa(errno, 0).str) ;
+ return -1;
+ }
+
+ /* Really MUST have non-blocking */
+ ret = set_nonblocking(sock_fd) ; /* issues WARNING if fails */
+ if (ret < 0)
+ {
+ close(sock_fd) ;
+ return -1 ;
+ } ;
+
+ /* All set -- create the VTY_SHELL_SERV */
+ if (VTYSH_DEBUG)
+ printf ("VTY shell accept\n");
+
+ uty_new_shell_serv(sock_fd) ;
+
+ /* Log new VTY */
+ uzlog (NULL, LOG_INFO, "Vty shell connection (fd %d)", sock_fd);
+ return 0;
+}
+
+/*==============================================================================
+ * Reading from the VTY_SHELL_SERV type sock.
+ *
+ * The select/pselect call-back ends up in utysh_read_ready().
+ */
+
+/*------------------------------------------------------------------------------
+ * Ready to read -> kicking the "SHELL_SERV CLI"
+ *
+ * End up here when there is something ready to be read.
+ *
+ * Will also end up here if an error has occurred, the other end has closed,
+ * this end has half closed, etc. This fact is used to kick the CLI even when
+ * there is no data to be read.
+ *
+ * Note that nothing is actually read here -- reading is done in the CLI itself,
+ * if required.
+ *
+ * The CLI decides whether to re-enable read, or enable write, or both.
+ */
+static void
+utysh_read_ready(vty_io vio)
+{
+ uty_sock_set_read(&vio->sock, off) ;
+
+ /* TODO: need minimal "CLI" for VTY_SHELL_SERV
+ * NB: when output from command is flushed out, must append the
+ * following four bytes: '\0' '\0' '\0' <ret>
+ * Where <ret> is the command return code.
+ */
+} ;
+
+/*------------------------------------------------------------------------------
+ * Callback -- qnexus: ready to read -> kicking the "SHELL_SERV CLI"
+ */
+static void
+vtysh_read_qnexus(qps_file qf, void* file_info)
+{
+ vty_io vio = file_info;
+
+ VTY_LOCK() ;
+
+ assert((vio->sock.fd == qf->fd) && (vio == vio->sock.info)) ;
+
+ utysh_read_ready(vio) ;
+
+ VTY_UNLOCK() ;
+}
+
+/*------------------------------------------------------------------------------
+ * Callback -- threads: ready to read -> kicking the "SHELL_SERV CLI"
+ */
+static int
+vtysh_read_thread(struct thread *thread)
+{
+ vty_io vio = THREAD_ARG (thread);
+
+ VTY_LOCK() ;
+
+ assert(vio->sock.fd == THREAD_FD (thread) && (vio == vio->sock.info)) ;
+
+ vio->sock.t_read = NULL ; /* implicitly */
+ utysh_read_ready(vio);
+
+ VTY_UNLOCK() ;
+ return 0 ;
+}
+
+/*------------------------------------------------------------------------------
+ * Read a lump of bytes and shovel into the command line buffer
+ *
+ * Lines coming in are terminated by '\0'.
+ *
+ * Assumes that the incoming command line is empty or otherwise incomplete.
+ *
+ * Moves stuff from the "buf" qstring and appends to "cl" qstring, stopping
+ * when get '\0' or empties the "buf".
+ *
+ * When empties "buf", reads a lump from the sock.
+ *
+ * Returns: 0 => command line is incomplete
+ * 1 => have a complete command line
+ * -1 => EOF (or not open, or failed)
+ */
+extern int
+utysh_read (vty_io vio, qstring cl, qstring buf)
+{
+ int get ;
+ char* cp ;
+ char* ep ;
+ size_t have ;
+
+ while (1)
+ {
+ /* process what there is in the buffer */
+ if (buf->len > buf->cp)
+ {
+ cp = qs_cp_char(buf) ;
+ ep = qs_ep_char(buf) ;
+ have = ep - cp ;
+
+ ep = memchr(cp, '\0', have) ;
+ if (ep != NULL)
+ have = ep - cp ; /* have upto, but excluding '\0' */
+
+ if (have > 0) /* take what have */
+ {
+ qs_insert(cl, cp, have) ;
+ cl->cp += have ;
+ buf->cp += have ;
+ } ;
+
+ if (ep != NULL) /* if found '\0' */
+ {
+ qs_term(cl) ; /* '\0' terminate */
+ ++buf->cp ; /* step past it */
+ return 1 ; /* have a complete line <<<<<<<<<<<<< */
+ }
+ } ;
+
+ /* buffer is empty -- try and get some more stuff */
+ assert(buf->len == buf->cp) ;
+
+ if (!vio->sock.read_open)
+ return -1 ; /* at EOF if not open <<<<<<<<<<<<< */
+
+ qs_need(buf, 500) ; /* need a reasonable lump */
+ qs_clear(buf) ; /* set cp = len = 0 */
+
+ get = read_nb(vio->sock.fd, buf->body, buf->size) ;
+ if (get > 0)
+ buf->len = get ;
+ else if (get == 0)
+ return 0 ; /* have an incomplete line <<<<<<<<<<<< */
+ else
+ {
+ if (get == -1)
+ uty_sock_error(vio, "read") ;
+
+ vio->sock.read_open = 0 ;
+
+ return -1 ; /* at EOF or failed <<<<<<<<<<<<< */
+ } ;
+ } ;
+} ;
+
+#endif
diff --git a/lib/vty_io_vsh.h b/lib/vty_io_vsh.h
new file mode 100644
index 00000000..87cd92d0
--- /dev/null
+++ b/lib/vty_io_vsh.h
@@ -0,0 +1,55 @@
+/* VTY IO SHELL -- VTY Shell I/O -- header
+ * Virtual terminal [aka TeletYpe] interface routine.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VTY_IO_SHELL_H
+#define _ZEBRA_VTY_IO_SHELL_H
+
+#include "misc.h"
+#include <errno.h>
+
+#include "uty.h"
+#include "vty.h"
+#include "vty_io.h"
+#include "vio_fifo.h"
+#include "vio_lines.h"
+#include "keystroke.h"
+#include "thread.h"
+#include "command.h"
+#include "qstring.h"
+
+/*==============================================================================
+ * Here are structures and other definitions which are shared by:
+ *
+ * vty_io.c -- the main VTY I/O stuff
+ *
+ * for I/O for VTY Shell Server.
+ */
+
+/*==============================================================================
+ * Functions
+ */
+
+extern int uty_vprintf_shell(vty_io vio, const char *format, va_list args) ;
+
+#endif /* _ZEBRA_VTY_IO_SHELL_H */
diff --git a/lib/vty_local.h b/lib/vty_local.h
new file mode 100644
index 00000000..2767f9d3
--- /dev/null
+++ b/lib/vty_local.h
@@ -0,0 +1,193 @@
+/* VTY top level
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VTY_LOCAL_H
+#define _ZEBRA_VTY_LOCAL_H
+
+#include "vty_common.h" /* First and foremost */
+#include "command_common.h"
+
+#include "vargs.h"
+
+#include "qpthreads.h"
+#include "qpnexus.h"
+#include "thread.h"
+
+/*==============================================================================
+ * This is for access to some things in vty.c which are not required
+ * by external users, who use vty.h.
+ *
+ * This is for use within the command/vty family.
+ *
+ * Should not be used with vty.h ! (Except in vty.c itself.)
+ *
+ * This may duplicate things published in vty.h, but also includes things
+ * which are not intended for "external" use.
+ */
+
+/*==============================================================================
+ * The VTYSH uses a unix socket to talk to the daemon.
+ *
+ * The ability to respond to a connection from VTYSH appears to be a *compile*
+ * time option. In the interests of keeping the code up to date, the VTYSH
+ * option is turned into a testable constant.
+ */
+#ifdef VTYSH
+ enum { VTYSH_ENABLED = true } ;
+#else
+ enum { VTYSH_ENABLED = false } ;
+#endif
+
+/*==============================================================================
+ * Variables in vty.c -- used in any of the family
+ */
+extern struct vty_io* vio_list_base ;
+extern struct vty_io* vio_monitors_base ;
+extern struct vty_io* vio_death_watch ;
+
+extern struct thread_master* vty_master ;
+
+extern bool vty_nexus ;
+
+extern qpn_nexus vty_cli_nexus ;
+extern qpn_nexus vty_cmd_nexus ;
+
+/*==============================================================================
+ * To make vty qpthread safe we use a single mutex.
+ *
+ * vty and log recurse through each other, so the same mutex is used
+ * for both, i.e. they are treated as being part of the same monitor.
+ *
+ * A recursive mutex is used. This simplifies the calling from log to vty and
+ * back again. It also allows for the vty internals to call each other.
+ *
+ * There are some "uty" functions which assume the mutex is locked.
+ *
+ * vty is closely bound to the command handling -- the main vty structure
+ * contains the context in which commands are parsed and executed.
+ */
+
+extern qpt_mutex_t vty_mutex ;
+
+#ifdef NDEBUG
+# define VTY_DEBUG 0 /* NDEBUG override */
+#else
+# ifndef VTY_DEBUG
+# define VTY_DEBUG 1 /* Set to 1 to turn on debug checks */
+# endif
+#endif
+
+#if VTY_DEBUG
+
+extern int vty_lock_count ;
+extern int vty_assert_fail ;
+
+#endif
+
+Inline void
+VTY_LOCK(void) /* if is qpthreads_enabled, lock vty_mutex */
+{
+ qpt_mutex_lock(&vty_mutex) ;
+ if (VTY_DEBUG)
+ ++vty_lock_count ;
+} ;
+
+Inline void
+VTY_UNLOCK(void) /* if is qpthreads_enabled, unlock vty_mutex */
+{
+ if (VTY_DEBUG)
+ --vty_lock_count ;
+ qpt_mutex_unlock(&vty_mutex) ;
+} ;
+
+Inline bool /* true => is (effectively) cli thread */
+vty_is_cli_thread(void)
+{
+ return !qpthreads_enabled || qpt_thread_is_self(vty_cli_nexus->thread_id) ;
+} ;
+
+/* For debug (and documentation) purposes, will VTY_ASSERT_LOCKED where that
+ * is required.
+ *
+ * In some cases, need also to be running in the CLI thread as well.
+ *
+ * Note that both these checks will pass if !qpthreads_enabled. So can have
+ * code which is called before qpthreads are started up, or which will never
+ * run qpthreaded !
+ */
+#if VTY_DEBUG
+
+Inline void
+VTY_ASSERT_FAILED(void)
+{
+ if (vty_assert_fail == 0) ;
+ {
+ vty_assert_fail = 1 ;
+ assert(0) ;
+ } ;
+} ;
+
+Inline void
+VTY_ASSERT_LOCKED(void)
+{
+ if ((vty_lock_count == 0) && (qpthreads_enabled))
+ VTY_ASSERT_FAILED() ;
+} ;
+
+Inline void
+VTY_ASSERT_CLI_THREAD(void)
+{
+ if (!vty_is_cli_thread())
+ VTY_ASSERT_FAILED() ;
+} ;
+
+#else
+
+#define VTY_ASSERT_LOCKED()
+#define VTY_ASSERT_CLI_THREAD()
+
+#endif
+
+/*==============================================================================
+ * Functions in vty.c -- used in any of the family
+ */
+extern int vty_out (vty vty, const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+extern int vty_out_indent(vty vty, int indent) ;
+extern void vty_out_clear(vty vty) ;
+
+extern void vty_set_lines(vty vty, int lines);
+
+extern bool vty_close(vty vty, bool final, qstring reason) ;
+
+extern void vty_open_config_write(vty vty, int fd) ;
+extern int vty_close_config_write(vty vty) ;
+
+extern void vty_log_fixed (const char *buf, size_t len);
+
+struct logline ; /* forward reference */
+struct zlog ; /* forward reference */
+
+extern void uty_log (struct logline* ll, struct zlog *zl, int priority,
+ const char *format, va_list va);
+
+#endif /* _ZEBRA_VTY_LOCAL_H */
diff --git a/lib/zconfig.h b/lib/zconfig.h
new file mode 100644
index 00000000..052bfe99
--- /dev/null
+++ b/lib/zconfig.h
@@ -0,0 +1,28 @@
+/* Zebra common header.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _ZEBRA_CONFIG_H
+#define _ZEBRA_CONFIG_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#endif /* _ZEBRA_CONFIG_H */