diff options
Diffstat (limited to 'lib/vty_pipe.c')
-rw-r--r-- | lib/vty_pipe.c | 496 |
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 |