| /**************************************************************************** |
| * drivers/syslog/syslog_channel.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/types.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <semaphore.h> |
| |
| #include <nuttx/syslog/syslog.h> |
| #include <nuttx/compiler.h> |
| #include <nuttx/mutex.h> |
| |
| #ifdef CONFIG_RAMLOG_SYSLOG |
| # include <nuttx/syslog/ramlog.h> |
| #endif |
| |
| #ifdef CONFIG_SYSLOG_RPMSG |
| # include <nuttx/syslog/syslog_rpmsg.h> |
| #endif |
| |
| #ifdef CONFIG_SYSLOG_RTT |
| # include <nuttx/segger/rtt.h> |
| #endif |
| |
| #ifdef CONFIG_ARCH_LOWPUTC |
| # include <nuttx/arch.h> |
| #endif |
| |
| #include "syslog.h" |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| #if defined(CONFIG_SYSLOG_DEFAULT) |
| static int syslog_default_putc(FAR struct syslog_channel_s *channel, |
| int ch); |
| static ssize_t syslog_default_write(FAR struct syslog_channel_s *channel, |
| FAR const char *buffer, size_t buflen); |
| #endif |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| #if defined(CONFIG_RAMLOG_SYSLOG) |
| static const struct syslog_channel_ops_s g_ramlog_channel_ops = |
| { |
| ramlog_putc, |
| ramlog_putc, |
| NULL, |
| ramlog_write |
| }; |
| |
| static struct syslog_channel_s g_ramlog_channel = |
| { |
| &g_ramlog_channel_ops |
| # ifdef CONFIG_SYSLOG_IOCTL |
| , "ram" |
| , false |
| # endif |
| }; |
| #endif |
| |
| #if defined(CONFIG_SYSLOG_RPMSG) |
| static const struct syslog_channel_ops_s g_rpmsg_channel_ops = |
| { |
| syslog_rpmsg_putc, |
| syslog_rpmsg_putc, |
| syslog_rpmsg_flush, |
| syslog_rpmsg_write, |
| syslog_rpmsg_write |
| }; |
| |
| static struct syslog_channel_s g_rpmsg_channel = |
| { |
| &g_rpmsg_channel_ops |
| # ifdef CONFIG_SYSLOG_IOCTL |
| , "rpmsg" |
| , false |
| # endif |
| }; |
| #endif |
| |
| #if defined(CONFIG_SYSLOG_RTT) |
| static const struct syslog_channel_ops_s g_rtt_channel_ops = |
| { |
| syslog_rtt_putc, |
| syslog_rtt_putc, |
| NULL, |
| syslog_rtt_write, |
| syslog_rtt_write |
| }; |
| |
| static struct syslog_channel_s g_rtt_channel = |
| { |
| &g_rtt_channel_ops |
| # ifdef CONFIG_SYSLOG_IOCTL |
| , "rtt" |
| , false |
| # endif |
| }; |
| #endif |
| |
| #if defined(CONFIG_SYSLOG_DEFAULT) |
| static const struct syslog_channel_ops_s g_default_channel_ops = |
| { |
| syslog_default_putc, |
| syslog_default_putc, |
| NULL, |
| syslog_default_write |
| }; |
| |
| static struct syslog_channel_s g_default_channel = |
| { |
| &g_default_channel_ops |
| # ifdef CONFIG_SYSLOG_IOCTL |
| , "default" |
| , false |
| # endif |
| }; |
| #endif |
| |
| /* This is a simply sanity check to avoid we have more elements than the |
| * `g_syslog_channel` array can hold |
| */ |
| |
| #ifdef CONFIG_SYSLOG_DEFAULT |
| # define SYSLOG_DEFAULT_AVAILABLE 1 |
| #else |
| # define SYSLOG_DEFAULT_AVAILABLE 0 |
| #endif |
| |
| #ifdef CONFIG_RAMLOG_SYSLOG |
| # define RAMLOG_SYSLOG_AVAILABLE 1 |
| #else |
| # define RAMLOG_SYSLOG_AVAILABLE 0 |
| #endif |
| |
| #ifdef CONFIG_SYSLOG_RPMSG |
| # define SYSLOG_RPMSG_AVAILABLE 1 |
| #else |
| # define SYSLOG_RPMSG_AVAILABLE 0 |
| #endif |
| |
| #ifdef CONFIG_SYSLOG_RTT |
| # define SYSLOG_RTT_AVAILABLE 1 |
| #else |
| # define SYSLOG_RTT_AVAILABLE 0 |
| #endif |
| |
| #define SYSLOG_NCHANNELS (SYSLOG_DEFAULT_AVAILABLE + \ |
| RAMLOG_SYSLOG_AVAILABLE + \ |
| SYSLOG_RPMSG_AVAILABLE + \ |
| SYSLOG_RTT_AVAILABLE) |
| |
| #if SYSLOG_NCHANNELS > CONFIG_SYSLOG_MAX_CHANNELS |
| # error "Maximum channel number exceeds." |
| #endif |
| |
| /* This is the current syslog channel in use */ |
| |
| FAR struct syslog_channel_s |
| *g_syslog_channel[CONFIG_SYSLOG_MAX_CHANNELS] = |
| { |
| #if defined(CONFIG_SYSLOG_DEFAULT) |
| &g_default_channel, |
| #endif |
| |
| #if defined(CONFIG_RAMLOG_SYSLOG) |
| &g_ramlog_channel, |
| #endif |
| |
| #if defined(CONFIG_SYSLOG_RPMSG) |
| &g_rpmsg_channel, |
| #endif |
| |
| #if defined(CONFIG_SYSLOG_RTT) |
| &g_rtt_channel |
| #endif |
| }; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: syslog_default_putc |
| * |
| * Description: |
| * If the arch supports a low-level putc function, output will be |
| * redirected there. Else acts as a dummy, no-nothing channel. |
| * |
| ****************************************************************************/ |
| |
| #if defined(CONFIG_SYSLOG_DEFAULT) |
| static int syslog_default_putc(FAR struct syslog_channel_s *channel, int ch) |
| { |
| UNUSED(channel); |
| |
| #if defined(CONFIG_ARCH_LOWPUTC) |
| return up_putc(ch); |
| #else |
| return ch; |
| #endif |
| } |
| |
| static ssize_t syslog_default_write(FAR struct syslog_channel_s *channel, |
| FAR const char *buffer, size_t buflen) |
| { |
| #if defined(CONFIG_ARCH_LOWPUTC) |
| static mutex_t lock = NXMUTEX_INITIALIZER; |
| |
| nxmutex_lock(&lock); |
| |
| up_nputs(buffer, buflen); |
| |
| nxmutex_unlock(&lock); |
| #endif |
| |
| UNUSED(channel); |
| return buflen; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: syslog_channel |
| * |
| * Description: |
| * Configure the SYSLOGging function to use the provided channel to |
| * generate SYSLOG output. |
| * |
| * Input Parameters: |
| * channel - Provides the interface to the channel to be used. |
| * |
| * Returned Value: |
| * Zero (OK) is returned on success. A negated errno value is returned |
| * on any failure. |
| * |
| ****************************************************************************/ |
| |
| int syslog_channel(FAR struct syslog_channel_s *channel) |
| { |
| #if (CONFIG_SYSLOG_MAX_CHANNELS != 1) |
| int i; |
| #endif |
| |
| DEBUGASSERT(channel != NULL); |
| |
| if (channel != NULL) |
| { |
| #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) |
| { |
| # ifdef CONFIG_SYSLOG_IOCTL |
| if (channel->sc_name[0] == '\0') |
| { |
| snprintf(channel->sc_name, sizeof(channel->sc_name), |
| "channel-%p", channel->sc_ops); |
| } |
| # endif |
| |
| 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 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; |
| |
| /* The channel is now removed from the list and its driver |
| * can be safely uninitialized. |
| */ |
| |
| if (channel->sc_ops->sc_close) |
| { |
| channel->sc_ops->sc_close(channel); |
| } |
| |
| return OK; |
| } |
| } |
| } |
| |
| return -EINVAL; |
| } |