diff options
author | Chris Hall <chris.hall@highwayman.com> | 2011-02-13 22:53:14 +0000 |
---|---|---|
committer | Chris Hall <chris.hall@highwayman.com> | 2011-02-13 22:53:14 +0000 |
commit | 64be6d766a65dc0749d17f5023d714678e9c96a6 (patch) | |
tree | f97e04068600d0851687b58d25ff198d1eb6cc73 | |
parent | 8443ca08672e0cf5b779f59db9d556dadf763de7 (diff) | |
download | quagga-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.h | 221 | ||||
-rw-r--r-- | lib/command_execute.c | 460 | ||||
-rw-r--r-- | lib/command_local.h | 161 | ||||
-rw-r--r-- | lib/elstring.c | 269 | ||||
-rw-r--r-- | lib/vty_command.c | 863 | ||||
-rw-r--r-- | lib/vty_command.h | 61 | ||||
-rw-r--r-- | lib/vty_common.h | 129 | ||||
-rw-r--r-- | lib/vty_io_vsh.c | 369 | ||||
-rw-r--r-- | lib/vty_io_vsh.h | 55 | ||||
-rw-r--r-- | lib/vty_local.h | 193 | ||||
-rw-r--r-- | lib/zconfig.h | 28 |
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 */ |