diff options
author | Chris Hall <chris.hall@highwayman.com> | 2011-07-21 19:53:02 +0100 |
---|---|---|
committer | Chris Hall <chris.hall@highwayman.com> | 2011-07-21 19:53:02 +0100 |
commit | 56da2a1c9b6361e302b7a39fe2740561a9012d88 (patch) | |
tree | 6b6543532133a0c618d0f4ec70a87cf3f96caf30 /lib/vty_io_term.c | |
parent | e535bc959729262480a9702e71334002edee3f8c (diff) | |
download | quagga-56da2a1c9b6361e302b7a39fe2740561a9012d88.tar.bz2 quagga-56da2a1c9b6361e302b7a39fe2740561a9012d88.tar.xz |
Update pipework and improve memory reporting.
Improve error handling for all new pipework inputs and outputs.
Change behaviour of ^C from VTY Terminal, so that will interrupt
output and terminate all running pipes -- including running
shell commands.
In pipe commands, recognise "~/..." and "~user/..." home directory
forms.
Changed "~/" to mean the usual home for the current user. "~~/"
now means the configuration file directory.
Introduced "shdir DIR" command to show what is (currently) what.
Changed "<|" so that if the command has a path, it is expanded
using Quagga's rules (including "~~/" and "~./") and the
"here" directory is set to that path.
Fixed collection of stderr output from all pipes so that is
separate from stdout output, and is always sent to the base
output (eg VTY Terminal).
Increase amount of information about the heap that "show mem"
shows -- particularly if the "memory_tracker" is enabled.
Tested and applied resulting fixes.
Diffstat (limited to 'lib/vty_io_term.c')
-rw-r--r-- | lib/vty_io_term.c | 489 |
1 files changed, 271 insertions, 218 deletions
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c index 857e457a..61f35761 100644 --- a/lib/vty_io_term.c +++ b/lib/vty_io_term.c @@ -54,16 +54,9 @@ * is closed either on command, or on timeout, or when the daemon is reset * or terminated. * - * - * - * + * All VIN_TERM and VOUT_TERM I/O is non-blocking. */ - - - - - /*============================================================================== * If possible, will use getaddrinfo() to find all the things to listen on. */ @@ -77,20 +70,26 @@ * Opening and closing VTY_TERMINAL type */ -typedef enum { - utw_error = 0, - utw_done = BIT(0), /* all possible is done */ - utw_stopped = BIT(1), - utw_blocked = BIT(2), /* I/O blocked */ - utw_paused = utw_blocked | utw_stopped, -} utw_ret_t ; - static void uty_term_read_ready(vio_vfd vfd, void* action_info) ; static void uty_term_write_ready(vio_vfd vfd, void* action_info) ; static vty_timer_time uty_term_read_timeout(vio_timer timer, void* action_info) ; static vty_timer_time uty_term_write_timeout(vio_timer timer, void* action_info) ; + +typedef enum { /* see uty_term_write() */ + utw_null = 0, + + utw_error, + + utw_done, + + utw_blocked, + utw_paused, + utw_more_enter, + +} utw_ret_t ; + static utw_ret_t uty_term_write(vio_vf vf) ; static void uty_term_will_echo(vty_cli cli) ; @@ -162,11 +161,11 @@ uty_term_open(int sock_fd, union sockunion *su) 0) ; /* no ibuf required */ uty_vout_push(vio, vf, VOUT_TERM, uty_term_write_ready, uty_term_write_timeout, - 4096) ; /* obuf is required */ - - uty_vout_sync_depth(vio) ; /* vin & vout are at same level */ + 4096, /* obuf is required */ + true) ; /* after buddy vin */ - vf->read_timeout = host.vty_timeout_val ; /* current EXEC timeout */ + vf->read_timeout = host.vty_timeout_val ; /* current EXEC timeout */ + vf->write_timeout = 30 ; /* something reasonable */ /* Set up the CLI object & initialise */ vf->cli = uty_cli_new(vf) ; @@ -194,25 +193,33 @@ uty_term_open(int sock_fd, union sockunion *su) vty_out(vty, "%% Cannot continue because no password is set\n") ; /* Enter the command loop. */ - uty_cmd_loop_enter(vio) ; + uty_cmd_queue_loop_enter(vio) ; } ; /*------------------------------------------------------------------------------ - * Command line fetch from a VTY_TERMINAL. + * Command line fetch from a VTY_TERMINAL -- in vf_open state. * * Fetching a command line <=> the previous command has completed. * - * Returns: CMD_SUCCESS -- have another command line ready to go - * CMD_WAITING -- would not wait for input <=> non-blocking - * CMD_EOF -- ?????? + * Returns: CMD_SUCCESS -- have another command line ready to go + * or: CMD_WAITING -- would not wait for input * * This can be called in any thread. * - * NB: this does not signal CMD_EOF TODO ???? + * Note that does not signal CMD_EOF because that is handled for the + * VTY_TERMINAL by the cmd_do_eof "special command". + * + * Note that this does no actual I/O, all that is done in the pselect() process, + * while a command line is collected in the CLI. So does not here return + * 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) { + VTY_ASSERT_LOCKED() ; + + qassert(vf->vin_state == vf_open) ; + return uty_cli_want_command(vf->cli, action, context) ; } ; @@ -243,14 +250,18 @@ uty_term_show_error_context(vio_vf vf, vio_fifo ebuf, uint depth) } ; /*------------------------------------------------------------------------------ - * Push output to the terminal. + * Push output to the terminal -- always not vf->blocking ! * - * Returns: CMD_SUCCESS -- all buffers are empty - * CMD_WAITING -- all buffers are not empty - * CMD_IO_ERROR -- failed -- final or not. + * Returns: CMD_SUCCESS -- done everything possible + * CMD_WAITING -- not "final" => waiting for output to complete + * "final" => would have waited but did not. + * CMD_IO_ERROR -- error or time-out (may be "final") + * + * This can be called in any thread. * - * This can be called in any thread. If "final" will not turn on any - * read/write ready stuff. + * Note that CMD_WAITING requires no further action from the caller, the + * background pselect process will complete the output and may signal the + * result via uty_cmd_signal(). */ extern cmd_return_code_t uty_term_out_push(vio_vf vf, bool final) @@ -258,8 +269,17 @@ uty_term_out_push(vio_vf vf, bool final) vty_cli cli = vf->cli ; utw_ret_t done ; - /* 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. + qassert(vf->vout_state == vf_open) ; + qassert(!vf->blocking) ; + + /* If squelching, dump 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 (!cli->out_active && !vio_fifo_empty(vf->obuf)) { @@ -271,34 +291,39 @@ uty_term_out_push(vio_vf vf, bool final) /* Give the terminal writing a shove. * * If final, keep pushing while succeeds in writing without blocking. + * + * Note that is only called "final" when closing the vout, by which time + * the "--more--" handling has been turned off and any output has been + * released. */ - if (final) - cli->flush = cli->out_active ; /* make sure empty everything */ - - do - { - if (final) - vio_lc_counter_reset(cli->olc) ; - - done = uty_term_write(vf) ; - } - while (final && (done == utw_paused)) ; - if (!final) + done = uty_term_write(vf) ; + else { - if (done == utw_error) - return CMD_IO_ERROR ; /* TODO */ - - if ((done & utw_blocked) != 0) + do { - confirm((utw_paused & utw_blocked) != 0) ; - - uty_term_set_readiness(vf, write_ready) ; - return CMD_WAITING ; - } ; + vio_lc_counter_reset(cli->olc) ; + done = uty_term_write(vf) ; + } while (done == utw_paused) ; } ; - return CMD_SUCCESS ; + /* 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. + * + * 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) ; + + return CMD_WAITING ; /* waiting for write ready */ } ; /*------------------------------------------------------------------------------ @@ -319,14 +344,14 @@ uty_term_read_close(vio_vf vf, bool final) { vty_io vio ; + qassert(vf->vin_state == vf_end) ; + /* Get the vio and ensure that we are all straight */ vio = vf->vio ; - assert((vio->vin == vio->vin_base) && (vio->vin == vf)) ; - assert(vio->vin->vin_state == vf_closing) ; + qassert((vio->vin == vio->vin_base) && (vio->vin == vf)) ; - /* - */ - uty_set_monitor(vio, 0) ; + /* Kill monitor state */ + uty_set_monitor(vio, off) ; /* Close the CLI as far as possible, leaving output side intact. * @@ -335,11 +360,6 @@ uty_term_read_close(vio_vf vf, bool final) */ uty_cli_close(vf->cli, false) ; - /* Log closing of VTY_TERMINAL - */ - assert(vio->vty->type == VTY_TERMINAL) ; - zlog (NULL, LOG_INFO, "Vty connection (fd %d) close", vio_vfd_fd(vf->vfd)) ; - return CMD_SUCCESS ; } ; @@ -355,7 +375,8 @@ extern void uty_term_close_reason(vio_vf vf, const char* reason) { vio_lc_clear(vf->cli->olc) ; - vio_fifo_clear(vf->cli->cbuf, true) ; + + vf->cli->mon_active = false ; /* stamp on any monitor output */ uty_cli_out(vf->cli, "%% %s%s", reason, uty_cli_newline) ; } ; @@ -364,56 +385,77 @@ uty_term_close_reason(vio_vf vf, const char* reason) * Close the writing side of VTY_TERMINAL. * * Assumes that the read side has been closed already, and so this is the last - * thing to be closed. + * thing to be closed. Any monitor state was turned off earlier when the read + * side was closed. * * Kicks the output side: * - * if final, will push as much as possible until would block. + * if final, will push as much as possible until all gone, would block or + * gets error. In any event, closes the cli, final. * * if not final, will push another tranche and let the uty_term_ready() keep * pushing until buffers empty and can uty_cmd_signal(). * - * Returns: CMD_SUCCESS => all written (or final) and CLI closed. - * CMD_WAITING => write ready running to empty the buffers - * CMD_IO_ERROR => - * others TODO + * Returns: CMD_SUCCESS => all written, + * or cannot write anything (more), + * or final and wrote what could + * CMD_WAITING -- not "final" => waiting for output to complete + * "final" => would have waited but did not. + * + * NB: if an error occurs while writing, that will have been logged, but there + * is nothing more to be done about it here -- so does not return + * CMD_IO_ERROR. */ extern cmd_return_code_t -uty_term_write_close(vio_vf vf, bool final, bool base) +uty_term_write_close(vio_vf vf, bool final) { cmd_return_code_t ret ; vty_io vio ; + VTY_ASSERT_LOCKED() ; + /* Get the vio and ensure that we are all straight * * Can only be the vout_base and must also be the vin_base, and the vin_base * must now be closed. */ vio = vf->vio ; - assert((vio->vout == vio->vout_base) && (vio->vout == vf)) ; - assert((vio->vin == vio->vin_base) && (vio->vin->vin_state == vf_closed)) ; + qassert((vio->vout == vio->vout_base) && (vio->vout == vf)) ; + qassert((vio->vin == vio->vin_base) && (vio->vin->vin_state == vf_closed)) ; + + ret = CMD_SUCCESS ; + + if (vf->vout_state == vf_open) + { + ret = uty_term_out_push(vf, final) ; - ret = uty_term_out_push(vf, final) ; + if (ret != CMD_WAITING) + ret = CMD_SUCCESS ; + } ; if (final) - vf->cli = uty_cli_close(vf->cli, final) ; + { + vf->cli = uty_cli_close(vf->cli, final) ; + + qassert(vio->vty->type == VTY_TERMINAL) ; + zlog (NULL, LOG_INFO, "Vty connection (fd %d) close", + vio_vfd_fd(vf->vfd)) ; + } ; return ret ; } ; /*============================================================================== - * Action routines for VIN_TERM/VOUT_TERM type vin/vout objects - */ - -/*============================================================================== * Readiness and the VIN_TERM type vin. * * For TERM stuff the driving force is write ready. This is used to prompt the * VOUT_TERM when there is outstanding output (obviously), but also if there * is buffered input in the keystroke stream. * - * The VIN_TERM uses read ready only when it doesn't set write ready. Does - * not set both at once. + * The VIN_TERM is read ready permanently, until eof is met. Note that the + * read timeout is reset each time uty_term_set_readiness is called. When + * eof is met, the VIN_TERM is read closed, which prevents any further setting + * of read ready and its timeout. */ static void uty_term_ready(vio_vf vf) ; @@ -421,17 +463,17 @@ static void uty_term_ready(vio_vf vf) ; /*------------------------------------------------------------------------------ * Set read/write readiness -- for VIN_TERM/VOUT_TERM * - * Note that sets only one of read or write, and sets write for preference. + * Is permanently read-ready (until eof or no longer vin_state == vf_open). */ extern void uty_term_set_readiness(vio_vf vf, vty_readiness_t ready) { VTY_ASSERT_LOCKED() ; - if ((ready & write_ready) != 0) + if ((ready & write_ready) != 0) uty_vf_set_write(vf, on) ; - else if ((ready & read_ready) != 0) - uty_vf_set_read(vf, on) ; + + uty_vf_set_read(vf, on) ; } ; /*------------------------------------------------------------------------------ @@ -442,9 +484,11 @@ uty_term_read_ready(vio_vfd vfd, void* action_info) { vio_vf vf = action_info ; - assert(vfd == vf->vfd) ; + qassert(vfd == vf->vfd) ; vf->cli->paused = false ; /* read ready clears paused */ + + uty_term_read(vf) ; uty_term_ready(vf) ; } ; @@ -456,7 +500,7 @@ uty_term_write_ready(vio_vfd vfd, void* action_info) { vio_vf vf = action_info ; - assert(vfd == vf->vfd) ; + qassert(vfd == vf->vfd) ; uty_term_ready(vf) ; } ; @@ -501,25 +545,25 @@ static void uty_term_ready(vio_vf vf) { vty_readiness_t ready ; - utw_ret_t done ; - bool signal ; + utw_ret_t done, done_before ; VTY_ASSERT_LOCKED() ; - /* Start by trying to write away any outstanding stuff, and then another - * tranche of any outstanding output. + /* Will attempt to write away any pending stuff, then for each call of + * uty_term_ready, put out another tranche of output (unless in '--more--' + * state). */ - ready = not_ready ; - if (!vf->cli->more_enabled) vio_lc_counter_reset(vf->cli->olc) ; /* do one tranche */ - done = uty_term_write(vf) ; - signal = ((done == utw_done) || (done == utw_stopped)) ; - - while (done != utw_error) + /* Now loop kicking the CLI and the output, until stops changing. + * + * This is because the CLI may generate more to write, and writing stuff + * away may release the CLI. + */ + done = utw_null ; + do { - utw_ret_t done_before ; done_before = done ; /* Kick the CLI, which may advance either because there is more input, @@ -532,59 +576,45 @@ uty_term_ready(vio_vf vf) /* Now try to write away any new output which may have been generated * by the CLI. + * + * Note that when enters "--more--" will return utw_more_enter, once, + * which causes a loop back to uty_cli(), which will start the process. + * When comes through here a second time, will return utw_done, once + * any prompt etc has been output. */ done = uty_term_write(vf) ; - if (done == done_before) - break ; /* quit if no change in response */ - - if ((done == utw_done) || (done == utw_stopped)) - signal = true ; - } ; - - if (done == utw_error) - ; /* TODO !! */ + if (done == utw_error) + return ; /* quit if in error */ - if ((done & utw_blocked) != 0) - { - confirm((utw_paused & utw_blocked) != 0) ; - ready |= write_ready ; - } ; + } while (done != done_before) ; - if ((done != utw_blocked) && (done != utw_error)) - { - /* Since is not output blocked, tell master that is now ready. */ - if (vf->pr_master != NULL) - uty_pipe_return_slave_ready(vf) ; - } ; + if (done != utw_done) /* isn't utw_error, either */ + ready |= write_ready ; uty_term_set_readiness(vf, ready) ; - /* Signal the command loop if out_active and the buffers empty out. + /* Signal the command loop if not waiting for write any more. */ - if (signal) + if ((ready & write_ready) == 0) uty_cmd_signal(vf->vio, CMD_SUCCESS) ; } ; /*------------------------------------------------------------------------------ * Read timer has expired. * - * If closing, then this is curtains -- have waited long enough ! - * - * TODO .... sort out the VTY_TERMINAL time-out & death-watch timeout - * - * Otherwise, half close the VTY and leave it to the death-watch to sweep up. + * Discard anything in the keystroke stream and set it "eof, timed-out". This + * will be picked up by the CLI and a cmd_do_timed-out will float out. */ static vty_timer_time uty_term_read_timeout(vio_timer timer, void* action_info) { vio_vf vf = action_info ; - assert(timer == vf->vfd->read_timer) ; + qassert(timer == vf->vfd->read_timer) ; VTY_ASSERT_LOCKED() ; - vf->vin_state = vf_timed_out ; keystroke_stream_set_eof(vf->cli->key_stream, true) ; /* timed out */ vf->cli->paused = false ; @@ -597,24 +627,20 @@ uty_term_read_timeout(vio_timer timer, void* action_info) /*------------------------------------------------------------------------------ * Write timer has expired. * - * If closing, then this is curtains -- have waited long enough ! - * - * TODO .... sort out the VTY_TERMINAL time-out & death-watch timeout - * - * Otherwise, half close the VTY and leave it to the death-watch to sweep up. + * Signal write timeout error. */ static vty_timer_time uty_term_write_timeout(vio_timer timer, void* action_info) { vio_vf vf = action_info ; - assert(timer == vf->vfd->read_timer) ; + qassert(timer == vf->vfd->write_timer) ; VTY_ASSERT_LOCKED() ; vf->cli->paused = false ; -//uty_close(vio, true, qs_set(NULL, "Timed out")) ; TODO + uty_vf_error(vf, verr_to_vout, 0) ; return 0 ; } ; @@ -650,38 +676,69 @@ vty_term_pause_timeout(qtimer qtr, void* timer_info, qtime_mono_t when) /*------------------------------------------------------------------------------ * Read a lump of bytes and shovel into the keystroke stream * - * This function is called from the vty_cli to top up the keystroke buffer, - * or in the stealing of a keystroke to end "--more--" state. - * * 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. * - * Steal keystroke if required -- see keystroke_input() + * 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. + * + * 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 + * any further setting of read_ready (to avoid permanent read_ready !). Does + * 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 => EOF (or not open, or failed, or timed out, ...) + * == -1 => I/O error + * == -2 => hit EOF (without reading anything else) */ extern int -uty_term_read(vio_vf vf, keystroke steal) +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 */ + if (vf->vin_state != vf_open) - return -1 ; /* at EOF if not open */ + { + /* If is not vf_open, but also not seen EOF on the keystroke stream, + * then now is a good moment to empty out the keystroke stream and + * force it to EOF. + */ + keystroke_stream_set_eof(vf->cli->key_stream, false) ; + return -2 ; + } ; + /* OK: read from input and pass result to keystroke stream. + */ get = read_nb(vio_vfd_fd(vf->vfd), buf, sizeof(buf)) ; - if (get >= 0) - keystroke_input(vf->cli->key_stream, buf, get, steal) ; - else if (get < 0) + /* -1 <=> error, -2 <=> EOF */ + if (get != 0) { if (get == -1) - uty_vf_error(vf, "read", errno) ; + { + /* 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 */ + } + else + { + /* Not error. get < 0 => EOF and that is set in key_stream. */ + keystroke_input(vf->cli->key_stream, buf, get) ; + } ; - keystroke_input(vf->cli->key_stream, NULL, 0, steal) ; - /* Tell keystroke stream that EOF met */ - get = -1 ; + if (get < 0) + vio_vfd_read_close(vf->vfd) ; } ; return get ; @@ -719,59 +776,40 @@ uty_term_mon_write(vio_vf vf) uty_cli_pre_monitor(vf->cli) ; /* make sure in a fit state */ - done = uty_term_write(vf) ; /* TODO -- errors !! */ - - if ((done & utw_blocked) != 0) - { - confirm((utw_paused & utw_blocked) != 0) ; - - uty_term_set_readiness(vf, write_ready) ; - } ; + done = uty_term_write(vf) ; /* this calls uty_vf_error() if + * there are any errors */ + if ((done != utw_done) && (done != utw_error)) + uty_term_set_readiness(vf, write_ready) ; } ; /*------------------------------------------------------------------------------ * Write as much as possible of what there is. * - * Move to more_wait if required. TODO + * Move to more_wait if required. * * If is cli->flush, then when all buffers are emptied out, clears itself and * the out_active flag. * * Returns: * - * utw_error -- I/O error -- see errno (utw_error = -1) - * - * utw_blocked -- write blocked -- some write operation would block + * utw_error -- I/O error either now or sometime earlier. * - * utw_paused -- have written as much as line control allows in one go. + * utw_done -- have written everything can find * - * NB: this does NOT mean is now in more_wait, it means that - * to write more it is necessary to clear the line - * control pause state. + * utw_blocked -- write blocked -- some write operation would block * - * utw_stopped -- have done as much as can do -- no more output is possible - * until some external event changes things. + * Need to set write ready & wait for it. * - * This implies that any pending output has completed, in - * particular the line control iovec and the cli->cbuf are - * both empty. + * utw_paused -- have written as much as line control allows in one go. * - * This state includes: + * Note that is *not* in "--more--" state, this is all to + * do with limiting work on each visit. * - * * !out_active -- if there is something in the vf->obuf, - * we are not yet ready to output it. + * Need to set write ready & wait for it. * - * * more_wait -- waiting for user + * utw_more_enter -- has just entered "--more--" state * - * utw_done -- have written everything can find, unless more output - * arrives, there is no more to do. - * - * If was cli->flush the all output really has gone, as - * well as any incomplete line. Also the out_active and - * the flush flags will have been cleared. - * - * If was not cli->flush, the out_active state persists, - * and there may be an incomplete line still pending. + * Need either to set write ready, or call the CLI. */ static utw_ret_t uty_term_write(vio_vf vf) @@ -783,33 +821,44 @@ uty_term_write(vio_vf vf) VTY_ASSERT_LOCKED() ; - /* If the vout is neither vf_open, not vf_closing, discard all buffered + /* If the vout is neither vf_open nor vf_closing, discard all buffered * output, and return all done. */ - if ((vf->vout_state != vf_open) && (vf->vout_state != vf_closing)) + if (vf->vout_state != vf_open) { + qassert(vf->vout_state == vf_end) ; + vio_fifo_clear(vf->obuf, false) ; vio_fifo_clear(cli->cbuf, false) ; vio_lc_clear(cli->olc) ; cli->out_active = false ; - cli->flush = false ; cli->more_wait = false ; cli->more_enter = false ; - return utw_done ; + return utw_error ; } ; /* Any outstanding line control output takes precedence */ - ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ; - if (ret != utw_done) - return ret ; /* utw_blocked or utw_error */ + if (vio_lc_pending(cli->olc)) + { + ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ; + if (ret != utw_done) + return ret ; /* utw_blocked or utw_error */ + } ; /* Next: empty out the cli output */ did = vio_fifo_write_nb(cli->cbuf, vio_vfd_fd(vf->vfd), true) ; - if (did != 0) - return (did < 0) ? utw_error : utw_blocked ; + + if (did > 0) + return utw_blocked ; + + if (did < 0) + { + uty_vf_error(vf, verr_io_vout, errno) ; + return utw_error ; + } ; /* Next: if there is monitor output to deal with, deal with it. * @@ -827,20 +876,23 @@ uty_term_write(vio_vf vf) LOG_UNLOCK() ; - if (did != 0) - return (did < 0) ? utw_error : utw_blocked ; + if (did > 0) + return utw_blocked ; + + if (did < 0) + { + uty_vf_error(vf, verr_io_vout, errno) ; + return utw_error ; + } ; uty_cli_post_monitor(vf->cli) ; } ; - /* If not out_active, or in more_wait, then we are stopped, waiting for some + /* If not out_active, or in more_wait, then we are done, waiting for some * external event to move things on. */ - if (cli->flush) - assert(cli->out_active) ; /* makes no sense, otherwise */ - - if (!cli->out_active || cli->more_wait) - return utw_stopped ; + if ((!cli->out_active) || (cli->more_wait)) + return utw_done ; /* can do no more */ /* Push the output fifo and any complete line fragments that may be buffered * in hand in the line control -- this will stop if the line counter becomes @@ -870,7 +922,7 @@ uty_term_write(vio_vf vf) break ; } ; - if ((have == 0) && (cli->flush)) + if ((have == 0) && !cli->in_progress) vio_lc_flush(cli->olc) ; ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ; @@ -890,12 +942,12 @@ uty_term_write(vio_vf vf) */ if ((have != 0) || vio_lc_have_complete_line_in_hand(cli->olc)) { - assert(vio_lc_counter_is_exhausted(cli->olc)) ; + qassert(vio_lc_counter_is_exhausted(cli->olc)) ; if (cli->more_enabled) { uty_cli_enter_more_wait(cli) ; - return utw_stopped ; + return utw_more_enter ; } else return utw_paused ; /* artificial block */ @@ -910,22 +962,21 @@ uty_term_write(vio_vf vf) * ...if not cli->flush, we are stopped, waiting for something else to * happen. */ - assert(!cli->more_wait && !cli->more_enter) ; + qassert(!cli->more_wait && !cli->more_enter) ; - if (!cli->flush) - return utw_stopped ; + if (cli->in_progress) + return utw_done ; /* can do no more */ - /* Even more exciting: is cli->flush ! + /* Even more exciting: is !cli->in_progress ! * * This means that any incomplete line must have been flushed, above. * So all buffers MUST be empty. */ - assert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ; + qassert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ; cli->out_active = false ; - cli->flush = false ; - return utw_done ; + return utw_done ; /* absolutely all done */ } ; /*------------------------------------------------------------------------------ @@ -937,7 +988,7 @@ uty_term_write(vio_vf vf) * * Returns: utw_blocked => blocked * utw_done => all gone (may still have stuff "in hand") - * utw_error => failed + * utw_error => failed -- error posted to uty_vf_error() */ static utw_ret_t uty_term_write_lc(vio_line_control lc, vio_vf vf, vio_fifo vff) @@ -946,7 +997,9 @@ uty_term_write_lc(vio_line_control lc, vio_vf vf, vio_fifo vff) did = vio_lc_write_nb(vio_vfd_fd(vf->vfd), lc) ; - if (did > 0) + if (did < 0) + uty_vf_error(vf, verr_io_vout, errno) ; + else if (did > 0) return utw_blocked ; vio_fifo_clear_hold_mark(vff) ; /* finished with FIFO contents */ @@ -1032,7 +1085,7 @@ uty_term_listen_addrinfo(const char *addr, unsigned short port) if ((ainfo->ai_family != AF_INET) && (ainfo->ai_family != AF_INET6)) continue; - assert(ainfo->ai_family == ainfo->ai_addr->sa_family) ; + qassert(ainfo->ai_family == ainfo->ai_addr->sa_family) ; ret = uty_term_listen_open(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol, ainfo->ai_addr, port) ; @@ -1498,8 +1551,8 @@ uty_telnet_command(vio_vf vf, keystroke stroke, bool callback) p = stroke->buf ; left = stroke->len ; - passert(left >= 1) ; /* must be if not broken ! */ - passert(stroke->value == *p) ; /* or something is wrong */ + qassert(left >= 1) ; /* must be if not broken ! */ + qassert(stroke->value == *p) ; /* or something is wrong */ ++p ; /* step past X of IAC X */ --left ; @@ -1508,7 +1561,7 @@ uty_telnet_command(vio_vf vf, keystroke stroke, bool callback) switch (stroke->value) { case tn_SB: - passert(left > 0) ; /* or parser failed */ + qassert(left > 0) ; /* or parser failed */ o = *p++ ; /* the option byte */ --left ; |