summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/list_util.h140
-rw-r--r--lib/qrand.c9
-rw-r--r--lib/qrand.h4
-rw-r--r--lib/vector.c2
-rw-r--r--lib/vty_command.c61
-rw-r--r--lib/vty_io.c60
-rw-r--r--lib/vty_io.h4
-rw-r--r--lib/vty_io_basic.c54
-rw-r--r--lib/vty_io_basic.h3
-rw-r--r--lib/vty_io_term.c8
-rw-r--r--lib/vty_io_vtysh.c9
11 files changed, 264 insertions, 90 deletions
diff --git a/lib/list_util.h b/lib/list_util.h
index 19183760..23677cd5 100644
--- a/lib/list_util.h
+++ b/lib/list_util.h
@@ -512,14 +512,18 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
*
* ddl_in_after(after, base, item, list) -- insert after
*
- * Treat as void function. The after & item may *not* be NULL.
+ * Treat as void function. The item may *not* be NULL.
+ *
+ * If after == NULL, insert item at the end of the current list.
*
* Undefined if item is already on any list (including this one), or if
* after is not on the list.
*
* ddl_in_before(before, base, item, list) -- insert before
*
- * Treat as void function. The before & item may *not* be NULL.
+ * Treat as void function. The item may *not* be NULL.
+ *
+ * If before == NULL, insert item at the start of the current list.
*
* Undefined if item is already on any list (including this one), or if
* before is not on the list.
@@ -570,6 +574,24 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
*
* Treat as function returning void*. Returns NULL if the item is NULL.
*
+ * ddl_slice(base, sub, list) -- remove sublist from given list
+ *
+ * Treat as void function. Does nothing if the sublist is empty.
+ *
+ * ddl_splice_after(after, base, sub, list)
+ * -- insert sublist after given item
+ *
+ * Treat as void function. Does nothing if the sublist is empty.
+ *
+ * If after == NULL, insert sublist at the end of the current list.
+ *
+ * ddl_splice_before(before, base, sub, list)
+ * -- insert sublist before given item
+ *
+ * Treat as void function. Does nothing if the sublist is empty.
+ *
+ * If before == NULL, insert sublist at the start of the current list.
+ *
* Note that ddl_del() and ddl_pop() do NOT affect the item->list.next
* or item->list.prev pointers.
*
@@ -577,7 +599,7 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
*
* "base" to be an r-value of type: struct base_pair(struct item*)*
*
- * That is... a variable or field which is a pointer to
+ * That is... a variable or field which is a pointer pair.
*
* "item" to be an l-value of type struct item*
*
@@ -586,7 +608,9 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
* "list" to be the name of a field in struct item
* of type: struct list_pair(struct item*)
*
+ * "sub" to be an r-value of type: struct base_pair(struct item*)*
*
+ * That is... a variable or field which is a pointer pointer pair.
*
*------------------------------------------------------------------------------
* For example:
@@ -672,23 +696,33 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
} while (0)
#define ddl_in_after(after, base, item, list) \
- do { (item)->list.next = (after)->list.next ; \
- (item)->list.prev = (after) ; \
- if ((after)->list.next != NULL) \
- (after)->list.next->list.prev = (item) ; \
+ do { if (after != NULL) \
+ { \
+ (item)->list.next = (after)->list.next ; \
+ (item)->list.prev = (after) ; \
+ if ((after)->list.next != NULL) \
+ (after)->list.next->list.prev = (item) ; \
+ else \
+ (base).tail = (item) ; \
+ (after)->list.next = (item) ; \
+ } \
else \
- (base).tail = (item) ; \
- (after)->list.next = (item) ; \
+ ddl_append(base, item, list) ; \
} while (0)
#define ddl_in_before(before, base, item, list) \
- do { (item)->list.next = (before) ; \
- (item)->list.prev = (before)->list.prev ; \
- if ((before)->list.prev != NULL) \
- (before)->list.prev->list.next = (item) ; \
+ do { if (before != NULL) \
+ { \
+ (item)->list.next = (before) ; \
+ (item)->list.prev = (before)->list.prev ; \
+ if ((before)->list.prev != NULL) \
+ (before)->list.prev->list.next = (item) ; \
+ else \
+ (base).head = (item) ; \
+ (before)->list.prev = (item) ; \
+ } \
else \
- (base).head = (item) ; \
- (before)->list.prev = (item) ; \
+ ddl_push(base, item, list) ; \
} while (0)
#define ddl_del(base, item, list) \
@@ -751,6 +785,82 @@ Private bool ssl_del_func(void** p_prev, void* item, size_t link_offset)
#define ddl_prev(item, list) \
((item) != NULL ? (item)->list.prev : NULL)
+#define ddl_slice(base, sub, list) \
+ do { if ((sub).head != NULL) \
+ { \
+ if ((sub).head->list.prev != NULL) \
+ (sub).head->list.prev->list.next = (sub).tail->list.next ; \
+ else \
+ { \
+ qassert((sub).head == (base).head) ; \
+ (base).head = (sub).tail->list.next ; \
+ } ; \
+ \
+ if ((sub).tail->list.next != NULL) \
+ (sub).tail->list.next->list.prev = (sub).head->list.prev ; \
+ else \
+ { \
+ qassert((sub).tail == (base).tail) ; \
+ (base).tail = (sub).head->list.prev ; \
+ } ; \
+ \
+ (sub).head->list.prev = NULL ; \
+ (sub).tail->list.next = NULL ; \
+ } \
+ } while (0)
+
+#define ddl_splice_after(after, base, sub, list) \
+ do { if ((sub).head != NULL) \
+ { \
+ if (after != NULL) \
+ { \
+ (sub).head->list.prev = (after) ; \
+ (sub).tail->list.next = (after)->list.next ; \
+ if ((after)->list.next != NULL) \
+ (after)->list.next->list.prev = (sub).tail ; \
+ else \
+ (base).tail = (sub).tail ; \
+ (after)->list.next = (sub).head ; \
+ } \
+ else \
+ { \
+ (sub).head->list.prev = (base).tail ; \
+ (sub).tail->list.next = NULL ; \
+ if ((base).tail != NULL) \
+ (base).tail->list.next = (sub).head ; \
+ else \
+ (base).head = (sub).head ; \
+ (base).tail = (sub).tail ; \
+ } ; \
+ } \
+ } while (0)
+
+#define ddl_splice_before(before, base, sub, list) \
+ do { if ((sub).head != NULL) \
+ { \
+ if (before != NULL) \
+ { \
+ (sub).tail->list.next = (before) ; \
+ (sub).head->list.prev = (before)->list.prev ; \
+ if ((before)->list.prev != NULL) \
+ (before)->list.prev->list.next = (sub).head ; \
+ else \
+ (base).head = (sub).head ; \
+ (before)->list.prev = (sub).tail ; \
+ } \
+ else \
+ { \
+ (sub).tail->list.next = (base).head ; \
+ (sub).head->list.prev = NULL ; \
+ if ((base).head != NULL) \
+ (base).head->list.prev = (sub).tail ; \
+ else \
+ (base).tail = (sub).tail ; \
+ (base).head = (sub).head ; \
+ } ; \
+ } \
+ } while (0)
+
/*==============================================================================
* Double Base, Single Link
*
diff --git a/lib/qrand.c b/lib/qrand.c
index 402bb432..a395b92c 100644
--- a/lib/qrand.c
+++ b/lib/qrand.c
@@ -32,17 +32,16 @@
*
* If range == 1, returns 0 every time !
*/
-extern int
-qrand(qrand_seq seq, int range)
+extern uint
+qrand(qrand_seq seq, uint range)
{
uint64_t r ;
- r = seq->last ^ 3141592653 ;
- r = ((r * 2650845021) + 5) & 0xFFFFFFFF ; /* see Knuth */
+ r = ((seq->last * 2650845021) + 5) & 0xFFFFFFFF ; /* see Knuth */
seq->last = r ;
if (range == 0)
return r >> 1 ;
else
- return (r % range) ;
+ return (r * range) >> 32 ;
} ;
diff --git a/lib/qrand.h b/lib/qrand.h
index e9a18436..cb81aceb 100644
--- a/lib/qrand.h
+++ b/lib/qrand.h
@@ -35,7 +35,7 @@
struct qrand_seq
{
- uint last ;
+ uint32_t last ;
} ;
typedef struct qrand_seq* qrand_seq ;
@@ -47,6 +47,6 @@ typedef struct qrand_seq qrand_seq_t[1] ;
* Functions
*/
-extern int qrand(qrand_seq seq, int range) ;
+extern uint qrand(qrand_seq seq, uint range) ;
#endif /* _ZEBRA_QRAND_H */
diff --git a/lib/vector.c b/lib/vector.c
index 09fb1b54..09457aac 100644
--- a/lib/vector.c
+++ b/lib/vector.c
@@ -903,7 +903,7 @@ vector_sak(int to_copy, vector to,
if (n_dst_nulls > 0)
memset(&dst->p_items[dst->end], 0, P_ITEMS_SIZE(n_dst_nulls)) ;
if (n_dst_move > 0)
- memmove(&dst->p_items[i_dst + n_dst], &dst->p_items[i_dst + n_src],
+ memmove(&dst->p_items[i_dst + n_src], &dst->p_items[i_dst + n_dst],
P_ITEMS_SIZE(n_dst_move)) ;
if (n_src_real > 0)
memcpy(&dst->p_items[i_dst], &src->p_items[i_src],
diff --git a/lib/vty_command.c b/lib/vty_command.c
index d55220a6..02897a5a 100644
--- a/lib/vty_command.c
+++ b/lib/vty_command.c
@@ -131,7 +131,7 @@
* Prototypes
*/
static bool uty_cmd_loop_prepare(vty_io vio) ;
-static cmd_ret_t uty_cmd_hiatus(vty_io vio, cmd_ret_t ret) ;
+static cmd_ret_t uty_cmd_hiatus(vty_io vio) ;
static cmd_ret_t vty_cmd_auth(vty vty, node_type_t* p_next_node) ;
static void uty_cmd_out_cancel(vty_io vio) ;
static uint uty_show_error_context(vio_fifo ebuf, vio_vf vf) ;
@@ -1295,9 +1295,6 @@ vty_cmd_hiatus(vty vty, cmd_ret_t ret)
qassert((vio->cl_state == vcl_cq_running) || (vio->cl_state == vcl_running)) ;
- if (vio->state & vst_final)
- return CMD_STOP ; /* it is all over */
-
/* Handle the return code, either:
*
* * nothing further required -- any exception will have updated the
@@ -1306,26 +1303,31 @@ vty_cmd_hiatus(vty vty, cmd_ret_t ret)
* * this is a command or parsing error, for which a vx_quash exception
* must be raised, and suitable error message generated.
*/
- switch (ret)
+ if (vio->state & vst_final)
+ ret = CMD_STOP ; /* it is all over */
+ else
{
- case CMD_SUCCESS:
- case CMD_HIATUS:
- case CMD_WAITING:
- case CMD_STOP:
- case CMD_CANCEL:
- case CMD_IO_ERROR:
- break ;
+ switch (ret)
+ {
+ case CMD_SUCCESS:
+ case CMD_HIATUS:
+ case CMD_WAITING:
+ case CMD_STOP:
+ case CMD_CANCEL:
+ case CMD_IO_ERROR:
+ break ;
- case CMD_WARNING:
- case CMD_ERROR:
- case CMD_ERR_PARSING:
- case CMD_ERR_NO_MATCH:
- case CMD_ERR_AMBIGUOUS:
- case CMD_ERR_INCOMPLETE:
- default: /* assume some sort of error */
- uty_vio_exception(vio, vx_quash) ;
- uty_cmd_failed(vio, ret) ;
- break ;
+ case CMD_WARNING:
+ case CMD_ERROR:
+ case CMD_ERR_PARSING:
+ case CMD_ERR_NO_MATCH:
+ case CMD_ERR_AMBIGUOUS:
+ case CMD_ERR_INCOMPLETE:
+ default: /* assume some sort of error */
+ uty_vio_exception(vio, vx_quash) ;
+ uty_cmd_failed(vio, ret) ;
+ break ;
+ } ;
} ;
/* The meat of the hiatus -- loop back as required.
@@ -1342,11 +1344,12 @@ vty_cmd_hiatus(vty vty, cmd_ret_t ret)
* position is a little complicated. In particular, changes on the output
* side may affect whether is waiting in the CLI.
*/
- while (1)
+ do
{
vio->signal = CMD_SUCCESS ; /* we are here ! */
- ret = uty_cmd_hiatus(vio, ret) ;
+ if (ret != CMD_STOP)
+ ret = uty_cmd_hiatus(vio) ;
switch (ret)
{
@@ -1384,10 +1387,8 @@ vty_cmd_hiatus(vty vty, cmd_ret_t ret)
default:
zabort("invalid return code from uty_cmd_hiatus") ;
} ;
-
- if (vio->signal == CMD_SUCCESS)
- break ;
- } ;
+ }
+ while (vio->signal != CMD_SUCCESS);
if (ret == CMD_WAITING)
{
@@ -1418,8 +1419,10 @@ vty_cmd_hiatus(vty vty, cmd_ret_t ret)
* pselect() system has moved things forward to).
*/
static cmd_ret_t
-uty_cmd_hiatus(vty_io vio, cmd_ret_t ret)
+uty_cmd_hiatus(vty_io vio)
{
+ cmd_ret_t ret ;
+
/* (1) Do we need to close one or more vin and/or vout, or are we waiting for
* one to close ?
*
diff --git a/lib/vty_io.c b/lib/vty_io.c
index 930ef7dd..ebcdb0a9 100644
--- a/lib/vty_io.c
+++ b/lib/vty_io.c
@@ -353,7 +353,7 @@ uty_close_reason_set(vty_io vio, const char* why, bool replace)
if ((why == NULL) || (*why == '\0'))
vio->close_reason = qs_free(vio->close_reason) ;
else
- vio->close_reason = qs_printf(vio->close_reason, "Terminated: %s", why) ;
+ vio->close_reason = qs_printf(vio->close_reason, "terminated: %s", why) ;
} ;
/*------------------------------------------------------------------------------
@@ -370,7 +370,7 @@ uty_suspend_reason_set(vty_io vio, const char* why)
if ((why == NULL) || (*why == '\0'))
why = "*reason unknown (BUG)*" ;
- vio->suspend_reason = qs_printf(vio->suspend_reason, "Suspended: %s", why) ;
+ vio->suspend_reason = qs_printf(vio->suspend_reason, "suspended: %s", why) ;
} ;
/*------------------------------------------------------------------------------
@@ -912,7 +912,7 @@ uty_vout_base_close(vty_io vio)
{
qstring wrapped ;
- wrapped = qs_printf(NULL, "---\n%s\n", qs_string(vio->close_reason)) ;
+ wrapped = qs_printf(NULL, "%%---\n%% %s\n", qs_string(vio->close_reason));
switch(vf->vout_type)
{
@@ -1276,7 +1276,7 @@ uty_vf_new(vty_io vio, const char* name, int fd, vfd_type_t type,
* and uty_cmd_loop_prepare()
* push_complete = false -- see uty_vout_push()
*
- * io_error = false -- so far, so good
+ * had_error = false -- so far, so good
*
* blocking = vio->blocking || io_type is blocking
*
@@ -2161,7 +2161,7 @@ uty_vf_not_open_error(vio_vf vf, vio_err_type_t err_type)
*
* * if the error is in the vin_base or the vout_base, but the vout_base is
* still working, then raise vx_stop_io_error, which will cancel down to
- * to vin_base/vout_base and then close vin_base and hence the vty.
+ * vin_base/vout_base and then close vin_base and hence the vty.
*
* * if the error is an I/O error, and the error is in the vout_base, then
* stop everything, final -- raise vx_sto_final exception !
@@ -2218,6 +2218,7 @@ uty_vf_error(vio_vf vf, vio_err_type_t err_type, int err)
vio_exception_t vx ;
vty_io vio ;
bool was_final ;
+ bool epipe ;
VTY_ASSERT_LOCKED() ;
@@ -2225,6 +2226,8 @@ uty_vf_error(vio_vf vf, vio_err_type_t err_type, int err)
/* Decide how to handle the error, post the exception and signal.
*/
+ epipe = false ;
+
if ((vf != vio->vin_base) && (vf != vio->vout_base))
vx = vx_io_error ;
else
@@ -2234,36 +2237,49 @@ uty_vf_error(vio_vf vf, vio_err_type_t err_type, int err)
if (vf == vio->vout_base)
{
if ((err_type & verr_io) || ((err_type & verr_mask) == verr_vout))
- vx = vx_stop_final ;
+ {
+ vx = vx_stop_final ;
+ epipe = (err_type & verr_io) && (err == EPIPE) ;
+ } ;
} ;
} ;
- was_final = (vio->state & vst_final) != 0 ;
+ was_final = (vio->state & vst_final) != 0 ; /* before this exception */
uty_vio_exception(vio, vx) ;
/* Log error and create error message as required.
*
- * Note that we log the first error on the vf and all I/O errors.
+ * Note that we log the first error on the vf and all I/O errors (except
+ * for EPIPE on the vout_base -- which we leave for the close reason
+ * logging).
*
* We only output an error message for the first error on the vf, and then
* only if was not vst_final before the error.
*/
- if (!vf->io_error || (err_type & verr_io))
+ if ((!vf->had_error || (err_type & verr_io)) && !epipe)
zlog_warn("%s", uty_error_message(vf, err_type, err, true /* log */).str) ;
- if (!vf->io_error && !was_final)
+ if (!vf->had_error && !was_final)
{
verr_mess_t err_mess ;
err_mess = uty_error_message(vf, err_type, err, false /* not log */) ;
if (vx == vx_stop_final)
- uty_close_reason_set(vio, err_mess.str, true /* replace */) ;
+ uty_close_reason_set(vio, err_mess.str, !epipe) ;
else
vio_fifo_printf(uty_cmd_get_ebuf(vio), "%% %s\n", err_mess.str) ;
} ;
+ vf->had_error = true ;
+
+ /* If this is an I/O error, tell the vfd not to generate any further I/O
+ * error messages on close etc.
+ */
+ if (err_type & verr_io)
+ vio_vfd_set_failed(vf->vfd) ;
+
/* Signal to the command loop and return CMD_IO_ERROR.
*
* One or both will be collected in the command loop "hiatus" and dealt
@@ -2291,9 +2307,12 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
const char* sort ;
bool vout ;
int fd ;
+ bool epipe ;
VTY_ASSERT_LOCKED() ;
+ epipe = (err_type & verr_io) && (err == EPIPE) ;
+
vout = false ;
fd = -1 ;
what = "*unknown verr_xxx (bug)*" ;
@@ -2330,6 +2349,7 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
default:
qassert(false) ;
+ epipe = false ;
} ;
name = vf->name ;
@@ -2387,6 +2407,7 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
qassert(false) ;
where = "*unknown VOUT_XXX (bug)*" ;
+ epipe = false ;
break ;
} ;
}
@@ -2434,6 +2455,7 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
qassert(false) ;
where = "*unknown VIN_XXX (bug)*" ;
+ epipe = false ;
break ;
} ;
} ;
@@ -2447,7 +2469,10 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
else
sort = "time-out" ;
- qfs_printf(qfs, "%s %s %s", where, what, sort) ;
+ if (!epipe)
+ qfs_printf(qfs, "%s %s %s", where, what, sort) ;
+ else
+ qfs_printf(qfs, "%s", where) ;
if (name != NULL)
qfs_printf(qfs, " '%s'", name) ;
@@ -2455,9 +2480,14 @@ uty_error_message(vio_vf vf, vio_err_type_t err_type, int err, bool log)
if (fd >= 0)
qfs_printf(qfs, " (fd=%d)", fd) ;
- if (((err_type & verr_io) != 0) && (err != 0))
- qfs_printf(qfs, ": %s", errtoa(err, 0).str) ;
- else if ((err_type & verr_vtysh) != 0)
+ if (err_type & verr_io)
+ {
+ if (!epipe)
+ qfs_printf(qfs, ": %s", errtoa(err, 0).str) ;
+ else
+ qfs_printf(qfs, " connection closed") ;
+ }
+ else if (err_type & verr_vtysh)
{
switch (err)
{
diff --git a/lib/vty_io.h b/lib/vty_io.h
index 3594d025..13139af3 100644
--- a/lib/vty_io.h
+++ b/lib/vty_io.h
@@ -375,7 +375,7 @@ struct vio_vf
/* General I/O
*
* Once an error has been posted -- see uty_vf_error() -- it is curtains
- * for the vio_vf. The io_error flag is to prevent multiple errors being
+ * for the vio_vf. The had_error flag is to prevent multiple errors being
* posted for the same vio_vf, because after the first error any subsequent
* errors are most likely a consequence of the first.
*
@@ -397,7 +397,7 @@ struct vio_vf
* line, or to return CMD_WAITING, which will then wait for some I/O to
* complete and signal the command loop to proceed.
*/
- bool io_error ; /* an I/O or timeout posted */
+ bool had_error ; /* an error has been posted */
bool blocking ; /* all I/O is blocking, pseudo or real */
diff --git a/lib/vty_io_basic.c b/lib/vty_io_basic.c
index 8fa579d6..fac64f66 100644
--- a/lib/vty_io_basic.c
+++ b/lib/vty_io_basic.c
@@ -434,6 +434,7 @@ vio_vfd_new(int fd, vfd_type_t type, vfd_io_type_t io_type, void* action_info)
*
* type -- X -- see below
* io_type -- X -- see below
+ * failed -- false
*
* action_info -- NULL -- set below if ! "blocking" vio_vfd
*
@@ -520,6 +521,17 @@ vio_vfd_set_action_info(vio_vfd vfd, void* action_info)
vfd->action_info = action_info ;
} ;
+/*------------------------------------------------------------------------------
+ * If there is a vfd, set the "failed" flag, which suppresses any further
+ * error logging - to avoid clutter.
+ */
+extern void
+vio_vfd_set_failed(vio_vfd vfd)
+{
+ if (vfd != NULL)
+ vfd->failed = true ;
+} ;
+
#if 0
/*------------------------------------------------------------------------------
* If there is a read action set for the give vio_vfd (if any), then kick it.
@@ -577,10 +589,25 @@ vio_vfd_read_close(vio_vfd vfd)
{
if (vfd->type == vfd_socket)
{
- int rc = shutdown(vfd->fd, SHUT_RD) ;
- if (rc < 0)
- zlog_err("%s: shutdown() failed, fd=%d: %s", __func__,
+ int rc, try ;
+
+ /* POSIX doesn't list EINTR as a failure for shutdown()
+ * but we handle it the same way as for close() in any case.
+ *
+ * We are completely paranoid and arrange not to get trapped
+ * here indefinitely.
+ */
+ try = 5 ;
+ do
+ rc = shutdown(vfd->fd, SHUT_RD) ;
+ while ((rc < 0) && (errno == EINTR) && (try-- > 0)) ;
+
+ if ((rc < 0) && !vfd->failed)
+ {
+ zlog_err("%s: shutdown() failed, fd=%d: %s", __func__,
vfd->fd, errtoa(errno, 0).str) ;
+ vfd->failed = true ;
+ } ;
} ;
vio_vfd_set_read(vfd, off, 0) ;
vfd->io_type ^= vfd_io_read ; /* now write only ! */
@@ -668,18 +695,23 @@ vio_vfd_close(vio_vfd vfd)
*/
if ((vfd->fd >= 0) && ((vfd->io_type & vfd_io_no_close) == 0))
{
- while (1)
- {
- int rc = close(vfd->fd) ;
-
- if (rc == 0)
- break ;
+ int rc, try ;
- if (errno == EINTR)
- continue ;
+ /* POSIX lists EINTR as a failure for close().
+ *
+ * We are completely paranoid and arrange not to get trapped
+ * here indefinitely.
+ */
+ try = 5 ;
+ do
+ rc = close(vfd->fd) ;
+ while ((rc < 0) && (errno == EINTR) && (try-- > 0)) ;
+ if ((rc < 0) && !vfd->failed)
+ {
zlog_err("%s: close() failed, fd=%d: %s", __func__, vfd->fd,
errtoa(errno, 0).str) ;
+ vfd->failed = true ;
} ;
} ;
diff --git a/lib/vty_io_basic.h b/lib/vty_io_basic.h
index 5c122873..3f731905 100644
--- a/lib/vty_io_basic.h
+++ b/lib/vty_io_basic.h
@@ -124,6 +124,8 @@ struct vio_vfd
vfd_type_t type ; /* used for half-close */
vfd_io_type_t io_type ; /* read, write, read/write */
+ bool failed ; /* avoid repeated error messages */
+
/* The rest of the vfd is to do with managing read/write ready and
* read/write timeouts for *non* blocking vfd.
*
@@ -219,6 +221,7 @@ extern vio_vfd vio_vfd_new(int fd, vfd_type_t type,
extern void vio_vfd_set_read_action(vio_vfd vfd, vio_vfd_action* action) ;
extern void vio_vfd_set_write_action(vio_vfd vfd, vio_vfd_action* action) ;
extern void vio_vfd_set_action_info(vio_vfd vfd, void* action_info) ;
+extern void vio_vfd_set_failed(vio_vfd vfd) ;
extern vio_vfd vio_vfd_read_close(vio_vfd vfd) ;
extern vio_vfd vio_vfd_close(vio_vfd vfd) ;
extern on_off_b vio_vfd_set_read(vio_vfd vfd, on_off_b how,
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 7ef7e0df..fc0fd8f0 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -431,17 +431,15 @@ uty_term_write_close(vio_vf vf)
*/
if (vio->state & vst_final)
{
- const char* reason, * sep ;
+ const char* reason ;
vf->cli = uty_cli_free(vf->cli) ;
reason = qs_string(vf->vio->close_reason) ;
- sep = ": " ;
if ((reason == NULL) || (*reason == '\0'))
- reason = sep = "" ;
+ reason = "closed" ;
- zlog_info("VTY connection (fd %d) closed%s%s",
- vio_vfd_fd(vf->vfd), sep, reason) ;
+ zlog_info("VTY connection (fd %d) %s", vio_vfd_fd(vf->vfd), reason) ;
}
else if (vf_active(vf->vout_state))
{
diff --git a/lib/vty_io_vtysh.c b/lib/vty_io_vtysh.c
index f506eaa3..321ee6aa 100644
--- a/lib/vty_io_vtysh.c
+++ b/lib/vty_io_vtysh.c
@@ -258,17 +258,16 @@ uty_sh_serv_write_close(vio_vf vf)
if (vio->state & vst_final)
{
- const char* reason, * sep ;
+ const char* reason ;
XFREE(MTYPE_VTY_CLI, vf->vtysh) ;
reason = qs_string(vf->vio->close_reason) ;
- sep = ": " ;
if ((reason == NULL) || (*reason == '\0'))
- reason = sep = "" ;
+ reason = "closed" ;
- zlog_info("vtysh connection '%s' (fd %d) closed%s%s", vf->name,
- vio_vfd_fd(vf->vfd), sep, reason) ;
+ zlog_info("vtysh connection '%s' (fd %d) %s", vf->name,
+ vio_vfd_fd(vf->vfd), reason) ;
}
else if (vf_active(vf->vout_state))
{