summaryrefslogtreecommitdiffstats
path: root/lib/vty_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vty_log.c')
-rw-r--r--lib/vty_log.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/vty_log.c b/lib/vty_log.c
new file mode 100644
index 00000000..edb3291b
--- /dev/null
+++ b/lib/vty_log.c
@@ -0,0 +1,258 @@
+/* VTY interface to logging
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "misc.h"
+
+#include "vty_log.h"
+#include "vty_local.h"
+#include "vty_io_term.h"
+#include "log_local.h"
+#include "list_util.h"
+#include "vio_fifo.h"
+#include "mqueue.h"
+
+/*==============================================================================
+ * This supports the "vty monitor" facility -- which reflects logging
+ * information to one or more VTY_TERMINAL vty.
+ *
+ * There are a number of issues:
+ *
+ * a) output of logging information should not be held up any longer than
+ * is absolutely necessary.
+ *
+ * b) console may be busy doing other things, so logging information needs
+ * to be buffered.
+ *
+ * c) zlog() et al, hold the LOG_LOCK(), which is at a lower level than the
+ * VTY_LOCK().
+ *
+ * d) may have one or more monitor vty, possibly at different levels of
+ * message.
+ *
+ * e) must avoid logging error messages for given vty on that vty !
+ *
+ *
+ *
+ *
+ */
+static vio_fifo monitor_buffer = NULL ;
+static uint monitor_count = 0 ;
+
+static bool mon_kicked = false ;
+static mqueue_block mon_mqb = NULL ;
+
+static void vty_mon_action(mqueue_block mqb, mqb_flag_t flag) ;
+
+/*------------------------------------------------------------------------------
+ * Initialise the vty monitor facility.
+ *
+ */
+extern void
+uty_init_monitor(void)
+{
+ LOG_LOCK() ;
+
+ vio_monitor_list = NULL ;
+ monitor_buffer = NULL ;
+
+ mon_kicked = false ;
+ mon_mqb = mqb_init_new(NULL, vty_mon_action, &mon_mqb) ;
+
+ LOG_UNLOCK() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set/Clear "monitor" state:
+ *
+ * set: if VTY_TERM and not already "monitor" (and write_open !)
+ * clear: if is "monitor"
+ */
+extern void
+uty_set_monitor(vty_io vio, bool on)
+{
+ int level ;
+ int count ;
+
+ VTY_ASSERT_LOCKED() ;
+
+ level = 0 ;
+ count = 0 ;
+
+ LOG_LOCK() ;
+
+ if (on && !vio->monitor)
+ {
+ if (vio->vty->type == VTY_TERMINAL)
+ {
+ vio->monitor = true ;
+
+ vio->maxlvl = INT_MAX ; /* pro tem TODO */
+ vio->mon_kick = false ;
+
+ if (vio->mbuf == NULL)
+ vio->mbuf = vio_fifo_init_new(NULL, 8 * 1024) ;
+
+ sdl_push(vio_monitor_list, vio, mon_list) ;
+
+ count = +1 ;
+ } ;
+ }
+ else if (!on && vio->monitor)
+ {
+ vio->monitor = false ;
+
+ vio->maxlvl = INT_MAX ; /* pro tem TODO */
+ vio->mon_kick = false ;
+
+ sdl_del(vio_monitor_list, vio, mon_list) ;
+ count = -1 ;
+ }
+
+ if (count != 0)
+ uzlog_add_monitor(NULL, count) ;
+
+ monitor_count += count ;
+
+ LOG_UNLOCK() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Put logging message to all suitable monitors.
+ *
+ * All we can do here is to shovel stuff into buffers and then kick the VTY
+ * to do something. If running multi-nexus, then the kick takes the form of
+ * a message sent to the cli nexus, otherwise can call the message action
+ * function here and now.
+ *
+ * NB: expect incoming line to NOT include '\n' or any other line ending.
+ */
+extern void
+vty_log(int priority, const char* line, uint len)
+{
+ vty_io vio ;
+ bool kick ;
+
+ LOG_ASSERT_LOCKED() ;
+
+ vio = vio_monitor_list ;
+ kick = false ;
+ while (vio != NULL)
+ {
+ if (priority <= vio->maxlvl)
+ {
+ vio_fifo_put_bytes(vio->mbuf, line, len) ;
+ vio_fifo_put_bytes(vio->mbuf, "\r\n", 2) ;
+
+ vio->mon_kick = kick = true ;
+ }
+ else
+ vio->mon_kick = false ;
+
+ vio = sdl_next(vio, mon_list) ;
+ } ;
+
+ if (kick)
+ {
+ if (vty_multi_nexus)
+ {
+ if (!mon_kicked)
+ {
+ mon_kicked = true ;
+ mqueue_enqueue(vty_cli_nexus->queue, mon_mqb, mqb_ordinary) ;
+ } ;
+ }
+ else
+ vty_mon_action(NULL, mqb_action) ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Put logging message to all suitable monitors.
+ *
+ * All we can do here is to shovel stuff into buffers and then boot the VTY
+ * to do something.
+ *
+ * NB: expect incoming line to NOT include '\n' or any other line ending.
+ */
+static void
+vty_mon_action(mqueue_block mqb, mqb_flag_t flag)
+{
+ VTY_LOCK() ;
+ LOG_LOCK() ; /* IN THIS ORDER !!! */
+
+ mon_kicked = false ; /* If anything else happens, need to kick again */
+
+ if (flag == mqb_action)
+ {
+ vty_io vio ;
+
+ vio = vio_monitor_list ;
+ while (vio != NULL)
+ {
+ assert(vio->vout_base->vout_type == VOUT_TERM) ;
+
+ if (vio->mon_kick)
+ {
+ vio->mon_kick = false ;
+ uty_term_mon_write(vio->vout_base) ;
+ } ;
+
+ vio = sdl_next(vio, mon_list) ;
+ } ;
+ }
+ else
+ mqb_free(mqb) ; /* Suicide */
+
+ LOG_UNLOCK() ;
+ VTY_UNLOCK() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Async-signal-safe version of vty_log for fixed strings.
+ *
+ * This is last gasp operation.
+ */
+extern void
+vty_log_fixed (const char *buf, uint len)
+{
+ vty_io vio ;
+
+ /* Write to all known "monitor" vty
+ *
+ * Forget all the niceties -- about to die in any case.
+ */
+ vio = sdl_head(vio_monitor_list) ;
+ while (vio != NULL)
+ {
+ write(vio_vfd_fd(vio->vout_base->vfd), buf, len) ;
+ write(vio_vfd_fd(vio->vout_base->vfd), "\r\n", 2) ;
+
+ vio = sdl_next(vio, mon_list) ;
+ } ;
+} ;
+
+
+
+
+
+