summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Hall <chris.hall@highwayman.com>2011-09-06 23:59:17 +0100
committerChris Hall <chris.hall@highwayman.com>2011-09-06 23:59:17 +0100
commit73a45fd38a9bc7279eb67021b07092a00768b559 (patch)
treec77bdc05adf7979a1cb73d21974251d8bbf6a758
parentbfca45143084f850dcfac2b14a090a6f008c8c96 (diff)
parent44b5aa5ca8b8a1620478c794dae11a7d71e9211e (diff)
downloadquagga-ex19b.tar.bz2
quagga-ex19b.tar.xz
Merge branch 'pipework' of /git/quagga.euro-ix into euro_ix_bex19b
Updated version to v0.99.18ex19b.
-rwxr-xr-xconfigure.ac2
-rw-r--r--lib/command.c7
-rw-r--r--lib/command_common.h2
-rw-r--r--lib/command_execute.c41
-rw-r--r--lib/command_execute.h3
-rw-r--r--lib/command_parse.c12
-rw-r--r--lib/command_parse.h27
-rw-r--r--lib/command_queue.c353
-rw-r--r--lib/vty_cli.c777
-rw-r--r--lib/vty_cli.h84
-rw-r--r--lib/vty_command.c102
-rw-r--r--lib/vty_io_term.c267
-rw-r--r--lib/vty_io_term.h6
13 files changed, 905 insertions, 778 deletions
diff --git a/configure.ac b/configure.ac
index 24c8950f..8b343086 100755
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@
## $Id$
AC_PREREQ(2.53)
-AC_INIT(Quagga, 0.99.18ex18b, [http://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.18ex19b, [http://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
diff --git a/lib/command.c b/lib/command.c
index ee855360..359ab0f1 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -994,9 +994,10 @@ DEFUN_CALL (show_version,
{
VTY_LOCK() ;
- uty_out (vty->vio, "Quagga %s (%s).\n", QUAGGA_VERSION,
- (host.name != NULL) ? host.name : "") ;
- uty_out (vty->vio, "%s\n", QUAGGA_COPYRIGHT);
+ uty_out (vty->vio, QUAGGA_PROGNAME " %s (%s%s).\n", QUAGGA_VERSION,
+ (host.name != NULL) ? host.name : "",
+ vty_multi_nexus ? " pthreaded" : "") ;
+ uty_out (vty->vio, "%s\n", QUAGGA_COPYRIGHT) ;
VTY_UNLOCK() ;
diff --git a/lib/command_common.h b/lib/command_common.h
index 4dd26753..501ebc3d 100644
--- a/lib/command_common.h
+++ b/lib/command_common.h
@@ -124,8 +124,6 @@ enum cmd_return_code
/* Return codes from the command parser */
- CMD_EMPTY, /* parser: nothing to execute */
-
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 */
diff --git a/lib/command_execute.c b/lib/command_execute.c
index cf04bb31..bd6b6249 100644
--- a/lib/command_execute.c
+++ b/lib/command_execute.c
@@ -313,7 +313,7 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
{
/* Deal with anything which is not success !
*/
- if ((ret != CMD_SUCCESS) && (ret != CMD_EMPTY))
+ if (ret != CMD_SUCCESS)
{
/* Will drop straight out of the loop if have anything other
* than CMD_HIATUS, CMD_EOF or CMD_CLOSE, which are all signals
@@ -335,22 +335,25 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
break ;
} ;
- /* If all is well, need another command line */
-
+ /* All is well, need another command line
+ */
ret = vty_cmd_fetch_line(vty) ; /* sets exec->action */
if (ret != CMD_SUCCESS)
continue ;
- /* Parse the command line we now have */
- assert(exec->action->to_do == cmd_do_command) ;
+ /* Parse the command line we now have -- loop if failed or there is
+ * nothing to execute.
+ */
+ qassert(exec->action->to_do == cmd_do_command) ;
cmd_tokenize(parsed, exec->action->line, exec->context->full_lex) ;
ret = cmd_parse_command(parsed, exec->context) ;
- if (ret != CMD_SUCCESS)
+ if ( (ret != CMD_SUCCESS) || ((parsed->parts & cmd_parts_execute) == 0) )
continue ;
- /* Special handling before first active line. */
+ /* Special handling before first active line.
+ */
if (first_cmd != NULL)
{
if (first_cmd != parsed->cmd)
@@ -362,7 +365,8 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
first_cmd = NULL ;
} ;
- /* reflection now..... */
+ /* reflection now.....
+ */
if (exec->reflect)
{
ret = vty_cmd_reflect_line(vty) ;
@@ -370,19 +374,23 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
continue ;
} ;
- /* Pipe work, if any */
+ /* Pipe work, if any
+ */
if ((parsed->parts & cmd_parts_pipe) != 0)
{
ret = cmd_open_pipes(vty) ;
- if (ret != CMD_SUCCESS)
+ if ((ret != CMD_SUCCESS) || ((parsed->parts & cmd_part_command) == 0))
continue ;
} ;
- /* Command execution, if any */
- if ((parsed->parts & cmd_part_command) != 0)
- ret = cmd_execute(vty) ;
+ /* Command execution
+ */
+ qassert((parsed->parts & cmd_part_command) != 0) ;
+
+ ret = cmd_execute(vty) ;
- /* Deal with success (or suppressed warning). */
+ /* Deal with success (or suppressed warning).
+ */
if ((ret == CMD_SUCCESS) || ((ret == CMD_WARNING) && ignore_warning))
ret = vty_cmd_success(vty) ;
} ;
@@ -398,8 +406,8 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
* Deal with any errors -- generate suitable error messages and close back
* to (but excluding) vout_base.
*
- * CMD_SUCCESS and CMD_EMPTY are impossible at this point -- they should
- * have been dealt with in the loop.
+ * CMD_SUCCESS is impossible at this point -- they should have been dealt
+ * with in the loop.
*
* CMD_EOF is also impossible -- vty_cmd_fetch_line() or vty_cmd_hiatus()
* can return that, but that will have been dealt with.
@@ -410,7 +418,6 @@ cmd_read_config(struct vty *vty, cmd_command first_cmd, bool ignore_warning)
* CMD_WAITING is not valid for blocking vio !
*/
qassert(ret != CMD_SUCCESS) ;
- qassert(ret != CMD_EMPTY) ;
qassert(ret != CMD_EOF) ;
qassert(ret != CMD_CLOSE) ;
qassert(ret != CMD_WAITING) ;
diff --git a/lib/command_execute.h b/lib/command_execute.h
index 97033b6e..df86154c 100644
--- a/lib/command_execute.h
+++ b/lib/command_execute.h
@@ -44,7 +44,8 @@ enum cmd_exec_state
exec_open_pipes, /* open pipes on command line */
exec_execute, /* execute standard command */
exec_special, /* execute special command */
- exec_done_cmd, /* command has completed */
+ exec_cmd_done, /* command completed somehow */
+ exec_cmd_success, /* command completed successfully */
exec_hiatus, /* while issues are dealt with */
exec_stopped, /* command loop has stopped */
} ;
diff --git a/lib/command_parse.c b/lib/command_parse.c
index 9204db70..54185428 100644
--- a/lib/command_parse.c
+++ b/lib/command_parse.c
@@ -3247,10 +3247,9 @@ static node_type_t cmd_auth_specials(cmd_context context, node_type_t target) ;
*
* - parsed->parts is what was found
*
- * - parsed->cmd->daemon => daemon
+ * NB: may be empty or comment only !
*
- * CMD_EMPTY => line is empty, except perhaps for comment
- * (iff parsing for execution)
+ * - parsed->cmd->daemon => daemon
*
* CMD_ERR_INCOMPLETE => "do" and nothing more
* (iff parsing for execution)
@@ -3317,13 +3316,10 @@ cmd_parse_command(cmd_parsed parsed, cmd_context context)
*/
if (((parsed->parts & cmd_part_command) == 0) && context->parse_execution)
{
- if ((parsed->parts & ~cmd_part_comment) == cmd_parts_none)
- return CMD_EMPTY ; /* accept empty */
-
if ((parsed->parts & cmd_part_do) != 0)
- return CMD_ERR_INCOMPLETE ; /* reject "do" alone */
+ return CMD_ERR_INCOMPLETE ; /* reject "do" alone */
- return CMD_SUCCESS ; /* accept pipes */
+ return CMD_SUCCESS ; /* accept pipes and empty */
} ;
/* Level 2 parsing
diff --git a/lib/command_parse.h b/lib/command_parse.h
index ab93f061..42fac7c0 100644
--- a/lib/command_parse.h
+++ b/lib/command_parse.h
@@ -476,15 +476,18 @@ enum cmd_pipe_type /* bit significant */
cmd_pipe_file = BIT(0),
cmd_pipe_shell = BIT(1),
- cmd_pipe_dev_null = BIT(2), /* out pipe only -- black hole */
+ cmd_pipe_dev_null = BIT(2), /* out pipe only -- black hole */
- /* For in pipes */
- cmd_pipe_reflect = BIT(4), /* + option */
+ /* For in pipes
+ */
+ cmd_pipe_reflect = BIT(4), /* + option */
- /* For out file pipes */
+ /* For out file pipes
+ */
cmd_pipe_append = BIT(4), /* >> */
- /* For out shell pipes */
+ /* For out shell pipes
+ */
cmd_pipe_shell_cmd = BIT(4), /* | at start of line */
} ;
typedef enum cmd_pipe_type cmd_pipe_type_t ;
@@ -494,15 +497,17 @@ enum cmd_parts /* bit significant */
{
cmd_parts_none = 0,
- cmd_part_do = BIT(0),
- cmd_part_command = BIT(1),
+ cmd_part_do = BIT(0), /* command has leading "do" */
+ cmd_part_command = BIT(1), /* command part exists */
+
+ cmd_part_in_pipe = BIT(2), /* in pipe part exists */
+ cmd_part_out_pipe = BIT(3), /* out pipe part exists */
- cmd_part_in_pipe = BIT(2),
- cmd_part_out_pipe = BIT(3),
+ cmd_parts_pipe = cmd_part_in_pipe | cmd_part_out_pipe,
- cmd_parts_pipe = (cmd_part_in_pipe | cmd_part_out_pipe),
+ cmd_parts_execute = cmd_part_command | cmd_parts_pipe,
- cmd_part_comment = BIT(4),
+ cmd_part_comment = BIT(4), /* commend part exists */
} ;
typedef enum cmd_parts cmd_parts_t ;
diff --git a/lib/command_queue.c b/lib/command_queue.c
index b80b2c9f..5c2f7c8c 100644
--- a/lib/command_queue.c
+++ b/lib/command_queue.c
@@ -118,8 +118,8 @@ static void cq_process(vty vty, cmd_exec_state_t state, cmd_return_code_t ret) ;
*
* Expects the vty start up process to have output some cheerful messages,
* which is treated as a dummy "login" command. So the loop is entered at
- * "exec_done_cmd", which will push out the output, deal with the return code,
- * and loop round to fetch the first command line (if required).
+ * "exec_cmd_done", which will deal with the return code, push any output, and
+ * loop round to fetch the first command line (if required).
*/
extern void
cq_loop_enter(vty vty, cmd_return_code_t ret)
@@ -128,7 +128,7 @@ cq_loop_enter(vty vty, cmd_return_code_t ret)
qassert(vty->exec->state == exec_null) ;
- cq_enqueue(vty, vty_cli_nexus, exec_done_cmd, ret) ;
+ cq_enqueue(vty, vty_cli_nexus, exec_cmd_done, ret) ;
} ;
/*------------------------------------------------------------------------------
@@ -292,152 +292,210 @@ cq_process(vty vty, cmd_exec_state_t state, cmd_return_code_t ret)
*/
while (1)
{
- switch(state)
- {
- /*--------------------------------------------------------------------
- * Should not get here in exec_null state.
- */
- case exec_null:
- zabort("exec state == exec_null") ;
- break ;
+ switch(state)
+ {
+ /*--------------------------------------------------------------------
+ * Should not get here in exec_null state.
+ */
+ case exec_null:
+ zabort("exec state == exec_null") ;
+ return ;
+
+ /*--------------------------------------------------------------------
+ * Hiatus state -- some return code to be dealt with !
+ *
+ * NB: we only reach here after breaking out of the switch, or
+ * on cq_continue().
+ */
+ case exec_hiatus:
+ while (1)
+ {
+ /* Let vty_cmd_hiatus() deal with the return code and/or any
+ * stop/error/etc trap, and adjust the stack as required.
+ */
+ ret = vty_cmd_hiatus(vty, ret) ;
- /*--------------------------------------------------------------------
- * Need another command to execute => in_pipe !
- *
- * If multi-threaded: may be in either thread. If vty_cmd_fetch_line()
- * cannot, for any reason, return a command line, will return something
- * other than CMD_SUCCESS -- which enters the exec_hiatus.
- */
- case exec_fetch:
- ret = vty_cmd_fetch_line(vty) ;
+ if (ret == CMD_SUCCESS)
+ break ; /* back to exec_fetch */
- if (ret != CMD_SUCCESS)
- break ;
+ if (ret == CMD_WAITING)
+ return ; /* <<< DONE, pro tem */
- if (exec->action->to_do != cmd_do_command)
- {
- state = exec_special ;
- continue ;
- } ;
+ if (ret == CMD_IO_ERROR)
+ continue ; /* give error back to hiatus */
- fall_through ; /* with ret == CMD_SUCCESS */
+ if (ret == CMD_STOP)
+ {
+ exec->state = exec_stopped ;
+ vty_cmd_loop_exit(vty) ;
- /*--------------------------------------------------------------------
- * Parse command in hand
- *
- * If multi-threaded: may be in either thread.
- */
- cmd_tokenize(parsed, exec->action->line, exec->context->full_lex) ;
+ return ; /* <<< DONE, permanently */
+ } ;
- ret = cmd_parse_command(parsed, exec->context) ;
- if (ret != CMD_SUCCESS)
- {
- if (ret != CMD_EMPTY)
- break ; /* stop on *any* parsing issue */
-
- /* Empty lines from in_pipes we simply ignore.
- *
- * Don't expect to see them otherwise, but if we do then need
- * to complete the command execution process.
- */
- ret = CMD_SUCCESS ;
-
- state = exec_done_cmd ;
- continue ;
- } ;
+ zabort("invalid return from vty_cmd_hiatus()") ;
+ } ;
- /* reflection now */
- if (exec->reflect)
- {
- ret = vty_cmd_reflect_line(vty) ;
+ fall_through ;
- if ((ret != CMD_SUCCESS) && (ret != CMD_WAITING))
- break ; /* CMD_IO_ERROR or CMD_HIATUS */
- } ;
+ /*--------------------------------------------------------------------
+ * Need another command to execute => in_pipe !
+ *
+ * If multi-threaded: may be in either thread. TODO !! If vty_cmd_fetch_line()
+ * cannot, for any reason, return a command line, will return something
+ * other than CMD_SUCCESS -- which enters the exec_hiatus.
+ */
+ case exec_fetch:
+ ret = vty_cmd_fetch_line(vty) ;
- fall_through ;
+ if (ret != CMD_SUCCESS)
+ break ;
- /*--------------------------------------------------------------------
- * Pipe work if any
- *
- * Will receive CMD_EOF if the VTY has been closed.
- *
- * If multi-threaded: must be in vty_cli_nexus to proceed -- so may
- * generate message to transfer to vty_cli_nexus.
- */
- case exec_open_pipes:
- if ((parsed->parts & cmd_parts_pipe) != 0)
- {
- /* If running pthreaded, do open pipes in vty_cli_nexus */
- if (exec->locus != vty_cli_nexus)
- return cq_enqueue(vty, vty_cli_nexus, exec_open_pipes, ret) ;
-
- /* Now in vty_cli_nexus */
- ret = cmd_open_pipes(vty) ;
- if (ret != CMD_SUCCESS)
- break ; /* quit if open fails */
- } ;
+ if (exec->action->to_do != cmd_do_command)
+ {
+ state = exec_special ;
+ continue ;
+ } ;
- fall_through ; /* with ret == CMD_SUCCESS */
+ /* Parse command in hand
+ *
+ * If multi-threaded: may be in either thread.
+ */
+ cmd_tokenize(parsed, exec->action->line, exec->context->full_lex) ;
- /*--------------------------------------------------------------------
- * Execute command in hand (if any)
- *
- * If multi-threaded: some commands can run in either thread, most must
- * run in the vty_cmd_nexus -- so may generate message to transfer to
- * the vty_cmd_nexus.
- */
- case exec_execute:
- if ((parsed->parts & cmd_part_command) != 0)
- {
- /* If running pthreaded, do most commands in vty_cmd_nexus */
- if ((exec->locus != vty_cmd_nexus) && (!cmd_is_direct(parsed)))
- return cq_enqueue(vty, vty_cmd_nexus, exec_execute, ret) ;
+ ret = cmd_parse_command(parsed, exec->context) ;
+ if (ret != CMD_SUCCESS)
+ break ; /* on *any* parsing issue */
- /* Standard command handling */
-#ifdef CONSUMED_TIME_CHECK
+ if ((parsed->parts & cmd_parts_execute) == 0)
+ {
+ /* Empty lines from in_pipes appear here.
+ *
+ * Don't expect to see them otherwise, but in any case need to
+ * complete the command execution process.
+ */
+ state = exec_cmd_success ;
+ continue ;
+ } ;
+
+ /* reflect if required
+ */
+ if (exec->reflect)
+ {
+ ret = vty_cmd_reflect_line(vty) ;
+
+ if ((ret != CMD_SUCCESS) && (ret != CMD_WAITING))
+ break ; /* CMD_IO_ERROR or CMD_HIATUS */
+ } ;
+
+ /*--------------------------------------------------------------------
+ * Pipe work if any
+ *
+ * Will receive CMD_EOF if the VTY has been closed.
+ *
+ * If multi-threaded: must be in vty_cli_nexus to proceed -- so may
+ * generate message to transfer to vty_cli_nexus.
+ */
+ case exec_open_pipes:
+ if ((parsed->parts & cmd_parts_pipe) != 0)
+ {
+ /* If running pthreaded, do open pipes in vty_cli_nexus
+ */
+ if (exec->locus != vty_cli_nexus)
+ return cq_enqueue(vty, vty_cli_nexus, exec_open_pipes, ret) ;
+
+ /* Now in vty_cli_nexus
+ */
+ ret = cmd_open_pipes(vty) ;
+ if (ret != CMD_SUCCESS)
+ break ; /* quit if open fails */
+
+ /* Finish if this is pipe only
+ */
+ if ((parsed->parts & cmd_part_command) == 0)
+ {
+ state = exec_cmd_success ;
+ continue ;
+ } ;
+ } ;
+
+ fall_through ;
+
+ /*--------------------------------------------------------------------
+ * If multi-threaded: most commands run in the vty_cmd_nexus, some
+ * run in the vty_cli_nexus -- transfer to the required nexus, as
+ * required.
+ */
+ qassert((parsed->parts & cmd_part_command) != 0);
+
+ if (cmd_is_direct(parsed))
+ {
+ if (exec->locus != vty_cli_nexus)
+ return cq_enqueue(vty, vty_cli_nexus, exec_execute, ret) ;
+ }
+ else
{
- RUSAGE_T before;
- RUSAGE_T after;
- unsigned long realtime, cputime;
+ if (exec->locus != vty_cmd_nexus)
+ return cq_enqueue(vty, vty_cmd_nexus, exec_execute, ret) ;
+ }
- GETRUSAGE(&before);
+ fall_through ;
+
+ /*--------------------------------------------------------------------
+ * Execute command -- now that is in the required nexus.
+ */
+ case exec_execute:
+#ifdef CONSUMED_TIME_CHECK
+ {
+ RUSAGE_T before;
+ RUSAGE_T after;
+ unsigned long realtime, cputime;
+
+ if (!cmd_is_direct(parsed))
+ GETRUSAGE(&before);
#endif /* CONSUMED_TIME_CHECK */
- ret = cmd_execute(vty) ;
+ ret = cmd_execute(vty) ;
#ifdef CONSUMED_TIME_CHECK
+ if (!cmd_is_direct(parsed))
+ {
GETRUSAGE(&after);
realtime = thread_consumed_time(&after, &before, &cputime) ;
if (realtime > CONSUMED_TIME_CHECK)
/* Warn about CPU hog that must be fixed. */
zlog(NULL, LOG_WARNING,
- "SLOW COMMAND: command took %lums (cpu time %lums): %s",
+ "SLOW COMMAND: command took %lums (cpu time %lums): %s",
realtime/1000, cputime/1000,
qs_make_string(exec->action->line)) ;
- } ;
-#endif /* CONSUMED_TIME_CHECK */
+ } ;
} ;
+#endif /* CONSUMED_TIME_CHECK */
+
+ /*--------------------------------------------------------------------
+ * Command has completed somehow -- this is the loop entry point.
+ */
+ case exec_cmd_done:
+ if (ret != CMD_SUCCESS)
+ break ;
fall_through ;
/*--------------------------------------------------------------------
- * Command has completed -- if successful, push output and loop back
+ * Command has completed successfully, push output and loop back
* to fetch another command.
*
- * Break if not successful, or push fails or must wait.
- *
* If multi-threaded: may be in either thread:
*
* vty_cmd_success() may set write ready -- so in vty_cmd_nexus may
* generate message to vty_cli_nexus.
*/
- case exec_done_cmd:
- if (ret == CMD_SUCCESS)
- ret = vty_cmd_success(vty) ;
+ case exec_cmd_success:
+ qassert(ret == CMD_SUCCESS) ;
+
+ ret = vty_cmd_success(vty) ;
if ((ret != CMD_SUCCESS) && (ret != CMD_WAITING))
- break ; /* stop */
+ break ;
state = exec_fetch ;
continue ;
@@ -450,77 +508,44 @@ cq_process(vty vty, cmd_exec_state_t state, cmd_return_code_t ret)
return cq_enqueue(vty, vty_cli_nexus, exec_special, ret) ;
ret = vty_cmd_special(vty) ;
- if (ret != CMD_SUCCESS)
- break ;
- state = exec_done_cmd ;
+ state = exec_cmd_done ;
continue ;
/*--------------------------------------------------------------------
- * Hiatus state -- some return code to be dealt with !
- *
- * If we are not in the vty_cli_nexus, then must pass the problem
- * to the vty_cli_nexus. If the return code is CMD_STOP, or there
- * is a CMD_STOP signal, then drop the config symbol of power -- see
- * uty_close().
- */
- case exec_hiatus:
- if (exec->locus != vty_cli_nexus)
- {
- vty_cmd_check_stop(vty, ret) ;
- return cq_enqueue(vty, vty_cli_nexus, exec_hiatus, ret) ;
- } ;
-
- while (1)
- {
- /* Let vty_cmd_hiatus() deal with the return code and/or any
- * stop/error/etc trap, and adjust the stack as required.
- */
- ret = vty_cmd_hiatus(vty, ret) ;
-
- if (ret == CMD_SUCCESS)
- break ; /* back to exec_fetch */
-
- if (ret == CMD_WAITING)
- {
- exec->state = exec_hiatus ;
- return ; /* <<< DONE, pro tem */
- } ;
-
- if (ret == CMD_IO_ERROR)
- continue ; /* give error back to hiatus */
-
- if (ret == CMD_STOP)
- {
- exec->state = exec_stopped ;
- vty_cmd_loop_exit(vty) ;
-
- return ; /* <<< DONE, permanently */
- } ;
-
- zabort("invalid return from vty_cmd_hiatus()") ;
- } ;
-
- state = exec_fetch ;
- continue ; /* can fetch, again */
-
- /*--------------------------------------------------------------------
* Should not get here in exec_stopped state.
*/
case exec_stopped:
zabort("exec state == exec_exit") ;
- break ;
+ return ;
/*----------------------------------------------------------------------
* Unknown exec->state !
*/
default:
zabort("unknown exec->state") ;
- break ;
+ return ;
} ;
- /* Have broken out of the switch() => exec_hiatus */
- state = exec_hiatus ;
+ /* Have broken out of the switch() => exec_hiatus
+ *
+ * Something has returned a return code that causes entry to the hiatus
+ * state to sort out.
+ *
+ * If we are not in the vty_cli_nexus, then must pass the problem
+ * to the vty_cli_nexus. If the return code is CMD_STOP, or there
+ * is a CMD_STOP signal, then drop the config symbol of power
+ * immediately -- see uty_close().
+ */
+ if (exec->locus != vty_cli_nexus)
+ {
+ vty_cmd_check_stop(vty, ret) ;
+ return cq_enqueue(vty, vty_cli_nexus, exec_hiatus, ret) ;
+ } ;
+
+ state = vty->exec->state = exec_hiatus ;
+
+ continue ;
} ;
} ;
diff --git a/lib/vty_cli.c b/lib/vty_cli.c
index a4ab8de3..d06e455e 100644
--- a/lib/vty_cli.c
+++ b/lib/vty_cli.c
@@ -60,8 +60,6 @@ static const char* telnet_newline = TELNET_NEWLINE ;
static bool uty_cli_callback(keystroke_callback_args) ;
static void uty_cli_update_more(vty_cli cli) ;
-static void uty_cli_cancel(vty_cli cli) ;
-
/*------------------------------------------------------------------------------
* Construct and initialise a new CLI object -- never embedded.
*
@@ -102,27 +100,16 @@ uty_cli_new(vio_vf vf)
* key_stream = X -- set below
*
* drawn = false
- *
- * tilde_prompt = false -- tilde prompt is not drawn
- * tilde_enabled = false -- set below if ! multi-threaded
+ * more_drawn = false
*
* prompt_len = 0 -- not drawn, in any case
- * extra_len = 0 -- not drawn, in any case
*
* prompt_node = NULL_NODE -- so not set !
* prompt_gen = 0 -- not a generation number
* prompt_for_node = NULL -- not set, yet
*
- * dispatched = false -- see below
- * in_progress = false -- see below
- * blocked = false -- see below
- * paused = false
- *
- * mon_active = false
- * out_active = false
- *
- * more_wait = false
- * more_enter = false
+ * state = X -- set below
+ * out_state = cos_idle
*
* more_enabled = false -- not in "--More--" state
*
@@ -142,6 +129,7 @@ uty_cli_new(vio_vf vf)
*
* olc = NULL -- see below
*/
+ confirm(cos_idle == 0) ;
confirm(NULL_NODE == 0) ; /* prompt_node & node */
confirm(cmd_do_nothing == 0) ; /* to_do */
confirm(CMD_ACTION_ALL_ZEROS) ; /* dispatch */
@@ -170,28 +158,18 @@ uty_cli_new(vio_vf vf)
uty_cli_set_lines(cli, host.lines, false) ;
uty_cli_update_more(cli) ; /* and update the olc etc to suit. */
- /* Enable "~ " prompt and pause timer if multi-threaded
- *
- * TODO decide whether to ditch the '~' prompt, given the priority given
- * to commands.
+ /* Enable pause timer if multi-threaded
*/
if (vty_nexus)
- {
- cli->pause_timer = qtimer_init_new(NULL, vty_cli_nexus->pile,
- vty_term_pause_timeout, cli) ;
-#if 0
- cli->tilde_enabled = vty_multi_nexus ;
-#endif
- } ;
+ cli->pause_timer = qtimer_init_new(NULL, vty_cli_nexus->pile,
+ vty_term_pause_timeout, cli) ;
- /* Ready to be started -- paused, out_active & more_wait are false.
+ /* Ready to be started -- note that out_state is cos_idle.
*
* Is started by the first call of uty_cli_want_command(), which (inter alia)
* set the cli->context so CLI knows how to prompt etc.
*/
- cli->dispatched = true ;
- cli->in_progress = true ;
- cli->blocked = true ;
+ cli->state = cst_in_progress ; /* start up "command" is running */
return cli ;
} ;
@@ -227,17 +205,24 @@ uty_cli_close(vty_cli cli, bool final)
/* Bring as much of the command handling to a stop as possible, and
* turn off "---more--" etc. so that output can proceed.
+ *
+ * If it is drawn, we wipe the command line (issuing ^C). We can, then,
+ * enable output -- which turns off any "--more--" stuff, but keep any
+ * existing pending monitor output (though forget any pause).
+ *
+ * We set the CLI stopped, so that nothing further will happen, including
+ * when any in_progress command completes.
*/
cli->more_enabled = false ;
cli->lines = 0 ; /* so will not be re-enabled */
- uty_cli_cancel(cli) ; /* " ^C\r\n" unless believed blank */
+ uty_cli_cancel(cli, true) ; /* " ^C\r\n" unless believed blank */
- cli->more_wait = false ; /* exit more_wait (if was in it) */
- cli->more_enter = false ; /* and so cannot be this */
-
- cli->blocked = true ; /* do not renter the CLI */
- cli->out_active = true ; /* if there is any output, it can go */
+ if (cli->state == cst_dispatched)
+ {
+ cmd_action_clear(cli->dispatch) ;
+ cli->state = cst_active ; /* never happened */
+ } ;
/* Ream out the history. */
{
@@ -247,32 +232,33 @@ uty_cli_close(vty_cli cli, bool final)
cli->hist = NULL ;
} ;
- /* Empty the keystroke handling. */
+ /* Empty the keystroke handling.
+ */
cli->key_stream = keystroke_stream_free(cli->key_stream) ;
- /* Can discard active command line if not dispatched */
- if (!cli->dispatched || final)
- cli->clx = qs_reset(cli->clx, free_it) ;
-
- /* Can discard context and parsed objects */
- cli->context = cmd_context_free(cli->context, true) ; /* its a copy */
+ /* Can discard parsed objects
+ */
cli->parsed = cmd_parsed_free(cli->parsed) ;
- /* Discard any pause_timer, and suppress */
+ /* Discard any pause_timer
+ */
cli->pause_timer = qtimer_free(cli->pause_timer) ;
- cli->paused = false ;
- cli->tilde_enabled = false ;
- /* If final, free the CLI object. */
+ /* If final, free the CLI object and stuff that has been kept while
+ * the output side closes.
+ */
if (final)
{
cli->prompt_for_node = qs_free(cli->prompt_for_node) ;
cli->cl = qs_free(cli->cl) ;
+ cli->clx = qs_free(cli->clx) ;
cli->cls = qs_free(cli->cls) ;
cli->cbuf = vio_fifo_free(cli->cbuf) ;
cli->olc = vio_lc_free(cli->olc) ;
+ cli->context = cmd_context_free(cli->context, true) ; /* its a copy */
+
XFREE(MTYPE_VTY_CLI, cli) ; /* sets cli = NULL */
} ;
@@ -292,20 +278,60 @@ static bool
uty_cli_callback(keystroke_callback_args /* void* context, keystroke stroke */)
{
vty_cli cli = context ;
+ cli_out_state_t out_state ;
switch (stroke->type)
{
case ks_char: /* character -- uint32_t */
- if ((cli->in_progress || cli->out_active) && !cli->more_wait)
+ /* We pick up the ^C as a cancel iff:
+ *
+ * is already cos_cancel -- has no further effect
+ *
+ * is cst_dispatched -- cancels before even started
+ *
+ * is cst_in_progress or cst_complete, provided is not in either
+ * cos_more_enter or cos_more_wait -- which deal with ^C themselves.
+ */
+ out_state = cli->out_state & cos_mask ;
+
+ if (out_state == cos_cancel)
+ return true ; /* eat duplicates */
+
+ switch (cli->state)
{
- vty_io vio = cli->vf->vio ;
+ case cst_active:
+ qassert(out_state == cos_idle) ;
+ return false ;
+
+ case cst_dispatched:
+ /* Managing to cancel before even started to run !!
+ *
+ * Clear the dispatched command, and then promote to
+ * cst_in_progress -- the current line contains the prompt
+ * and command, which the cancel handling will append ^C to.
+ */
+ qassert(out_state == cos_idle) ;
+
+ cmd_action_clear(cli->dispatch) ;
+ cli->state = cst_in_progress ;
+
+ break ;
+
+ case cst_in_progress:
+ case cst_complete:
+ if ((out_state == cos_more_enter) || (out_state == cos_more_wait))
+ return false ;
- uty_cmd_signal(vio, CMD_CANCEL) ; /* ^C */
+ break ;
- return true ;
+ default:
+ return false ;
} ;
- return false ;
+ cli->out_state ^= (out_state ^ cos_cancel) ;
+ uty_cmd_signal(cli->vf->vio, CMD_CANCEL) ;
+
+ return true ;
case ks_iac: /* Telnet command */
return uty_telnet_command(cli->vf, stroke, true) ;
@@ -436,69 +462,84 @@ uty_cli_update_more(vty_cli cli)
*
* State of the CLI:
*
- * dispatched -- a command line has been dispatched, and is waiting for
- * (dsp) command loop to fetch it.
+ * cst_active -- is busy drawing prompt, fetching input, processing same,
+ * etc. -- preparing the next command.
+ *
+ * cst_dispatched -- a command line has been dispatched, and is waiting for
+ * command loop to fetch it.
+ *
+ * Note that command line is drawn, and cursor is at
+ * the end of the line.
+ *
+ * cst_in_progress -- a command has been taken by the command loop, and is
+ * still running -- or at least no further command has
+ * been fetched by the command loop.
+ *
+ * The command may be an in_pipe, so there may be many
+ * commands to be completed before the CLI level command
+ * is.
+ *
+ * cst_complete -- the last CLI level command has completed, and we are
+ * waiting for the output to go cos_idle before continuing
+ * to cst_active.
+ *
+ * State of the output:
*
- * in_progress -- a command has been taken by the command loop, and is still
- * (inp) running -- or at least no further command has been
- * fetched by the command loop.
+ * cos_idle -- all output (other than the CLI line) is idle.
*
- * The command may be an in_pipe, so there may be many
- * commands to be completed before the CLI level command is.
+ * cos_active -- the command output FIFO is being emptied.
*
- * or: the CLI has been closed.
+ * This is set when output is pushed, and cleared when
+ * everything is written away and is cst_complete.
*
- * blocked -- is in_progress and a further command is now ready to be
- * (bkd) dispatched.
+ * cos_cancel -- all command output is frozen until the command loop
+ * deals with the cancel action.
*
- * or: the CLI has been closed.
+ * cos_more_enter -- in the process of entering "--more--" state
*
- * out_active -- the command output FIFO is being emptied.
- * (oa)
- * This is set when output is pushed, and cleared when
- * everything is written away and in_progress is not set.
- * When it is set, any current command line is wiped.
+ * cos_more_wait -- in the "--more--" state
*
- * Note that what this flag does is prevent the CLI from
- * running until the output completes, and in particular
- * prevents it from writing anything to the CLI buffer.
+ * cos_monitor -- is busy outputting monitor stuff.
*
- * more_wait -- is in "--more--" wait state. => out_active !
- * (mwt)
- * The "--more--" CLI uses the CLI output buffer to draw
- * and undraw the "--more--" prompt. The buffer will
- * otherwise be empty because is out_active.
+ * This state "qualifier" may be applied to any of the
+ * above states.
*
- * more_enter -- is in the process of entering the "--more--" wait state,
- * (men) waiting to write the "--more--" prompt and prepare the
- * keystroke input.
+ * This is set when monitor output is ready, and when it
+ * is set any current command line is wiped.
*
- * The following are the valid combinations:
+ * cos_paused -- is pausing after monitor output, before continuing
+ * to output stuff, or redraw CLI line -- in case more
+ * monitor stuff rolls up.
*
- * dsp:inp:bkd: oa:mwt:men:
- * ---:---:---:---:---:---:-----------------------------------------
- * 0 : 0 : 0 : 0 : 0 : 0 : collecting a new command
- * 1 : 0 : 0 : 0 : 0 : 0 : waiting for command to be fetched
- * 1 : 1 : 0 : X : 0 : 0 : command fetched and running
- * 1 : 1 : 1 : X : 0 : 0 : waiting for command to complete
- * 0 : 0 : 0 : 1 : 0 : 0 : waiting for command output to finish
- * 1 : X : X : 1 : 1 : 1 : waiting for "--more--" to start
- * 1 : X : X : 1 : 1 : 0 : waiting for "--more--" response
- * 1 : 1 : 1 : 1 : 0 : 0 : waiting for command to complete,
- * after the CLI has been closed
+ * This state "qualifier" may be applied to any of the
+ * above states.
*
- * There are two output FIFOs:
+ * If running threaded, this is set and the associated
+ * timer is started, when monitor output completes.
+ *
+ * NB: cos_monitor and cos_paused are mutually exclusive.
+ *
+ * NB: cos_monitor and cos_paused take priority over
+ * other output state.
+ *
+ * There are three output FIFOs:
*
* 1. for the CLI itself -- uty_cli_out and friends
*
- * 2. for output generated by commands -- vty_out and friends.
+ * 2. for monitor output
+ *
+ * 3. for output generated by commands -- vty_out and friends.
+ *
+ * The CLI FIFO is emptied whenever possible, in preference to the other
+ * FIFOs.
+ *
+ * The monitor FIFO is emptied in preference to the command FIFO.
*
- * The CLI FIFO is emptied whenever possible, in preference to the command
- * FIFO. The command FIFO is emptied when out_active. While a command is
- * in_progress all its output is collected in the command output buffer,
- * to be written away when the command completes, or if it pushes the output
+ * The command FIFO is emptied when cos_active. While a command is in
+ * progress all its output is collected in the command output buffer, to be
+ * written away when the command completes, or if it pushes the output
* explicitly. Note that where the CLI level command is an in_pipe, the first
- * output will set out_active, and that will persist until returns to the CLI
+ * output will set cos_active, and that will persist until returns to the CLI
* level. Between commands in the pipe, the output will be pushed, so will
* output stuff more or less as it is generated.
*
@@ -527,7 +568,8 @@ uty_cli_update_more(vty_cli cli)
*
* The output process used the line_control structure to manage the output, and
* occasionally enter the trivial "--more--" CLI. This is invisible to the
- * main CLI. (See the more_wait and more_enter flags and their handling.)
+ * main CLI. (See the cos_more_wait and cos_more_enter states and their
+ * handling.)
*
* If the user decides to abandon output at the "--more--" prompt, then the
* then contents of the command output FIFO are discarded.
@@ -538,19 +580,10 @@ uty_cli_update_more(vty_cli cli)
* When running in qnexus mode, many commands are not executed directly in the
* CLI, but are queued for execution by the main "routeing" nexus.
*
- * The parsing of commands is context sensitive. The context depends may
- * change during the execution of a command. So... it is not possible to
- * dispatch a command until the previous one has completed.
- *
- * In qnexus mode, when a command is queued, the CLI does not go cli_blocked,
- * even if some output has already been generated. This allows a further
- * command to be entered while the previous one is executed. However, if the
- * command is dispatched before the previous one completes, then the cli will
- * block.
- *
- * While the previous command is executing, the current command line has a
- * minimal prompt -- to show that the context is not known. When the previous
- * command completes, the command line is redrawn in the new context.
+ * The parsing of commands is context sensitive, as is the prompt. The context
+ * depends may change during the execution of a command. So... it is not
+ * possible to read and dispatch a command until the previous one has
+ * completed.
*
*------------------------------------------------------------------------------
* Command line drawn state.
@@ -561,17 +594,11 @@ uty_cli_update_more(vty_cli cli)
*
* The command line can be "wiped" -- see uty_cli_wipe() -- which removes all
* output and prompt, and leaves the console at the start of an empty line
- * where the command line used to be.
- *
- * On entry to the CLI, it will draw the command line again if it has been
- * wiped.
- *
- * This mechanism is used to support the partial command line that may be
- * entered while a queued command executes.
- *
- * It is also used for the command help/completion system.
+ * where the command line used to be. On entry to the CLI, it will draw the
+ * command line again if it has been wiped.
*
- * It is also used to support the "monitor" output.
+ * This is used for the command help/completion system and for the "monitor"
+ * output.
*/
/*==============================================================================
@@ -583,7 +610,7 @@ uty_cli_update_more(vty_cli cli)
static enum vty_readiness uty_cli_standard(vty_cli cli) ;
static cmd_do_t uty_cli_auth(vty_cli cli) ;
static enum vty_readiness uty_cli_more_wait(vty_cli cli) ;
-static void uty_cli_draw(vty_cli cli) ;
+static void uty_cli_draw(vty_cli cli, bool more_prompt) ;
/*------------------------------------------------------------------------------
* CLI for VTY_TERMINAL
@@ -606,11 +633,34 @@ uty_cli(vty_cli cli)
if (cli->vf->vin_state == vf_closed)
return not_ready ; /* Nothing more from CLI if closed */
- /* Standard or "--more--" CLI ? */
- if (cli->more_wait)
- return uty_cli_more_wait(cli) ;
- else
- return uty_cli_standard(cli) ;
+ /* Standard or "--more--" CLI ?
+ *
+ * If cos_idle, then can run standard CLI if is cst_active or cst_complete.
+ *
+ * If cos_more_wait or cos_more_enter, then can run more_wait CLI.
+ *
+ * Note that cos_cancel, cos_monitor and cos_paused preclude entry to any
+ * CLI.
+ */
+ switch (cli->out_state)
+ {
+ case cos_idle:
+ if (cli->state == cst_complete)
+ cli->state = cst_active ;
+
+ if (cli->state == cst_active)
+ return uty_cli_standard(cli) ;
+ break ;
+
+ case cos_more_enter:
+ case cos_more_wait:
+ return uty_cli_more_wait(cli) ;
+
+ default:
+ break ;
+ } ;
+
+ return not_ready ;
} ;
/*==============================================================================
@@ -618,17 +668,18 @@ uty_cli(vty_cli cli)
*/
static cmd_do_t uty_cli_process(vty_cli cli) ;
-static void uty_cli_response(vty_cli cli, cmd_do_t cmd_do) ;
+static void uty_cli_response(vty_cli cli, cmd_do_t to_do) ;
-static bool uty_cli_dispatch(vty_cli cli) ;
+static void uty_cli_dispatch(vty_cli cli, cmd_do_t to_do) ;
static cmd_do_t uty_cli_command(vty_cli cli) ;
static void uty_cli_hist_add (vty_cli cli, qstring clx) ;
-static void uty_cli_pause_start(vty_cli cli) ;
static void uty_cli_goto_end_if_drawn(vty_cli cli) ;
/*------------------------------------------------------------------------------
- * Standard CLI for VTY_TERM -- if not blocked, runs until:
+ * Standard CLI for VTY_TERM
+ *
+ * Entered only if cst_active && cos_idle. Runs until:
*
* * runs out of keystrokes
* * executes a command
@@ -637,126 +688,86 @@ static void uty_cli_goto_end_if_drawn(vty_cli cli) ;
* is to allow for a modicum of sharing of the system. For real keyboard input
* this will make no difference at all !
*
- * Returns: not_ready blocked and was blocked when entered
- * write_ready if there is anything in the keystroke stream
- * read_ready otherwise
+ * NB: it is expected that the caller will attempt to flush any output
+ * generated.
+ *
+ * Returns: write_ready if the keystroke buffer is not empty and is not
+ * blocked, which uses write_ready to return here.
*/
static vty_readiness_t
uty_cli_standard(vty_cli cli)
{
- bool need_prompt ;
+ cmd_do_t to_do ;
VTY_ASSERT_LOCKED() ;
- assert(!cli->more_wait) ; /* cannot be here in more_wait state ! */
-
- /* cli_blocked is set when is waiting for a command, or some output to
- * complete.
- *
- * NB: in both these cases, assumes that other forces are at work to
- * keep things moving.
- */
- if (cli->blocked || cli->out_active || cli->paused || cli->mon_active)
- return not_ready ;
+ qassert((cli->state == cst_active) && (cli->out_state == cos_idle)) ;
/* Make sure that the command line is drawn.
*
* If there is nothing pending, then can run the CLI until there is
* something to do, or runs out of input.
*/
- if (!cli->drawn)
- uty_cli_draw(cli) ;
-
- if (cli->to_do == cmd_do_nothing)
- cli->to_do = cli->auth_context ? uty_cli_auth(cli)
- : uty_cli_process(cli) ;
+ if (!cli->drawn || cli->more_drawn)
+ uty_cli_draw(cli, false) ;
- /* If have something to do, do it if we can. */
- need_prompt = false ;
+ to_do = cli->to_do ; /* pick up any pending "to_do" */
- if (cli->to_do != cmd_do_nothing)
- {
- /* Reflect immediate response */
- uty_cli_response(cli, cli->to_do) ;
-
- /* If command not already in progress, dispatch this one, which may
- * set the CLI blocked.
- *
- * Otherwise is now blocked until queued command completes.
- */
- if (cli->dispatched)
- cli->blocked = true ; /* waiting for previous */
- else
- need_prompt = uty_cli_dispatch(cli) ; /* dispatch latest */
- } ;
+ if (to_do == cmd_do_nothing)
+ to_do = cli->auth_context ? uty_cli_auth(cli)
+ : uty_cli_process(cli) ;
+ else
+ cli->to_do = cmd_do_nothing ; /* clear pending "to_do" */
- /* If blocked, must wait for some other event to continue in CLI.
- *
- * Note that will be blocked if have just dispatched a command, and is
- * not "tilde_enabled" -- which is the case if single threaded, and may be
- * so for other reasons.
- *
- * If the keystroke stream is not empty, use write_ready as a proxy for
- * CLI ready -- no point doing anything until any buffered output has been
- * written away.
- *
- * If command prompt has been redrawn, need to kick writer to deal with
- * that -- will reenter to then process any keystrokes.
+ /* If we have something to do, now is the time to do it.
*/
- assert(!cli->paused) ;
-
- if (cli->blocked)
- return not_ready ;
-
- if (!keystroke_stream_empty(cli->key_stream) || need_prompt)
- return write_ready ;
+ if (to_do != cmd_do_nothing)
+ uty_cli_dispatch(cli, to_do) ;
- /* The keystroke stream is empty, but CLI is not blocked.
+ /* If not active, must wait for some other event to continue in CLI.
*
- * If a command is dispatched, and output is not active, and the command
- * line is not drawn, then go to paused state, so that will delay output
- * of the prompt slightly (or until a keystroke arrives, or the current
- * command completes, or something else happens).
- *
- * Note that if a command has been dispatched, and is !tilde_enabled, then
- * will now be blocked, so won't be here.
+ * Otherwise, if the keystroke stream is not empty, use write_ready as a
+ * proxy for CLI ready -- no point doing anything until any buffered output
+ * has been written away.
*/
- if (cli->dispatched && !cli->out_active && !cli->drawn)
- uty_cli_pause_start(cli) ;
-
- return read_ready ;
+ if ((cli->state != cst_active) || keystroke_stream_empty(cli->key_stream))
+ return read_ready ;
+ else
+ return write_ready ;
} ;
/*------------------------------------------------------------------------------
- * Dispatch the current cli->to_do -- queueing it if necessary.
+ * Dispatch the given "to_do".
*
- * Requires that are NOT blocked and NO command is queued.
+ * Requires that are NOT blocked and NO command is queued etc.
*
- * Expects to be on new blank line, and when returns will be on new, blank
- * line.
+ * Expects to be at the end of the command line for the command to be
+ * executed -- issues suitable response on the command line..
*
* Generally sets cli->to_do = cmd_do_nothing and clears cli->cl to empty.
*
- * Can set cli->cl_do = and cli->cl to be a follow-on command.
+ * Can set cli->to_do = and cli->cl to be a follow-on command.
*
- * Returns: true <=> nothing, in fact, to do: prompt has been redrawn.
+ * If there is something to do, it is queued for the command loop to deal with,
+ * will then be cst_dispatched. NB: the current line is still drawn, and
+ * cursor is at the end of the line.
+ *
+ * If there is nothing to do, issues newline and the prompt, and returns.
*/
-static bool
-uty_cli_dispatch(vty_cli cli)
+static void
+uty_cli_dispatch(vty_cli cli, cmd_do_t to_do)
{
qstring tmp ;
- cmd_do_t to_do_now ;
vty_io vio = cli->vf->vio ;
VTY_ASSERT_LOCKED() ;
/* About to dispatch a command, so must be in the following state. */
- qassert(!cli->dispatched && !cli->in_progress
- && !cli->blocked && !cli->out_active) ;
+ qassert((cli->state == cst_active) && (cli->out_state == cos_idle)) ;
qassert(cli->context->node == vio->vty->exec->context->node) ;
- /* Set cli->clx to the command about to execute & pick up cli->to_do.
+ /* Set cli->clx to the command about to execute.
*
* Clear cli->cl and cli->to_do.
*/
@@ -764,18 +775,19 @@ uty_cli_dispatch(vty_cli cli)
cli->clx = cli->cl ;
cli->cl = tmp ;
- to_do_now = cli->to_do ; /* current operation */
-
cli->to_do = cmd_do_nothing ; /* clear */
qs_clear(cli->cl) ; /* set cl empty */
+ /* Produce suitable response for the to_do_now */
+ uty_cli_response(cli, to_do) ;
+
/* Dispatch command */
if (cli->auth_context)
- to_do_now |= cmd_do_auth ;
+ to_do |= cmd_do_auth ;
else
{
/* All other nodes... */
- switch (to_do_now)
+ switch (to_do)
{
case cmd_do_nothing:
case cmd_do_ctrl_c:
@@ -784,7 +796,7 @@ uty_cli_dispatch(vty_cli cli)
break ;
case cmd_do_command:
- to_do_now = uty_cli_command(cli) ;
+ to_do = uty_cli_command(cli) ;
break ;
case cmd_do_ctrl_d:
@@ -792,12 +804,12 @@ uty_cli_dispatch(vty_cli cli)
break ;
case cmd_do_ctrl_z:
- to_do_now = uty_cli_command(cli) ;
+ to_do = uty_cli_command(cli) ;
- if (to_do_now == cmd_do_nothing)
- to_do_now = cmd_do_ctrl_z ;
+ if (to_do == cmd_do_nothing)
+ to_do = cmd_do_ctrl_z ; /* restore ^Z if line empty */
else
- cli->to_do = cmd_do_ctrl_z ; /* defer the ^Z */
+ cli->to_do = cmd_do_ctrl_z ; /* defer the ^Z */
break ;
@@ -808,24 +820,19 @@ uty_cli_dispatch(vty_cli cli)
cli->hp = cli->h_now ; /* in any event, back to the present */
- if (to_do_now != cmd_do_nothing)
+ if (to_do != cmd_do_nothing)
{
- cmd_action_set(cli->dispatch, to_do_now, cli->clx) ;
- cli->dispatched = true ;
+ cmd_action_set(cli->dispatch, to_do, cli->clx) ;
+ cli->state = cst_dispatched ;
uty_cmd_signal(vio, CMD_SUCCESS) ;
-
- cli->blocked = (to_do_now != cmd_do_command) || !cli->tilde_enabled ;
}
else
{
cmd_action_clear(cli->dispatch) ;
- cli->dispatched = false ;
-
- uty_cli_draw(cli) ;
+ uty_cli_out_newline(cli) ;
+ uty_cli_draw(cli, false) ;
} ;
-
- return !cli->dispatched ;
} ;
/*------------------------------------------------------------------------------
@@ -849,89 +856,35 @@ uty_cli_command(vty_cli cli)
/*------------------------------------------------------------------------------
* Want another command line from the CLI.
*
- * If in_progress this <=> any previous command has completed, and output may
- * be active writing the results away. Will:
- *
- * * clear cli->dispatched
- * * clear cli->in_progress
- * * clear cli->blocked
- *
- * May be in more_wait state -- so avoids touching that.
- *
- * If not in_progress, then if dispatched, we have a new command ready to pass
- * to the command loop -- which we do here, and set cli->in_progress.
- *
- * Returns: CMD_SUCCESS -- the given action has been set to next command
- * or: CMD_WAITING -- no command available (yet)
- *
- * Note that for the CLI eof and read time-out are handled as cmd_do_eof and
- * cmd_do_timed_out -- so will float through as CMD_SUCCESS and be processed
- * as commands.
- *
- * Write I/O errors and time-outs are signalled by uty_vf_error(), and
- * therefore caught in the command loop.
- *
- * Read I/O errors are signalled by uty_vf_error(). Read timeout is treated
- * as above.
+ * If have one, return it and CMD_SUCCESS and set cst_in_progress.
+ * Otherwise, return CMD_WAITING.
*/
extern cmd_return_code_t
-uty_cli_want_command(vty_cli cli, cmd_action action, cmd_context context)
+uty_cli_want_command(vty_cli cli, cmd_action action)
{
VTY_ASSERT_LOCKED() ;
- if (cli->in_progress)
- {
- /* Previous command has completed
- *
- * Make sure state reflects the fact that we are now waiting for a
- * command.
- */
- cli->dispatched = false ; /* no longer have a dispatched command */
- cli->in_progress = false ; /* command complete */
- cli->blocked = false ; /* releases possibly blocked command */
- cli->paused = false ; /* override paused state */
-
- *cli->context = *context ; /* make sure is up to date */
- cli->auth_context = ( (cli->context->node == AUTH_NODE)
- || (cli->context->node == AUTH_ENABLE_NODE) ) ;
-
- /* If the output is owned by command output, then when the buffers
- * empty, and in_progress is seen to be false, out_active will be
- * cleared.
- *
- * If the output side is not owned by command output, rewrite the
- * command line, so that prompt is up to date and visible.
- *
- * In any case, kick write_ready to ensure output clears and prompt is
- * written and so on.
- */
- if (!cli->out_active)
- uty_cli_draw(cli) ;
-
- uty_term_set_readiness(cli->vf, write_ready) ;
- }
- else if (cli->dispatched)
+ if (cli->state == cst_dispatched)
{
/* New command has been dispatched -- can now pass that to the
* command loop -- setting it in_progress.
+ *
+ * This is the moment we issue the newline, which we want written away.
*/
- assert(cli->dispatch->to_do != cmd_do_nothing) ;
+ qassert(cli->dispatch->to_do != cmd_do_nothing) ;
+ qassert((cli->out_state & cos_mask) == cos_idle) ;
+
cmd_action_take(action, cli->dispatch) ;
- cli->in_progress = true ;
- } ;
+ cli->state = cst_in_progress ;
- return cli->in_progress ? CMD_SUCCESS : CMD_WAITING ;
-} ;
+ uty_cli_out_newline(cli) ;
+ uty_term_set_readiness(cli->vf, write_ready) ;
-/*------------------------------------------------------------------------------
- * Start pause timer and set paused.
- */
-static void
-uty_cli_pause_start(vty_cli cli)
-{
- qtimer_set(cli->pause_timer, qt_add_monotonic(QTIME(0.2)), NULL) ;
- cli->paused = true ;
+ return CMD_SUCCESS ;
+ } ;
+
+ return CMD_WAITING ;
} ;
/*==============================================================================
@@ -940,13 +893,14 @@ uty_cli_pause_start(vty_cli cli)
* While command output is being cleared from its FIFO, the CLI is blocked.
*
* When the output side signals that "--more--" is required, it sets the
- * more_wait and more_enter flags.
+ * cos_more_enter out state.
*
* The first stage of handling "--more--" is to suck the input dry, so that
* (as far as is reasonably possible) does not steal a keystroke as the
- * "--more--" response which was typed before the prompt was issued.
+ * "--more--" response which was typed before the prompt was issued. This is
+ * the cos_more_enter state.
*
- * The more_enter flag indicates that the CLI is in this first stage.
+ * Once is waiting for a keystroke, is in cos_more_wait state.
*/
/*------------------------------------------------------------------------------
@@ -959,30 +913,29 @@ uty_cli_enter_more_wait(vty_cli cli)
{
VTY_ASSERT_LOCKED() ;
- qassert(cli->out_active && !cli->more_wait && !cli->drawn) ;
+ qassert((cli->out_state == cos_active) && !cli->drawn) ;
- cli->more_wait = true ; /* new state */
- cli->more_enter = true ; /* drawing the "--more--" etc. */
+ cli->out_state = cos_more_enter ; /* draw the "--more--" etc. */
} ;
/*------------------------------------------------------------------------------
* Handle the "--more--" state.
*
- * If is paused or the monitor is active, do nothing -- those override the
- * "--more--" state.
+ * Entered only if cos_more_enter or cos_more_wait. So does not get here if
+ * cos_monitor or cos_paused are set.
*
- * If more_enter is set, then need to make sure the "--more--" prompt is
+ * If cos_more_enter is set, then need to make sure the "--more--" prompt is
* written, and that any keystrokes which arrived before the prompt is
* written are taken into the keystroke stream -- so not stolen.
*
* Note that the "--more--" state may be interrupted by monitor output,
- * which, once complete, sets more_enter again.
+ * which, once complete, sets cos_more_enter again.
*
- * If more_enter is not set, tries to steal a keystroke, and if succeeds wipes
- * the "--more--" prompt and exits cli_more_wait -- and may cancel all
+ * If cos_more_wait is set, tries to steal a keystroke, and if succeeds wipes
+ * the "--more--" prompt and exits cos_more_wait -- and may cancel all
* outstanding output.
*
- * EOF on input causes immediate exit from cli_more_state.
+ * EOF on input causes immediate exit from "--more--"
*
* Returns: read_ready -- waiting to steal a keystroke
* write_ready -- waiting to draw or undraw the "--more--" prompt
@@ -996,32 +949,32 @@ uty_cli_more_wait(vty_cli cli)
VTY_ASSERT_LOCKED() ;
- assert(cli->more_wait) ; /* must be in more_wait state ! */
+ qassert( (cli->out_state == cos_more_enter) ||
+ (cli->out_state == cos_more_wait) ) ;
- if (cli->paused || cli->mon_active)
- return not_ready ;
-
- /* Deal with the first stage of "--more--" */
- if (cli->more_enter)
+ /* Deal with the first stage of "--more--"
+ *
+ * If the "--more--" is not drawn, draw it.
+ *
+ * Hoover up any input there is pending -- probably none, but this seems
+ * tidy.
+ *
+ * If the "--more--" prompt has been written away, we are ready to steal
+ * a keystroke -- ie go to cos_more_wait.
+ *
+ * In any event, exit write_ready ready to keep things moving.
+ */
+ if (cli->out_state == cos_more_enter)
{
- int get ;
+ if (!cli->drawn || !cli->more_drawn)
+ uty_cli_draw(cli, true) ; /* draw the "--more--" */
- if (!cli->drawn)
- uty_cli_draw(cli) ; /* draw the "--more--" */
-
- /* If the CLI buffer is not yet empty, then is waiting for the
- * initial prompt to clear, so nothing to be done here.
- */
- if (!vio_fifo_empty(cli->cbuf))
- return write_ready ;
+ uty_term_read(cli->vf) ; /* hoover up. */
- cli->more_enter = false ;
+ if (vio_fifo_empty(cli->cbuf))
+ cli->out_state = cos_more_wait ;
- /* empty the input buffer into the keystroke stream */
- do
- {
- get = uty_term_read(cli->vf) ;
- } while (get > 0) ;
+ return write_ready ;
} ;
/* Try to get a stolen keystroke. If the keystroke stream has hit
@@ -1078,15 +1031,13 @@ uty_cli_more_wait(vty_cli cli)
* Return write_ready to tidy up the screen and, unless cleared, write
* some more.
*/
+ cli->out_state = cos_active ; /* revert to active state */
if (cancel)
{
vio_fifo_clear(cli->vf->obuf, false) ;
- vio_lc_clear(cli->olc) ; /* clear & reset counter */
-
- uty_cli_goto_end_if_drawn(cli) ;
- cli->drawn = false ;
+ vio_lc_clear(cli->olc) ; /* clear & reset counter */
- qassert(cli->out_active) ;
+ cli->out_state = cos_cancel ;
uty_cmd_signal(cli->vf->vio, CMD_CANCEL) ; /* ^C */
}
@@ -1096,9 +1047,6 @@ uty_cli_more_wait(vty_cli cli)
uty_cli_wipe(cli, 0) ;
} ;
- cli->more_wait = false ; /* exit more_wait */
- cli->more_enter = false ; /* tidy */
-
return write_ready ;
} ;
@@ -1124,7 +1072,7 @@ uty_cli_more_wait(vty_cli cli)
*/
/*-----------------------------------------------------------------------------
- * Prepare for new monitor output line.
+ * Prepare for new monitor output line (s).
*
* Wipe any existing command line.
*/
@@ -1135,7 +1083,7 @@ uty_cli_pre_monitor(vty_cli cli)
uty_cli_wipe(cli, 0) ;
- cli->mon_active = true ; /* block cli & enable empty of fifo */
+ cli->out_state = (cli->out_state | cos_monitor) & ~cos_paused ;
} ;
/*------------------------------------------------------------------------------
@@ -1143,7 +1091,8 @@ uty_cli_pre_monitor(vty_cli cli)
*
* If monitor line failed to complete, append the rump to the CLI buffer.
*
- * If have a non-empty command line, or is cli_more_wait, redraw the command
+ *
+ * If have a non-empty command line, or is cos_more_wait, redraw the command
* line.
*
* Returns: 0 => rump was empty and no command line stuff written
@@ -1154,12 +1103,31 @@ uty_cli_post_monitor(vty_cli cli)
{
VTY_ASSERT_LOCKED() ;
- uty_cli_pause_start(cli) ; /* do not draw prompt immediately */
+ /* Clear the monitor output state.
+ *
+ * Should not be cos_paused -- but clear that too.
+ */
+ qassert((cli->out_state & (cos_monitor | cos_paused)) == cos_monitor) ;
- cli->more_enter = cli->more_wait ;
- /* revert to more_enter state */
+ cli->out_state &= ~(cos_monitor | cos_paused) ;
+
+ /* If was cos_more_wait, then fall back to cos_more_enter.
+ *
+ * Note that does not set cos_cancel on top of cos_more_wait/cos_more_enter !
+ */
+ if (cli->out_state == cos_more_wait)
+ cli->out_state = cos_more_enter ;
+
+ /* If not cos_cancel, if we have a pause_timer, then set that going, now.
+ *
+ * Note that when the cli is closed any timer is freed.
+ */
+ if ((cli->out_state != cos_cancel) && (cli->pause_timer != NULL))
+ {
+ qtimer_set(cli->pause_timer, qt_add_monotonic(QTIME(0.2)), NULL) ;
+ cli->out_state |= cos_paused ;
+ } ;
- cli->mon_active = false ; /* unblock cli & turn off output */
} ;
/*==============================================================================
@@ -1272,10 +1240,9 @@ uty_cli_write_s(vty_cli cli, const char *str)
extern void
uty_cli_out_newline(vty_cli cli)
{
- uty_cli_goto_end_if_drawn(cli) ;
+ uty_cli_goto_end_if_drawn(cli) ; /* clears cli->drawn */
uty_cli_write(cli, telnet_newline, 2) ;
- cli->drawn = false ;
} ;
/*------------------------------------------------------------------------------
@@ -1305,16 +1272,15 @@ uty_cli_out_wipe_n(vty_cli cli, int n)
*
* Clears cli->drawn.
*/
-static void
-uty_cli_cancel(vty_cli cli)
+extern void
+uty_cli_cancel(vty_cli cli, bool cntrl_c)
{
if (cli->drawn)
{
- uty_cli_goto_end_if_drawn(cli) ;
+ uty_cli_goto_end_if_drawn(cli) ; /* clears cli->drawn */
- uty_cli_write_s(cli, " ^C" TELNET_NEWLINE) ;
-
- cli->drawn = false ;
+ if (cntrl_c)
+ uty_cli_write_s(cli, " ^C" TELNET_NEWLINE) ;
} ;
} ;
@@ -1322,70 +1288,52 @@ uty_cli_cancel(vty_cli cli)
* If the command line is drawn and the cursor is not at the end of the line,
* move the physical cursor to the end of the line.
*
- * Assumes about to issue newline.
+ * Assumes about to issue newline, so clears cli->drawn
*/
static void
uty_cli_goto_end_if_drawn(vty_cli cli)
{
- ulen after ;
+ if (cli->drawn && !cli->more_drawn)
+ {
+ ulen after ;
+
+ after = qs_after_cp_nn(cli->cl) ;
+
+ if (after != 0)
+ uty_cli_write(cli, qs_cp_char_nn(cli->cl), after) ;
+ } ;
- if (cli->drawn && ( (after = qs_after_cp_nn(cli->cl)) != 0 ))
- uty_cli_write(cli, qs_cp_char_nn(cli->cl), after) ;
+ cli->drawn = false ;
} ;
/*------------------------------------------------------------------------------
- * Send response to the given cmd_do
- *
- * If no command is in progress, then will send newline to signal that the
- * command is about to be dispatched.
+ * Send any special response -- depending on what's to_do.
*
- * If command is in progress, then leaves cursor on '^' to signal that is now
- * waiting for previous command to complete.
+ * NB: at this point MUST be at end of cli->cl.
*/
-static const char* cli_response [2][cmd_do_count] =
+static const char* cli_response [cmd_do_count] =
{
- { /* when not waiting for previous command to complete */
- [cmd_do_command] = "",
- [cmd_do_ctrl_c] = "^C",
- [cmd_do_ctrl_d] = "^D",
- [cmd_do_ctrl_z] = "^Z",
- [cmd_do_eof] = "^*",
- [cmd_do_timed_out] = "^!"
- },
- { /* when waiting for a previous command to complete */
- [cmd_do_command] = "^",
+ [cmd_do_command] = NULL,
[cmd_do_ctrl_c] = "^C",
[cmd_do_ctrl_d] = "^D",
[cmd_do_ctrl_z] = "^Z",
[cmd_do_eof] = "^*",
- [cmd_do_timed_out] = "^!"
- }
+ [cmd_do_timed_out] = "^!",
} ;
static void
uty_cli_response(vty_cli cli, cmd_do_t to_do)
{
const char* str ;
- int len ;
- assert((to_do != cmd_do_nothing) && cli->drawn
+ qassert((to_do != cmd_do_nothing) && cli->drawn
&& (qs_cp_nn(cli->cl) == qs_len_nn(cli->cl))) ;
+ qassert(to_do < cmd_do_count) ;
- str = (to_do < cmd_do_count)
- ? cli_response[cli->dispatched ? 1 : 0][to_do] : NULL ;
- assert(str != NULL) ;
-
- len = uty_cli_write_s(cli, str) ;
+ str = (to_do < cmd_do_count) ? cli_response[to_do] : NULL ;
- if (cli->dispatched)
- {
- cli->extra_len = len ;
- uty_cli_write_n(cli, telnet_backspaces, len) ;
- }
- else
- {
- uty_cli_out_newline(cli) ;
- } ;
+ if (str != NULL)
+ uty_cli_write_s(cli, str) ;
} ;
/*------------------------------------------------------------------------------
@@ -1416,10 +1364,10 @@ uty_cli_wipe(vty_cli cli, int len)
assert(qs_cp_nn(cli->cl) <= qs_len_nn(cli->cl)) ;
/* Establish how much ahead and how much behind the cursor */
- a = cli->extra_len ;
+ a = 0 ;
b = cli->prompt_len ;
- if (!cli->more_wait)
+ if (!cli->more_drawn)
{
a += qs_len_nn(cli->cl) - qs_cp_nn(cli->cl) ;
b += qs_cp_nn(cli->cl) ;
@@ -1440,7 +1388,7 @@ uty_cli_wipe(vty_cli cli, int len)
uty_cli_write_n(cli, telnet_backspaces, b) ;
/* Nothing there any more */
- cli->drawn = false ;
+ cli->drawn = false ;
} ;
/*------------------------------------------------------------------------------
@@ -1464,10 +1412,9 @@ uty_cli_wipe(vty_cli cli, int len)
*
* Sets: cli->drawn = true
* cli->prompt_len = length of prompt used
- * cli->extra_len = 0
*/
static void
-uty_cli_draw(vty_cli cli)
+uty_cli_draw(vty_cli cli, bool more_prompt)
{
const char* prompt ;
size_t l_len ;
@@ -1480,19 +1427,12 @@ uty_cli_draw(vty_cli cli)
p_len = 0 ;
l_len = 0 ;
}
- else if (cli->more_wait)
+ else if (more_prompt)
{
prompt = "--more--" ;
p_len = strlen(prompt) ;
l_len = 0 ;
}
- else if (cli->dispatched)
- {
- /* If there is a queued command, the prompt is a minimal affair. */
- prompt = "~ " ;
- p_len = strlen(prompt) ;
- l_len = qs_len_nn(cli->cl) ;
- }
else
{
/* The prompt depends on the node, and is expected to include the
@@ -1533,8 +1473,7 @@ uty_cli_draw(vty_cli cli)
/* Set about writing the prompt and the line */
cli->drawn = true ;
- cli->extra_len = false ;
-
+ cli->more_drawn = more_prompt ;
cli->prompt_len = p_len ;
uty_cli_write(cli, prompt, p_len) ;
@@ -2008,13 +1947,12 @@ uty_cli_get_keystroke(vty_cli cli, keystroke stroke)
if (stroke->type != ks_iac)
return cmd_do_keystroke ; /* have a keystroke */
- /* Deal with telnet command, so invisible to upper level */
+ /* Deal with telnet command, so invisible to upper level
+ */
uty_telnet_command(cli->vf, stroke, false) ;
}
else
{
- int get ;
-
qassert(stroke->type == ks_null) ;
switch (stroke->value)
@@ -2033,10 +1971,7 @@ uty_cli_get_keystroke(vty_cli cli, keystroke stroke)
break ;
} ;
- get = uty_term_read(cli->vf) ; /* sets eof in key_stream
- if hit eof or error */
- if ((get == 0) || (get == -1))
- return cmd_do_nothing ;
+ return cmd_do_nothing ;
} ;
} ;
} ;
@@ -2986,7 +2921,7 @@ uty_cli_help_finish(vty_cli cli)
{
if (!cli->drawn)
{
- uty_cli_draw(cli) ;
+ uty_cli_draw(cli, false) ;
qs_copy(cli->cls, cli->cl) ;
} ;
} ;
diff --git a/lib/vty_cli.h b/lib/vty_cli.h
index e366ecdf..13d394aa 100644
--- a/lib/vty_cli.h
+++ b/lib/vty_cli.h
@@ -37,6 +37,35 @@
#include "keystroke.h"
/*------------------------------------------------------------------------------
+ * States of the CLI and related output.
+ */
+typedef enum cli_state
+{
+ cst_active = 0,
+ cst_dispatched = 1,
+ cst_in_progress = 2,
+ cst_complete = 3,
+
+} cli_state_t ;
+
+typedef enum cli_out_state
+{
+ cos_idle = 0,
+
+ cos_active = 1,
+ cos_cancel = 2,
+
+ cos_more_enter = 3,
+ cos_more_wait = 4,
+
+ cos_mask = BIT(4) - 1,
+
+ cos_monitor = BIT(6),
+ cos_paused = BIT(7),
+
+} cli_out_state_t ;
+
+/*------------------------------------------------------------------------------
* The vty_cli structure pointed to by the vty_io structure.
*/
typedef struct vty_cli* vty_cli ;
@@ -74,70 +103,33 @@ struct vty_cli
* any other output can use the screen.
*
* In particular, must be cleared before setting
- * out_active -- see below.
+ * cos_active -- see below.
*
- * tilde_enabled <=> do the "~ " one command line ahead.
+ * more_drawn <=> what is drawn is the "--more--" prompt.
+ * => drawn
*
* If drawn is true, the following are valid:
*
- * tilde_prompt -- the prompt is the "~ "
- *
* prompt_len -- the length of the prompt part.
* (will be the "--more--" prompt in cli_more_wait)
*
- * extra_len -- the length of any ^X at the cursor position
- * (for when blocked waiting for queued command)
- *
* echo_suppress -- the user part of the command line is suppressed
*
* NB: echo_suppress is only used for password entry.
*/
bool drawn ;
-
- bool tilde_prompt ;
- bool tilde_enabled ;
-
+ bool more_drawn ;
int prompt_len ;
- int extra_len ;
/* "cache" for prompt -- when node or host name changes, prompt does */
node_type_t prompt_node ;
name_gen_t prompt_gen ;
qstring prompt_for_node ;
- /* State of the CLI
- *
- * dispatched -- command dispatched by CLI
- * in_progress -- command taken by the command loop
- * blocked -- blocked until current command completes
- * paused -- command dispatched and nothing else happened
- *
- * mon_active -- there is stuff in the logging monitor buffer
- *
- * out_active -- contents of the obuf FIFO are being written away
- * though may be blocked in more_wait
- *
- * This flag <=> that the command output "owns" the screen.
- *
- * While this flag is set, the CLI may not write to the
- * screen.
- *
- * Flag is cleared when obuf is empty, and is !in_progress.
- *
- * more_wait -- is in "--more--" wait state
- * more_enter -- more_wait and waiting for "--more--" prompt to be
- * written away and keystrokes to be consumed.
+ /* State of the CLI and its output
*/
- bool dispatched ;
- bool in_progress ;
- bool blocked ;
- bool paused ;
-
- bool mon_active ;
- bool out_active ;
-
- bool more_wait ;
- bool more_enter ;
+ cli_state_t state ;
+ cli_out_state_t out_state ;
/* This is set only if the "--more--" handling is enabled */
bool more_enabled ;
@@ -199,13 +191,13 @@ extern ulen uty_cli_prompt_len(vty_cli cli) ;
extern vty_readiness_t uty_cli(vty_cli cli) ;
-extern cmd_return_code_t uty_cli_want_command(vty_cli cli, cmd_action action,
- cmd_context context) ;
+extern cmd_return_code_t uty_cli_want_command(vty_cli cli, cmd_action action) ;
extern void uty_cli_out(vty_cli cli, const char *format, ...)
PRINTF_ATTRIBUTE(2, 3) ;
extern void uty_cli_out_newline(vty_cli cli) ;
extern void uty_cli_write(vty_cli cli, const char *this, int len) ;
extern void uty_cli_wipe(vty_cli cli, int len) ;
+extern void uty_cli_cancel(vty_cli cli, bool cntrl_c) ;
extern void uty_cli_set_lines(vty_cli cli, int lines, bool explicit) ;
extern void uty_cli_set_window(vty_cli cli, int width, int height) ;
diff --git a/lib/vty_command.c b/lib/vty_command.c
index d195f193..79a8a294 100644
--- a/lib/vty_command.c
+++ b/lib/vty_command.c
@@ -121,6 +121,7 @@ static bool uty_cmd_loop_prepare(vty_io vio) ;
static void uty_cmd_stopping(vty_io vio, bool exeunt) ;
static cmd_return_code_t uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret) ;
static cmd_return_code_t vty_cmd_auth(vty vty, node_type_t* p_next_node) ;
+static void uty_cmd_complete(vty_io vio) ;
static void uty_cmd_out_cancel(vio_vf vf, bool base) ;
static uint uty_show_error_context(vio_fifo ebuf, vio_vf vf) ;
static uint uty_cmd_failed(vty_io vio, cmd_return_code_t ret) ;
@@ -544,8 +545,7 @@ vty_cmd_fetch_line(vty vty)
break ;
case VIN_TERM:
- ret = uty_term_fetch_command_line(vf, exec->action,
- exec->context) ;
+ ret = uty_term_fetch_command_line(vf, exec->action) ;
break ;
case VIN_VTYSH:
@@ -976,8 +976,8 @@ vty_cmd_auth(vty vty, node_type_t* p_next_node)
*
* The command_queue command loop runs until something happens that it
* cannot immediately deal with, at which point it enters "exec_hiatus", and
- * this function is called. The command loop will deal with CMD_SUCCESS and
- * CMD_EMPTY, but otherwise this function must deal with:
+ * this function is called. The command loop will deal with CMD_SUCCESS,
+ * but otherwise this function must deal with:
*
* CMD_HIATUS -- something requires attention, eg:
*
@@ -1010,8 +1010,6 @@ vty_cmd_auth(vty vty, node_type_t* p_next_node)
*
* CMD_SUCCESS -- see below
*
- * CMD_EMPTY -- should not appear, but is treated as CMD_SUCCESS
- *
* anything else -- treated as a command or I/O or other error.
*
* The handling of errors depends on the type of error:
@@ -1180,7 +1178,6 @@ uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret)
switch (ret)
{
case CMD_SUCCESS:
- case CMD_EMPTY:
case CMD_HIATUS:
ret = CMD_SUCCESS ; /* OK */
break ;
@@ -1320,6 +1317,11 @@ uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret)
*
* If the vty is about to be closed, this step ensures that all output
* is tidily dealt with, before uty_close() performs its "final" close.
+ *
+ * If we are also down to the vin_base, then signal that the last base
+ * level command has completed. Need to do this even if the vin_depth
+ * is zero -- so that, if required, the output side will signal that
+ * all I/O is complete.
*/
if (vio->vout_depth == 1)
{
@@ -1327,6 +1329,8 @@ uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret)
{
/* Once we have cleared the output buffer etc., clear the cancel
* flag and output "^C" to show what has happened.
+ *
+ * Also, for VTY_TERMINAL, clears the cos_cancel down to cos_active.
*/
uty_cmd_out_cancel(vio->vout, true) ; /* stop output & pipe return
* is vout_base */
@@ -1350,6 +1354,9 @@ uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret)
ret = uty_cmd_out_push(vio->vout, false) ;
+ if (vio->vin_depth <= 1)
+ uty_cmd_complete(vio) ;
+
if (ret != CMD_SUCCESS)
return ret ; /* CMD_WAITING or CMD_IO_ERROR */
} ;
@@ -1688,19 +1695,27 @@ vty_cmd_success(vty vty)
vty_io vio ;
VTY_LOCK() ;
- vio = vty->vio ; /* once locked */
+ vio = vty->vio ; /* once locked */
ret = vio->signal ; /* signal can interrupt */
- if (ret == CMD_SUCCESS)
+ /* out_suppress is set only when is VTY_CONFIG_READ and the output is not
+ * required -- not even if there is a signal outstanding.
+ *
+ * NB: we do not need to worry about uty_cmd_complete() for VTY_CONFIG_READ.
+ *
+ * If not interrupted by a signal, push anything there is to push, and
+ * if we are at the base stack level, signal uty_cmd_complete().
+ */
+ if (vty->exec->out_suppress)
+ vio_fifo_back_to_end_mark(vio->obuf, true) ; /* keep end mark */
+ else if (ret == CMD_SUCCESS)
{
if (!vio_fifo_tail_empty(vio->obuf))
- {
- if (!vty->exec->out_suppress)
- ret = uty_cmd_out_push(vio->vout, false) ; /* not final */
- else
- vio_fifo_back_to_end_mark(vio->obuf, true) ; /* keep end mark */
- } ;
+ ret = uty_cmd_out_push(vio->vout, false) ; /* not final */
+
+ if ((vio->vin_depth == 1) && (vio->vout_depth == 1))
+ uty_cmd_complete(vio) ;
} ;
VTY_UNLOCK() ;
@@ -1709,6 +1724,60 @@ vty_cmd_success(vty vty)
} ;
/*------------------------------------------------------------------------------
+ * A command has completed -- for whatever reason -- no further output will
+ * appear, so the output buffer can now emptied out (including any trailing
+ * line without a line ending) and when that finishes the output is, again,
+ * idle.
+ *
+ * This is *only* when is at the base vin and vout level (or if vin is closed
+ * and is at base vout).
+ *
+ * For VTY_TERMINAL, the completion of all output associated with a command
+ * signals the time to start fetching the next one.
+ *
+ * For VTY_SHELL_SERVER, ditto.
+ *
+ * For VTY_CONFIG_READ, nothing is required.
+ */
+static void
+uty_cmd_complete(vty_io vio)
+{
+ VTY_ASSERT_LOCKED() ;
+
+ qassert((vio->vin_depth <= 1) && (vio->vout_depth == 1)) ;
+
+ switch (vio->vin->vin_type)
+ {
+ case VIN_NONE:
+ zabort("invalid vin_none") ;
+ break ;
+
+ case VIN_TERM:
+ uty_term_cmd_complete(vio->vin, vio->vty->exec->context) ;
+ break ;
+
+ case VIN_VTYSH:
+ /* Signal end of command return */
+ break ;
+
+ case VIN_FILE:
+ break ;
+
+ case VIN_PIPE:
+ break ;
+
+ case VIN_CONFIG:
+ break ; /* do nothing ! */
+
+ case VIN_DEV_NULL:
+ break ;
+
+ default:
+ zabort("unknown vin_type") ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
* If there is anything after the end_mark, push it to be written, now.
*
* This is used by configuration file output, which outputs to the fifo and
@@ -1858,6 +1927,9 @@ uty_cmd_out_cancel(vio_vf vf, bool base)
*/
vio_fifo_clear(vf->obuf, false) ;
+ if (vf->vout_type == VOUT_TERM)
+ uty_term_out_cancelled(vf) ;
+
if (!base && (vf->vout_state == vf_open))
vf->vout_state = vf_end ;
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 0660afb6..42ab941a 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -181,6 +181,11 @@ uty_term_open(int sock_fd, union sockunion *su)
if (0)
uty_term_dont_lflow_ahead (vf->cli) ;
+ /* Hoover up any currently available input -- possibly Telnet commands/
+ * escapes from the other end.
+ */
+ uty_term_read(vf) ;
+
/* Say hello */
vty_hello(vty);
@@ -215,13 +220,53 @@ uty_term_open(int sock_fd, union sockunion *su)
* CMD_IO_ERROR -- any errors are dealt with by signalling the command loop.
*/
extern cmd_return_code_t
-uty_term_fetch_command_line(vio_vf vf, cmd_action action, cmd_context context)
+uty_term_fetch_command_line(vio_vf vf, cmd_action action)
{
VTY_ASSERT_LOCKED() ;
qassert(vf->vin_state == vf_open) ;
- return uty_cli_want_command(vf->cli, action, context) ;
+ return uty_cli_want_command(vf->cli, action) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Command has completed.
+ *
+ * If is cst_in_progress:
+ *
+ * -- set cst_complete
+ *
+ * -- collect current context
+ *
+ * -- if is cos_idle then force cos_active -- the obuf etc. will be
+ * empty, but we want to make sure that all other buffers empty out,
+ * and that the output side will signal when that's so.
+ *
+ * -- kick write_ready to make sure that things move along.
+ */
+extern void
+uty_term_cmd_complete(vio_vf vf, cmd_context context)
+{
+ vty_cli cli = vf->cli ;
+
+ VTY_ASSERT_LOCKED() ;
+
+ if (cli->state == cst_in_progress)
+ {
+ cli->state = cst_complete ;
+
+ if (cli->out_state == cos_idle)
+ {
+ vio_fifo_clear(vf->obuf, false) ; /* keep end mark */
+ cli->out_state = cos_active ;
+ } ;
+
+ *cli->context = *context ;
+ cli->auth_context = ( (cli->context->node == AUTH_NODE)
+ || (cli->context->node == AUTH_ENABLE_NODE) ) ;
+
+ uty_term_set_readiness(vf, write_ready) ;
+ } ;
} ;
/*------------------------------------------------------------------------------
@@ -269,28 +314,36 @@ uty_term_out_push(vio_vf vf, bool final)
{
vty_cli cli = vf->cli ;
utw_ret_t done ;
+ cli_out_state_t out_state ;
qassert(vf->vout_state == vf_open) ;
qassert(!vf->blocking) ;
- /* If squelching, dump anything we have in the obuf.
+ out_state = cli->out_state & cos_mask ;
+
+ /* If squelching, discard anything we have in the obuf.
*/
if (vf->vio->cancel)
vio_fifo_clear(vf->obuf, false) ; /* keep end mark */
- /* If have something in the obuf that needs to be written, then if not
- * already out_active, make sure the command line is clear, and set
- * out_active.
+ /* If we have something in the obuf that needs to be written, then if
+ * is cos_idle, make sure the command line is clear, and set cos_active.
+ *
+ * Note that may be cos_idle | cos_monitor, for which we need to keep the
+ * monitor flag but update to cos_active -- the cli will already be wiped.
*/
- if (!cli->out_active && !vio_fifo_empty(vf->obuf))
+ if (!vio_fifo_empty(vf->obuf) && (out_state == cos_idle))
{
uty_cli_wipe(cli, 0) ;
- cli->out_active = true ;
+ cli->out_state ^= (cos_active ^ cos_idle) ;
vio_lc_counter_reset(cli->olc) ;
} ;
/* Give the terminal writing a shove.
*
+ * Note that there may be stuff pending, and stuff in the cbuf, etc. We
+ * depend on the uty_term_write() to know all about what can be done.
+ *
* If final, keep pushing while succeeds in writing without blocking.
*
* Note that is only called "final" when closing the vout, by which time
@@ -310,21 +363,52 @@ uty_term_out_push(vio_vf vf, bool final)
/* Deal with the result
*
- * If required and if not final make sure that write ready is set, so
- * that the pselect() process can pursue the issue.
+ * If not failed and not final, set write ready if:
+ *
+ * not utw_done => output blocked.
+ *
+ * cli->out_state == cos_idle => CLI may run
*
* Return code depends on utw_xxx
*/
- if (done == utw_done)
- return CMD_SUCCESS ; /* don't set write ready */
-
if (done == utw_error)
return CMD_IO_ERROR ; /* don't set write ready */
if (!final)
- uty_term_set_readiness(vf, write_ready) ;
+ {
+ if ((done != utw_done) || (cli->out_state == cos_idle))
+ uty_term_set_readiness(vf, write_ready) ;
+ } ;
- return CMD_WAITING ; /* waiting for write ready */
+ return (done == utw_done) ? CMD_SUCCESS : CMD_WAITING ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Completed the cancelling of command(s) and output.
+ *
+ * Caller is about to output "^C" to signal completion of the cancellation
+ * process -- sets the cli->state to cos_active, to allow final output to
+ * proceed, and the command loop continue.
+ *
+ * Clears any cos_paused !
+ *
+ * If the current line is "drawn", make sure we are at the end of it, and then
+ * clear the "drawn" state, because "^C\n" is about to follow.
+ *
+ * Clear the line control, to make sure that cannot now interfere.
+ */
+extern void
+uty_term_out_cancelled(vio_vf vf)
+{
+ vty_cli cli = vf->cli ;
+
+ qassert((cli->out_state & cos_mask) == cos_cancel) ;
+
+ cli->out_state = cos_active | (cli->out_state & cos_monitor) ;
+
+ vio_lc_counter_reset(cli->olc) ;
+
+ uty_cli_cancel(cli, false) ;
} ;
/*------------------------------------------------------------------------------
@@ -377,8 +461,8 @@ uty_term_close_reason(vio_vf vf, const char* reason)
{
vio_lc_clear(vf->cli->olc) ;
- vf->cli->mon_active = false ; /* stamp on any monitor output */
-
+ vf->cli->out_state = cos_idle ; /* stamp on monitor or other output
+ * clear cancel and paused */
uty_cli_out(vf->cli, "%% %s%s", reason, uty_cli_newline) ;
} ;
@@ -487,7 +571,7 @@ uty_term_read_ready(vio_vfd vfd, void* action_info)
qassert(vfd == vf->vfd) ;
- vf->cli->paused = false ; /* read ready clears paused */
+ vf->cli->out_state &= ~cos_paused ; /* read ready clears paused */
uty_term_read(vf) ;
uty_term_ready(vf) ;
@@ -547,6 +631,7 @@ uty_term_ready(vio_vf vf)
{
vty_readiness_t ready ;
utw_ret_t done, done_before ;
+ cli_out_state_t out_state ;
VTY_ASSERT_LOCKED() ;
@@ -562,6 +647,7 @@ uty_term_ready(vio_vf vf)
* This is because the CLI may generate more to write, and writing stuff
* away may release the CLI.
*/
+ out_state = vf->cli->out_state ;
done = utw_null ;
do
{
@@ -595,9 +681,9 @@ uty_term_ready(vio_vf vf)
uty_term_set_readiness(vf, ready) ;
- /* Signal the command loop if not waiting for write any more.
+ /* Signal the command loop if the cli->out_state has changed significantly
*/
- if ((ready & write_ready) == 0)
+ if ((vf->cli->out_state == cos_idle) && (out_state != cos_idle))
uty_cmd_signal(vf->vio, CMD_SUCCESS) ;
} ;
@@ -618,7 +704,7 @@ uty_term_read_timeout(vio_timer timer, void* action_info)
keystroke_stream_set_eof(vf->cli->key_stream, true) ; /* timed out */
- vf->cli->paused = false ;
+ vf->cli->out_state &= ~cos_paused ;
uty_term_ready(vf) ;
@@ -639,7 +725,7 @@ uty_term_write_timeout(vio_timer timer, void* action_info)
VTY_ASSERT_LOCKED() ;
- vf->cli->paused = false ;
+ vf->cli->out_state &= ~cos_paused ;
uty_vf_error(vf, verr_to_vout, 0) ;
@@ -659,9 +745,9 @@ vty_term_pause_timeout(qtimer qtr, void* timer_info, qtime_mono_t when)
cli = timer_info ;
assert(cli->pause_timer == qtr) ;
- if (cli->paused)
+ if (cli->out_state & cos_paused)
{
- cli->paused = false ;
+ cli->out_state ^= cos_paused ;
uty_term_ready(cli->vf) ;
} ;
@@ -675,15 +761,13 @@ vty_term_pause_timeout(qtimer qtr, void* timer_info, qtime_mono_t when)
*/
/*------------------------------------------------------------------------------
- * Read a lump of bytes and shovel into the keystroke stream
+ * Hoover up input and shovel into the keystroke stream
*
* NB: need not be in the term_ready path. Indeed, when the VTY_TERMINAL is
* initialised, this is called to suck up any telnet preamble.
*
- * NB: the terminal is permanently read-ready, so will keep calling this
- * until all input is hoovered up. For real terminals it is assumed that
- * reading a lump of bytes this small will immediately empty the input
- * buffer.
+ * NB: the terminal is permanently read-ready, so the keystroke stream
+ * should be permanently topped up.
*
* When reaches EOF on the input eof is set in the keystroke stream, and the
* vfd is read closed. Read closing the vfd turns off any timeout and prevents
@@ -691,23 +775,16 @@ vty_term_pause_timeout(qtimer qtr, void* timer_info, qtime_mono_t when)
* NOT set vf->vin_state to vf_end, because that is not true until the
* keystroke stream is empty. Once eof is set in the keystroke stream, this
* code will not attempt any further input from the vfd.
- *
- * Returns: 0 => nothing available
- * > 0 => read at least one byte
- * == -1 => I/O error
- * == -2 => hit EOF (without reading anything else)
*/
-extern int
+extern void
uty_term_read(vio_vf vf)
{
keystroke_stream stream ;
- unsigned char buf[500] ;
- int get ;
stream = vf->cli->key_stream ;
if (keystroke_stream_met_eof(stream))
- return -2 ; /* already seen EOF */
+ return ; /* already seen EOF */
if (vf->vin_state != vf_open)
{
@@ -716,33 +793,51 @@ uty_term_read(vio_vf vf)
* force it to EOF.
*/
keystroke_stream_set_eof(vf->cli->key_stream, false) ;
- return -2 ;
+ return ;
} ;
/* OK: read from input and pass result to keystroke stream.
+ *
+ * Uses a relatively small buffer, which should be fine for actual
+ * terminals !
*/
- get = read_nb(vio_vfd_fd(vf->vfd), buf, sizeof(buf)) ;
- /* -1 <=> error, -2 <=> EOF */
- if (get != 0)
+ while (1)
{
- if (get == -1)
+ unsigned char buf[500] ;
+ int get ;
+
+ get = read_nb(vio_vfd_fd(vf->vfd), buf, sizeof(buf)) ;
+ /* -1 <=> error, -2 <=> EOF */
+ if (get == 0)
+ return ;
+
+ if (get != -1)
{
- /* Error: signal to command loop and force key_stream empty */
- uty_vf_error(vf, verr_io_vin, errno) ;
- keystroke_stream_set_eof(vf->cli->key_stream, false) ;
- /* not timed-out */
+ /* Not error. get < 0 => EOF and that is set in key_stream.
+ */
+ keystroke_input(vf->cli->key_stream, buf, get) ;
}
else
{
- /* Not error. get < 0 => EOF and that is set in key_stream. */
- keystroke_input(vf->cli->key_stream, buf, get) ;
+ /* Error: signal to command loop and force key_stream empty
+ */
+ uty_vf_error(vf, verr_io_vin, errno) ;
+ keystroke_stream_set_eof(vf->cli->key_stream, false) ;
+ /* not timed-out */
} ;
- if (get < 0)
- vio_vfd_read_close(vf->vfd) ;
- } ;
+ if (get > 0)
+ continue ; /* hoover up all there is. */
+
+ /* Error or EOF -- close the input half of the socket, and we're done.
+ *
+ * NB: this does not affect the vin_state, which (if not error) continues
+ * vf_open until hits EOF on the keystroke stream.
+ */
+ vio_vfd_read_close(vf->vfd) ;
- return get ;
+ return ;
+ } ;
} ;
/*==============================================================================
@@ -752,8 +847,8 @@ uty_term_read(vio_vf vf)
*
* cli->cbuf -- command line -- reflects the status of the command line
*
- * vf->obuf -- command output -- which is written to the file only while
- * out_active, and not blocked in more_wait.
+ * vf->obuf -- command output -- which is written to the terminal only while
+ * cos_active.
*
* The cli output takes precedence.
*
@@ -786,10 +881,14 @@ uty_term_mon_write(vio_vf vf)
/*------------------------------------------------------------------------------
* Write as much as possible of what there is.
*
- * Move to more_wait if required.
+ * If there is anything in the CLI buffer, try to empty that.
+ *
+ * If is cos_monitor, try to empty the mbuf.
*
- * If is cli->flush, then when all buffers are emptied out, clears itself and
- * the out_active flag.
+ * If cos_active, try to empty the obuf. Move to more_wait if required.
+ *
+ * If is not "in_progress", then when all buffers are emptied out, clears
+ * itself and the cos_active state.
*
* Returns:
*
@@ -833,10 +932,7 @@ uty_term_write(vio_vf vf)
vio_fifo_clear(cli->cbuf, false) ;
vio_lc_clear(cli->olc) ;
- cli->out_active = false ;
-
- cli->more_wait = false ;
- cli->more_enter = false ;
+ cli->out_state = cos_idle ; /* stamps on everything */
return utw_error ;
} ;
@@ -863,13 +959,13 @@ uty_term_write(vio_vf vf)
/* Next: if there is monitor output to deal with, deal with it.
*
- * Note that the mon_active flag is set under VTY_LOCK(), so do not
+ * Note that the cos_monitor state is set under VTY_LOCK(), so do not
* need to LOG_LOCK() to discover whether there is anything to do.
*
* But the vio->mbuf is filled under LOG_LOCK(), so need to write it
* under the same.
*/
- if (cli->mon_active)
+ if (cli->out_state & cos_monitor)
{
LOG_LOCK() ;
@@ -886,13 +982,13 @@ uty_term_write(vio_vf vf)
return utw_error ;
} ;
- uty_cli_post_monitor(vf->cli) ;
+ uty_cli_post_monitor(vf->cli) ; /* clears monitor output state */
} ;
- /* If not out_active, or in more_wait, then we are done, waiting for some
- * external event to move things on.
+ /* If not cos_active we are done, waiting for some external event to move
+ * things on.
*/
- if ((!cli->out_active) || (cli->more_wait))
+ if (cli->out_state != cos_active)
return utw_done ; /* can do no more */
/* Push the output fifo and any complete line fragments that may be buffered
@@ -903,9 +999,8 @@ uty_term_write(vio_vf vf)
* even if the fifo is empty -- this deals with any parts of a complete
* line that may be held in the line control due to counter exhaustion.
*
- * If the fifo is or becomes empty, then if is cli->flush, flush out any
- * incomplete line which may be held in the line control -- in effect,
- * cli->flush is a phantom '\n' at the end of the output fifo !
+ * If the fifo is or becomes empty, then if the command has completed, flush
+ * out any incomplete line which may be held in the line control.
*/
vio_fifo_set_hold_mark(vf->obuf) ; /* released in uty_term_write_lc() */
@@ -923,7 +1018,7 @@ uty_term_write(vio_vf vf)
break ;
} ;
- if ((have == 0) && !cli->in_progress)
+ if ((have == 0) && (cli->state == cst_complete))
vio_lc_flush(cli->olc) ;
ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ;
@@ -957,25 +1052,23 @@ uty_term_write(vio_vf vf)
/* Exciting stuff: there is nothing left to output...
*
* ...with the sole possible exception of an incomplete line buffered
- * in the line control, which can do nothing about until there is more
- * to be output, or the output is flushed...
+ * in the line control -- if not cst_complete.
*
- * ...if not cli->flush, we are stopped, waiting for something else to
- * happen.
+ * ...if is cst_complete, all output has gone, so can fall back to cos_idle.
*/
- qassert(!cli->more_wait && !cli->more_enter) ;
-
- if (cli->in_progress)
- return utw_done ; /* can do no more */
+ qassert(cli->out_state = cos_active) ;
- /* Even more exciting: is !cli->in_progress !
- *
- * This means that any incomplete line must have been flushed, above.
- * So all buffers MUST be empty.
- */
- qassert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ;
+ if (cli->state == cst_complete)
+ {
+ /* Even more exciting: is cst_complete
+ *
+ * This means that any incomplete line must have been flushed, above.
+ * So all buffers MUST be empty.
+ */
+ qassert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ;
- cli->out_active = false ;
+ cli->out_state = cos_idle ;
+ } ;
return utw_done ; /* absolutely all done */
} ;
diff --git a/lib/vty_io_term.h b/lib/vty_io_term.h
index 78d37b18..ac5620e3 100644
--- a/lib/vty_io_term.h
+++ b/lib/vty_io_term.h
@@ -56,14 +56,16 @@
extern void uty_term_new(vty_io vio, int sock_fd) ;
extern cmd_return_code_t uty_term_fetch_command_line(vio_vf vf,
- cmd_action action, cmd_context context) ;
+ cmd_action action) ;
+extern void uty_term_cmd_complete(vio_vf vf, cmd_context context) ;
extern cmd_return_code_t uty_term_out_push(vio_vf vf, bool final) ;
+extern void uty_term_out_cancelled(vio_vf vf) ;
extern uint uty_term_show_error_context(vio_vf vf, vio_fifo ebuf, uint depth) ;
extern cmd_return_code_t uty_term_read_close(vio_vf vf, bool final) ;
extern void uty_term_close_reason(vio_vf vf, const char* reason) ;
extern cmd_return_code_t uty_term_write_close(vio_vf vf, bool final);
-extern int uty_term_read(vio_vf vf) ;
+extern void uty_term_read(vio_vf vf) ;
extern void uty_term_set_readiness(vio_vf vf, vty_readiness_t ready) ;
extern qtimer_action vty_term_pause_timeout ;