diff --git a/drivers/syslog/Kconfig b/drivers/syslog/Kconfig index 1f8aa2b0ce..0e45cc9432 100644 --- a/drivers/syslog/Kconfig +++ b/drivers/syslog/Kconfig @@ -17,6 +17,12 @@ config SYSLOG_WRITE bool default n +config SYSLOG_MAX_CHANNELS + int "Maximum SYSLOG channels" + default 1 + ---help--- + Maximum number of supported SYSLOG channels. + config RAMLOG bool "RAM log device support" default n diff --git a/drivers/syslog/syslog.h b/drivers/syslog/syslog.h index 1922e002d8..f4e9560565 100644 --- a/drivers/syslog/syslog.h +++ b/drivers/syslog/syslog.h @@ -48,7 +48,8 @@ extern "C" */ struct syslog_channel_s; /* Forward reference */ -EXTERN FAR const struct syslog_channel_s *g_syslog_channel; +EXTERN FAR const struct syslog_channel_s *g_syslog_channel + [CONFIG_SYSLOG_MAX_CHANNELS]; /**************************************************************************** * Public Function Prototypes @@ -216,7 +217,6 @@ int syslog_add_intbuffer(int ch); * to the SYSLOG device. * * Input Parameters: - * channel - The syslog channel to use in performing the flush operation. * force - Use the force() method of the channel vs. the putc() method. * * Returned Value: @@ -229,8 +229,7 @@ int syslog_add_intbuffer(int ch); ****************************************************************************/ #ifdef CONFIG_SYSLOG_INTBUFFER -int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel, - bool force); +int syslog_flush_intbuffer(bool force); #endif /**************************************************************************** diff --git a/drivers/syslog/syslog_channel.c b/drivers/syslog/syslog_channel.c index 90c1d8b9a0..8de7bbbedf 100644 --- a/drivers/syslog/syslog_channel.c +++ b/drivers/syslog/syslog_channel.c @@ -92,7 +92,11 @@ static const struct syslog_channel_s g_default_channel = /* This is the current syslog channel in use */ -FAR const struct syslog_channel_s *g_syslog_channel = &g_default_channel; +FAR const struct syslog_channel_s +*g_syslog_channel[CONFIG_SYSLOG_MAX_CHANNELS] = +{ + &g_default_channel +}; /**************************************************************************** * Private Functions @@ -135,14 +139,82 @@ static int syslog_default_putc(int ch) int syslog_channel(FAR const struct syslog_channel_s *channel) { +#if (CONFIG_SYSLOG_MAX_CHANNELS != 1) + int i; +#endif + DEBUGASSERT(channel != NULL); if (channel != NULL) { DEBUGASSERT(channel->sc_putc != NULL && channel->sc_force != NULL); - g_syslog_channel = channel; +#if (CONFIG_SYSLOG_MAX_CHANNELS == 1) + g_syslog_channel[0] = channel; return OK; +#else + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == NULL) + { + g_syslog_channel[i] = channel; + return OK; + } + else if (g_syslog_channel[i] == channel) + { + return OK; + } + } +#endif + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: syslog_channel_remove + * + * Description: + * Removes an already configured SYSLOG channel from the list of used + * channels. + * + * Input Parameters: + * channel - Provides the interface to the channel to be removed. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int syslog_channel_remove(FAR const struct syslog_channel_s *channel) +{ + int i; + + DEBUGASSERT(channel != NULL); + + if (channel != NULL) + { + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == channel) + { + /* Get the rest of the channels one position back + * to ensure that there are no holes in the list. + */ + + while (i < (CONFIG_SYSLOG_MAX_CHANNELS - 1) && + g_syslog_channel[i + 1] != NULL) + { + g_syslog_channel[i] = g_syslog_channel[i + 1]; + i++; + } + + g_syslog_channel[i] = NULL; + + return OK; + } + } } return -EINVAL; diff --git a/drivers/syslog/syslog_flush.c b/drivers/syslog/syslog_flush.c index c2edbd04c2..c763c6cbbd 100644 --- a/drivers/syslog/syslog_flush.c +++ b/drivers/syslog/syslog_flush.c @@ -64,21 +64,29 @@ int syslog_flush(void) { - DEBUGASSERT(g_syslog_channel != NULL); + int i; #ifdef CONFIG_SYSLOG_INTBUFFER /* Flush any characters that may have been added to the interrupt * buffer. */ - syslog_flush_intbuffer(g_syslog_channel, true); + syslog_flush_intbuffer(true); #endif - /* Then flush all of the buffered output to the SYSLOG device */ - - if (g_syslog_channel->sc_flush != NULL) + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) { - return g_syslog_channel->sc_flush(); + if (g_syslog_channel[i] == NULL) + { + break; + } + + /* Then flush all of the buffered output to the SYSLOG device */ + + if (g_syslog_channel[i]->sc_flush != NULL) + { + g_syslog_channel[i]->sc_flush(); + } } return OK; diff --git a/drivers/syslog/syslog_force.c b/drivers/syslog/syslog_force.c index e9d6d6359c..db6f000b29 100644 --- a/drivers/syslog/syslog_force.c +++ b/drivers/syslog/syslog_force.c @@ -55,18 +55,29 @@ int syslog_force(int ch) { - DEBUGASSERT(g_syslog_channel != NULL && - g_syslog_channel->sc_force != NULL); + int i; #ifdef CONFIG_SYSLOG_INTBUFFER /* Flush any characters that may have been added to the interrupt * buffer through the emergency channel */ - syslog_flush_intbuffer(g_syslog_channel, true); + syslog_flush_intbuffer(true); #endif - /* Then send the character to the emergency channel */ + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == NULL) + { + break; + } - return g_syslog_channel->sc_force(ch); + DEBUGASSERT(g_syslog_channel[i]->sc_force != NULL); + + /* Then send the character to the emergency channel */ + + g_syslog_channel[i]->sc_force(ch); + } + + return ch; } diff --git a/drivers/syslog/syslog_intbuffer.c b/drivers/syslog/syslog_intbuffer.c index eb686bb9be..cd64158b78 100644 --- a/drivers/syslog/syslog_intbuffer.c +++ b/drivers/syslog/syslog_intbuffer.c @@ -264,7 +264,6 @@ int syslog_add_intbuffer(int ch) * to the SYSLOG device. * * Input Parameters: - * channel - The syslog channel to use in performing the flush operation. * force - Use the force() method of the channel vs. the putc() method. * * Returned Value: @@ -276,41 +275,49 @@ int syslog_add_intbuffer(int ch) * ****************************************************************************/ -int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel, - bool force) +int syslog_flush_intbuffer(bool force) { syslog_putc_t putfunc; int ch; - int ret = OK; - - /* Select which putc function to use for this flush */ - - putfunc = force ? channel->sc_putc : channel->sc_force; + int i; /* This logic is performed with the scheduler disabled to protect from * concurrent modification by other tasks. */ sched_lock(); + do { /* Transfer one character to time. This is inefficient, but is * done in this way to: (1) Deal with concurrent modification of * the interrupt buffer from interrupt activity, (2) Avoid keeper * interrupts disabled for a long time, and (3) to handler - * wraparound of the circular buffer indices. + * wrap-around of the circular buffer indices. */ ch = syslog_remove_intbuffer(); - if (ch != EOF) + + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) { - ret = putfunc(ch); + if ((g_syslog_channel[i] == NULL) || (ch == EOF)) + { + break; + } + + /* Select which putc function to use for this flush */ + + putfunc = force ? g_syslog_channel[i]->sc_putc : + g_syslog_channel[i]->sc_force; + + putfunc(ch); } } - while (ch != EOF && ret >= 0); + while (ch != EOF); sched_unlock(); - return ret; + + return ch; } #endif /* CONFIG_SYSLOG_INTBUFFER */ diff --git a/drivers/syslog/syslog_putc.c b/drivers/syslog/syslog_putc.c index 1078aa2e75..fb6181bd69 100644 --- a/drivers/syslog/syslog_putc.c +++ b/drivers/syslog/syslog_putc.c @@ -55,7 +55,7 @@ int syslog_putc(int ch) { - DEBUGASSERT(g_syslog_channel != NULL); + int i; /* Is this an attempt to do SYSLOG output from an interrupt handler? */ @@ -65,8 +65,8 @@ int syslog_putc(int ch) if (up_interrupt_context()) { /* Buffer the character in the interrupt buffer. - * The interrupt buffer will be flushed before the next normal, - * non-interrupt SYSLOG output. + * The interrupt buffer will be flushed before the next + * normal,non-interrupt SYSLOG output. */ return syslog_add_intbuffer(ch); @@ -76,27 +76,46 @@ int syslog_putc(int ch) { /* Force the character to the SYSLOG device immediately * (if possible). - * This means that the interrupt data may not be in synchronization - * with output data that may have been buffered by sc_putc(). + * This means that the interrupt data may not be in + * synchronization with output data that may have been + * buffered by sc_putc(). */ - DEBUGASSERT(g_syslog_channel->sc_force != NULL); + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == NULL) + { + break; + } - return g_syslog_channel->sc_force(ch); + DEBUGASSERT(g_syslog_channel[i]->sc_force != NULL); + + g_syslog_channel[i]->sc_force(ch); + } } } else { - DEBUGASSERT(g_syslog_channel->sc_putc != NULL); - #ifdef CONFIG_SYSLOG_INTBUFFER /* Flush any characters that may have been added to the interrupt * buffer. */ - syslog_flush_intbuffer(g_syslog_channel, false); + syslog_flush_intbuffer(false); #endif - return g_syslog_channel->sc_putc(ch); + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == NULL) + { + break; + } + + DEBUGASSERT(g_syslog_channel[i]->sc_putc != NULL); + + g_syslog_channel[i]->sc_putc(ch); + } } + + return ch; } diff --git a/drivers/syslog/syslog_write.c b/drivers/syslog/syslog_write.c index 068c0f46e3..7fae32313c 100644 --- a/drivers/syslog/syslog_write.c +++ b/drivers/syslog/syslog_write.c @@ -56,7 +56,8 @@ static ssize_t syslog_default_write(FAR const char *buffer, size_t buflen) { - size_t nwritten; + int i; + size_t nwritten = 0; if (up_interrupt_context() || sched_idletask()) { @@ -70,23 +71,43 @@ static ssize_t syslog_default_write(FAR const char *buffer, size_t buflen) else #endif { - DEBUGASSERT(g_syslog_channel->sc_force != NULL); - g_syslog_channel->sc_force(*buffer++); + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) + { + if (g_syslog_channel[i] == NULL) + { + break; + } + + DEBUGASSERT(g_syslog_channel[i]->sc_force != NULL); + g_syslog_channel[i]->sc_force(*buffer++); + } } } } -#ifdef CONFIG_SYSLOG_WRITE - else if (g_syslog_channel->sc_write) - { - nwritten = g_syslog_channel->sc_write(buffer, buflen); - } -#endif else { - for (nwritten = 0; nwritten < buflen; nwritten++) + for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) { - DEBUGASSERT(g_syslog_channel->sc_putc != NULL); - g_syslog_channel->sc_putc(*buffer++); + if (g_syslog_channel[i] == NULL) + { + break; + } + +#ifdef CONFIG_SYSLOG_WRITE + if (g_syslog_channel[i]->sc_write) + { + nwritten = g_syslog_channel[i]->sc_write(buffer, buflen); + } + else +#endif + { + DEBUGASSERT(g_syslog_channel[i]->sc_putc != NULL); + + for (nwritten = 0; nwritten < buflen; nwritten++) + { + g_syslog_channel[i]->sc_putc(*buffer++); + } + } } } @@ -122,7 +143,7 @@ ssize_t syslog_write(FAR const char *buffer, size_t buflen) * buffer. */ - syslog_flush_intbuffer(g_syslog_channel, false); + syslog_flush_intbuffer(false); } #endif diff --git a/include/nuttx/syslog/syslog.h b/include/nuttx/syslog/syslog.h index e9771c3ae5..823ab3ffe7 100644 --- a/include/nuttx/syslog/syslog.h +++ b/include/nuttx/syslog/syslog.h @@ -131,13 +131,31 @@ extern "C" * channel - Provides the interface to the channel to be used. * * Returned Value: - * Zero (OK)is returned on success. A negated errno value is returned + * Zero (OK) is returned on success. A negated errno value is returned * on any failure. * ****************************************************************************/ int syslog_channel(FAR const struct syslog_channel_s *channel); +/**************************************************************************** + * Name: syslog_channel_remove + * + * Description: + * Removes an already configured SYSLOG channel from the list of used + * channels. + * + * Input Parameters: + * channel - Provides the interface to the channel to be removed. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int syslog_channel_remove(FAR const struct syslog_channel_s *channel); + /**************************************************************************** * Name: syslog_initialize *