summaryrefslogtreecommitdiffstats
path: root/lib/vty_pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vty_pipe.c')
-rw-r--r--lib/vty_pipe.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/lib/vty_pipe.c b/lib/vty_pipe.c
new file mode 100644
index 00000000..b2c3fd64
--- /dev/null
+++ b/lib/vty_pipe.c
@@ -0,0 +1,496 @@
+/* VTY Command Line Pipe Handling
+ * 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_cli.h"
+#include "vty_command.h"
+#include "vty_io.h"
+#include "vio_lines.h"
+
+#include "command_execute.h"
+#include "command_queue.h"
+
+#include "memory.h"
+
+/*==============================================================================
+ * VTY Command Line Input Pipe
+ *
+ * Here are the mechanics which support the:
+ *
+ * < file_name
+ *
+ * <| shell_command
+ *
+ * and the:
+ *
+ * > file_name
+ * >> file_name
+ * | shell_command
+ *
+ *==============================================================================
+ * The file_name handling
+ *
+ * Two directories are supported:
+ *
+ * "home" -- being the root for configuration files
+ *
+ * "cd" -- being the root for relative filenames, in the usual way
+ *
+ * "here" -- being the directory for the enclosing "< filename"
+ * see below for more detailed semantics
+ *
+ * There are the global values:
+ *
+ * config home -- defaults to directory for configuration file.
+ * may be set by command.
+ *
+ * config cd -- defaults to cwd at start up
+ *
+ * There are the local values, within a given CLI instance (ie VTY):
+ *
+ * cli home -- set to config home when CLI instance starts, or when
+ * config home is set within the CLI.
+ *
+ * cli cd -- similarly
+ *
+ * cli here -- outside < is same as cli home, unless explicitly set
+ * - set by cli here
+ * - pushed each time executes <, and set to directory for
+ * the < filename.
+ * - pushed each time executes <| and left unchanged
+ * - popped each time exits < or <|
+ * - set to parent by "no cli here" inside <, or to
+ * default state outside <
+ *
+ * And then the filename syntax:
+ *
+ * /path -- absolute path -- in the usual way
+ *
+ * path -- path wrt "cli cd" -- in the usual way
+ *
+ * ~/path -- path in "cli home" -- so "config" stuff
+ *
+ * ~./path -- path in "here" -- so wrt to enclosing < file
+ *
+ *==============================================================================
+ * The Input Pipe Commands
+ *
+ * These are "universal commands".
+ *
+ * They are:
+ *
+ * < filename -- filename as above
+ *
+ * treat contents of given file as command lines.
+ * (That may include further < commands.)
+ *
+ * See notes on cli here for pushing/popping the here
+ * directory.
+ *
+ * TODO: Filename and quotes ??
+ *
+ * <| shell_command -- the shell command is executed "as is" by system().
+ *
+ * the stdout and stderr are collected.
+ *
+ * treats stdout as command lines.
+ * (That may include further < commands.)
+ *
+ * anything from stderr is sent to the VTY output.
+ *
+ * As far as the top level CLI is concerned, these are discrete commands.
+ * That is to say:
+ *
+ * -- except where blocked while reading the "pipe", all commands are
+ * executed one after another, in one Routing Engine operation.
+ *
+ * -- in any event, all output is gathered in the VTY buffering, and will
+ * be sent to the console (or where ever) only when the outermost command
+ * completes.
+ *
+ * There are three options associated with the output from a < operation:
+ *
+ * -- suppress command line echo
+ *
+ * whether to suppress echo of commands to the VTY before they are
+ * dispatched.
+ *
+ * The default is not to suppress command line echo.
+ *
+ * -- suppress command results
+ *
+ * whether to suppress any output generated by each command.
+ *
+ * The default is not to suppress command results.
+ *
+ * -- suppress "more"
+ *
+ * whether to do "--more--", if currently applies, when finally
+ * outputting all the command results.
+ *
+ * The default is not to suppress "more".
+ *
+ * This option can only be set for the outermost < operation.
+ *
+ * Remembering that all output occurs in one go when the outermost < operation
+ * completes.
+ *
+ * The default is to show everything and implement "--more--", pretty much as
+ * if the commands had been typed in. Except that "--more--" applies to
+ * everything (including the command lines) together, rather than to the output
+ * of each command individually.
+ *
+ * These options may be changed by flags attached to the <, as follows:
+ *
+ * ! suppress command line echo
+ *
+ * ? suppress "--more--"
+ *
+ * * suppress command output
+ *
+ * TODO: cli xxx commands for echo and output suppression and notes ....
+ *
+ * TODO: Error handling....
+ *
+ * TODO: Closing the CLI....
+ *
+ * TODO: Time out and the CLI....
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+#if 0
+/*==============================================================================
+ *
+ */
+
+#include "misc.h"
+
+#include "command_local.h"
+
+#include "vty_io_pipe.h"
+#include "vty_io_file.h"
+#include "vty_io_basic.h"
+
+/*==============================================================================
+ * VTY File Output
+ *
+ * This is for input and output of configuration files and piped stuff.
+ *
+ * When reading the configuration (and piped stuff in the configuration) I/O
+ * is blocking... nothing else can run while this is going on. Otherwise,
+ * all I/O is non-blocking.
+ */
+
+
+
+/*==============================================================================
+ * Prototypes.
+ */
+
+/*------------------------------------------------------------------------------
+ *
+ *
+ */
+extern cmd_return_code_t
+uty_file_read_open(vty_io vio, qstring name, bool reflect)
+{
+ const char* name_str ;
+ int fd ;
+ vio_vf vf ;
+ vfd_io_type_t iot ;
+
+ name_str = qs_make_string(name) ;
+
+ iot = vfd_io_read | vfd_io_blocking ; /* TODO blocking */
+
+ /* Do the basic file open. */
+ fd = uty_fd_file_open(name_str, iot) ;
+
+ if (fd < 0)
+ {
+ uty_out(vio, "%% Could not open input file %s\n", name_str) ;
+
+ return CMD_WARNING ;
+ }
+
+ /* OK -- now push the new input onto the vin_stack. */
+ vf = uty_vf_new(vio, name_str, fd, vfd_file, iot) ;
+ uty_vin_push(vio, vf, VIN_FILE, NULL, NULL, 16 * 1024) ;
+
+ vf->parse_type = cmd_parse_strict ;
+ vf->reflect_enabled = reflect ;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ *
+ *
+ */
+extern cmd_return_code_t
+uty_file_write_open(vty_io vio, qstring name, bool append)
+{
+ const char* name_str ;
+ int fd ;
+ vio_vf vf ;
+ vfd_io_type_t iot ;
+
+ iot = vfd_io_write | vfd_io_blocking ; /* TODO blocking */
+
+ if (append)
+ iot |= vfd_io_append ;
+
+ name_str = qs_make_string(name) ;
+
+ /* Do the basic file open. */
+ fd = uty_fd_file_open(name_str, iot) ;
+
+ if (fd < 0)
+ {
+ uty_out(vio, "%% Could not open output file %s\n", name_str) ;
+
+ return CMD_WARNING ;
+ }
+
+ /* OK -- now push the new input onto the vin_stack. */
+ vf = uty_vf_new(vio, name_str, fd, vfd_file, iot) ;
+ uty_vout_push(vio, vf, VOUT_FILE, NULL, NULL, 16 * 1024) ;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*==============================================================================
+ * Command line fetch from a file or pipe.
+ *
+ * Returns: CMD_SUCCESS -- have another command line ready to go
+ * CMD_WAITING -- do not have a command line at the moment
+ * CMD_EOF -- ran into EOF
+ * CMD_IO_ERROR -- ran into an I/O error
+ */
+extern cmd_return_code_t
+uty_file_fetch_command_line(vio_vf vf, qstring* line)
+{
+ assert(vf->vin_state == vf_open) ;
+
+ if (vf->line_complete)
+ {
+ vio_fifo_set_hold_mark(vf->ibuf) ; /* advance hold */
+
+ vf->line_complete = false ;
+ vf->line_number += vf->line_step ;
+
+ qs_set_len_nn(vf->cl, 0) ;
+ vf->line_step = 0 ;
+ } ;
+
+ while (1)
+ {
+ char* s, * p, * q, * e ;
+ size_t have ;
+ ulen len ;
+
+ s = vio_fifo_get(vf->ibuf, &have) ;
+
+ /* If nothing in hand, try and get some more.
+ *
+ * Either exits or loops back to set s & have.
+ */
+ if (have == 0)
+ {
+ int get ;
+
+ get = vio_fifo_read_nb(vf->ibuf, vio_vfd_fd(vf->vfd), 100) ;
+
+ if (get > 0)
+ continue ; /* loop back */
+
+ if (get == 0)
+ return CMD_WAITING ; /* need to set read ready ! */
+
+ if (get == -1)
+ ; /* register error */
+
+ if (get == -2)
+ return (qs_len_nn(vf->cl) > 0) ? CMD_SUCCESS : CMD_EOF ;
+ } ;
+
+ /* Try to find a '\n' -- converting all other control chars to ' '
+ *
+ * When we find '\n' step back across any trailing ' ' (which includes
+ * any control chars before the '\n').
+ *
+ * This means that we cope with "\r\n" line terminators. But not anything
+ * more exotic.
+ */
+ p = s ;
+ e = s + have ; /* have != 0 */
+ q = NULL ;
+
+ while (p < e)
+ {
+ if (*p++ < 0x20)
+ {
+ if (*(p-1) != '\n')
+ {
+ *(p-1) = ' ' ; /* everything other than '\n' */
+ continue ;
+ } ;
+
+ ++vf->line_step ; /* got a '\n' */
+
+ q = p ; /* point just past '\n' */
+ do --q ; while ((q > s) && (*(q-1) == ' ')) ;
+ /* discard trailing "spaces" */
+ break ;
+ } ;
+ } ;
+
+ /* Step past what have just consumed -- we have a hold_mark, so
+ * stuff is still in the fifo.
+ */
+ vio_fifo_step(vf->ibuf, p - s) ;
+
+ /* If not found '\n', then we have a line fragment that needs to be
+ * appended to any previous line fragments.
+ *
+ * Loops back to try to get some more form the fifo.
+ */
+ if (q == NULL)
+ {
+ qs_append_str_n(vf->cl, s, p - s) ;
+ continue ;
+ } ;
+
+ /* If we have nothing so far, set alias to point at what we have in
+ * the fifo. Otherwise, append to what we have.
+ *
+ * End up with: s = start of entire line, so far.
+ * p = end of entire line so far.
+ */
+ len = q - s ; /* length to add */
+ if (qs_len_nn(vf->cl) == 0)
+ {
+ qs_set_alias_n(vf->cl, s, len) ;
+ p = q ;
+ }
+ else
+ {
+ if (len != 0)
+ qs_append_str_n(vf->cl, s, len) ;
+
+ s = qs_char_nn(vf->cl) ;
+ p = s + qs_len_nn(vf->cl) ;
+
+ if ((len == 0) && (p > s) && (*(p-1) == ' '))
+ {
+ /* Have an empty end of line section, and the last character
+ * of what we have so far is ' ', so need now to trim trailing
+ * spaces off the stored stuff.
+ */
+ do --p ; while ((p > s) && (*(p-1) == ' ')) ;
+
+ qs_set_len_nn(vf->cl, p - s) ;
+ } ;
+ } ;
+
+ /* Now worry about we have a trailing '\'. */
+
+ if ((p == s) || (*(p-1) != '\\'))
+ break ; /* no \ => no continuation => success */
+
+ /* Have a trailing '\'.
+ *
+ * If there are an odd number of '\', strip the last one and loop
+ * round to collect the continuation.
+ *
+ * If there are an even number of '\', then this is not a continuation.
+ *
+ * Note that this rule deals with the case of the continuation line
+ * being empty... e.g. ....\\\ n n -- where n is '\n'
+ */
+ q = p ;
+ do --q ; while ((q > s) && (*(q-1) == '\\')) ;
+
+ if (((p - q) & 1) == 0)
+ break ; /* even => no continuation => success */
+
+ qs_set_len_nn(vf->cl, p - s - 1) ; /* strip odd '\' */
+
+ continue ; /* loop back to fetch more */
+ } ;
+
+ /* Success have a line in hand */
+
+ vf->line_complete = true ;
+ *line = vf->cl ;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command output push to a file or pipe.
+ *
+ * Returns: CMD_SUCCESS -- done
+ * CMD_IO_ERROR -- ran into an I/O error
+ */
+extern cmd_return_code_t
+uty_file_out_push(vio_vf vf)
+{
+ assert(vf->vout_state == vf_open) ;
+
+ if (vio_fifo_write_nb(vf->obuf, vio_vfd_fd(vf->vfd), false) >= 0)
+ return CMD_SUCCESS ;
+ else
+ return CMD_IO_ERROR ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Tidy up after input file has been closed
+ */
+extern void
+uty_file_read_close(vio_vf vf)
+{
+ return ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Flush output buffer and close.
+ *
+ * Returns: true <=> buffer (now) empty
+ */
+extern bool
+uty_file_write_close(vio_vf vf, bool final)
+{
+ return vio_fifo_write_nb(vf->obuf, vio_vfd_fd(vf->vfd), true) == 0 ;
+} ;
+#endif