Move fs/drivers/fs_devsyslog.c to drivers/syslog/syslog_device.c

This commit is contained in:
Gregory Nutt
2016-06-19 08:46:46 -06:00
parent b66112347c
commit e27491f5be
5 changed files with 88 additions and 144 deletions
+42
View File
@@ -72,6 +72,48 @@ config RAMLOG_NPOLLWAITERS
endif
comment "System Logging"
config SYSLOG
bool "Advanced SYSLOG features"
default n
---help---
Enables generic system logging features. NOTE: This setting is not
required to enable system logging. If this feature is not enable
system logging will still be available and will log to the system
console (like printf()). This setting is required to enable
customization of the basic system logging capability.
config SYSLOG_TIMESTAMP
bool "Prepend timestamp to syslog message"
default n
---help---
Prepend timestamp to syslog message.
if SYSLOG
config SYSLOG_CHAR
bool "System log character device support"
default y
---help---
Enable the generic character device for the SYSLOG. The full path to the
SYSLOG device is provided by SYSLOG_DEVPATH. A valid character device (or
file) must exist at this path. It will by opened by syslog_initialize.
Do not enable more than one SYSLOG device.
config SYSLOG_DEVPATH
string "System log device"
default "/dev/syslog"
depends on SYSLOG_CHAR
---help---
The full path to the system logging device. For the RAMLOG SYSLOG device,
this is normally "/dev/ramlog". For character SYSLOG devices, it should be
some other existing character device (or file) supported by the configuration
(such as "/dev/ttyS1")/
endif
config SYSLOG_CONSOLE
bool "Use SYSLOG for /dev/console"
default n
+12 -5
View File
@@ -46,15 +46,22 @@ ifeq ($(CONFIG_DRIVER_NOTE),y)
CSRCS += note_driver.c
endif
############################################################################
# Include SYSLOG drivers (only one should be enabled)
# The RAMLOG device is usable as a system logging device or standalone
ifeq ($(CONFIG_RAMLOG),y)
CSRCS += ramlog.c
else ifeq ($(CONFIG_SYSLOG),y)
endif
# If no special logging devices are implemented, then the default SYSLOG
# logic at fs/fs_syslog.c will be used
############################################################################
# Include SYSLOG drivers (only one should be enabled)
ifeq ($(CONFIG_SYSLOG),y)
# System logging to a character device (or file)
ifeq ($(CONFIG_SYSLOG_CHAR),y)
CSRCS += syslog_device.c
endif
# (Add other SYSLOG drivers here)
+481
View File
@@ -0,0 +1,481 @@
/****************************************************************************
* driver/syslog/syslog_device.c
*
* Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#include <assert.h>
#include <nuttx/fs/fs.h>
#include <nuttx/arch.h>
#include <nuttx/syslog/syslog.h>
#if defined(CONFIG_SYSLOG) && defined(CONFIG_SYSLOG_CHAR)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Open the device/file write-only, try to create (file) it if it doesn't
* exist, if the file that already exists, then append the new log data to
* end of the file.
*/
#define SYSLOG_OFLAGS (O_WRONLY | O_CREAT | O_APPEND)
/* An invalid thread ID */
#define NO_HOLDER ((pid_t)-1)
/****************************************************************************
* Private Types
****************************************************************************/
/* This enumeration represents the state of the SYSLOG device interface */
enum syslog_state_e
{
SYSLOG_UNINITIALIZED = 0, /* SYSLOG has not been initialized */
SYSLOG_INITIALIZING, /* SYSLOG is being initialized */
SYSLOG_REOPEN, /* SYSLOG open failed... try again later */
SYSLOG_FAILURE, /* SYSLOG open failed... don't try again */
SYSLOG_OPENED, /* SYSLOG device is open and ready to use */
};
/* This structure contains all SYSLOGing state information */
struct syslog_dev_s
{
uint8_t sl_state; /* See enum syslog_state_e */
sem_t sl_sem; /* Enforces mutually exclusive access */
pid_t sl_holder; /* PID of the thread that holds the semaphore */
struct file sl_file; /* The syslog file structure */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* This is the device structure for the console or syslogging function. */
static struct syslog_dev_s g_sysdev;
static const uint8_t g_syscrlf[2] =
{
'\r', '\n'
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: syslog_takesem
*
* Description:
* Write to the syslog device
*
****************************************************************************/
static inline int syslog_takesem(void)
{
pid_t me = getpid();
int ret;
/* Does this thread already hold the semaphore? That could happen if
* we wer called recursively, i.e., if the logic kicked off by
* syslog_write() where to generate more debug output. Return an error
* in that case.
*/
if (g_sysdev.sl_holder == me)
{
/* Return an error (instead of deadlocking) */
return -EWOULDBLOCK;
}
/* Either the semaphore is available or is currently held by another
* thread. Wait for it to become available.
*/
ret = sem_wait(&g_sysdev.sl_sem);
if (ret < 0)
{
return -get_errno();
}
/* We hold the semaphore. We can safely mark ourself as the holder
* of the semaphore.
*/
g_sysdev.sl_holder = me;
return OK;
}
/****************************************************************************
* Name: syslog_givesem
*
* Description:
* Write to the syslog device
*
****************************************************************************/
static inline void syslog_givesem(void)
{
#ifdef CONFIG_DEBUG_ASSERTIONS
pid_t me = getpid();
DEBUGASSERT(g_sysdev.sl_holder == me);
#endif
/* Relinquish the semaphore */
g_sysdev.sl_holder = NO_HOLDER;
sem_post(&g_sysdev.sl_sem);
}
/****************************************************************************
* Name: syslog_write
*
* Description:
* Write to the syslog device
*
****************************************************************************/
static inline ssize_t syslog_write(FAR const void *buf, size_t nbytes)
{
FAR struct inode *inode;
/* Let the driver perform the write */
inode = g_sysdev.sl_file.f_inode;
DEBUGASSERT(inode != NULL);
return inode->u.i_ops->write(&g_sysdev.sl_file, buf, nbytes);
}
/****************************************************************************
* Name: syslog_flush
*
* Description:
* Flush any buffer data in the file system to media.
*
****************************************************************************/
#ifndef CONFIG_DISABLE_MOUNTPOINT
static inline void syslog_flush(void)
{
FAR struct inode *inode = g_sysdev.sl_file.f_inode;
/* Is this a mountpoint? Does it support the sync method? */
DEBUGASSERT(inode != NULL);
if (inode->u.i_mops->sync)
{
/* Yes... synchronize to the stream */
(void)inode->u.i_mops->sync(&g_sysdev.sl_file);
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: syslog_initialize
*
* Description:
* Initialize to use the character device (or file) at
* CONFIG_SYSLOG_DEVPATH as the SYSLOG sink.
*
* NOTE that this implementation excludes using a network connection as
* SYSLOG device. That would be a good extension.
*
****************************************************************************/
int syslog_initialize(void)
{
int fd;
int ret;
/* At this point, the only expected states are SYSLOG_UNINITIALIZED or
* SYSLOG_REOPEN.. Not SYSLOG_INITIALIZING, SYSLOG_FAILURE, SYSLOG_OPENED.
*/
DEBUGASSERT(g_sysdev.sl_state == SYSLOG_UNINITIALIZED ||
g_sysdev.sl_state == SYSLOG_REOPEN);
g_sysdev.sl_state = SYSLOG_INITIALIZING;
/* Open the device driver. */
fd = open(CONFIG_SYSLOG_DEVPATH, O_WRONLY);
if (fd < 0)
{
int errcode = get_errno();
DEBUGASSERT(errcode > 0);
/* We failed to open the file. Perhaps it does exist? Perhaps it
* exists, but is not ready because it depends on insertion of a
* removable device?
*
* In any case we will attempt to re-open the device repeatedly.
* The assumption is that the device path is valid but that the
* driver has not yet been registered or a removable device has
* not yet been installed.
*/
g_sysdev.sl_state = SYSLOG_REOPEN;
return -errcode;
}
/* Detach the file descriptor from the file structure. The file
* descriptor is a task-specific concept. Detaching the file
* descriptor allows us to use the device on all threads in all tasks.
*/
ret = file_detach(fd, &g_sysdev.sl_file);
if (ret < 0)
{
/* This should not happen and means that something very bad has
* occurred.
*/
g_sysdev.sl_state = SYSLOG_FAILURE;
close(fd);
return ret;
}
/* The SYSLOG device is open and ready for writing. */
sem_init(&g_sysdev.sl_sem, 0, 1);
g_sysdev.sl_holder = NO_HOLDER;
g_sysdev.sl_state = SYSLOG_OPENED;
return OK;
}
/****************************************************************************
* Name: syslog_putc
*
* Description:
* This is the low-level system logging interface. The debugging/syslogging
* interfaces are syslog() and lowsyslog(). The difference is is that
* the syslog() function writes to syslogging device (usually fd=1, stdout)
* whereas lowsyslog() uses a lower level interface that works from
* interrupt handlers. This function is a a low-level interface used to
* implement lowsyslog().
*
****************************************************************************/
int syslog_putc(int ch)
{
ssize_t nbytes;
uint8_t uch;
int errcode;
int ret;
/* Ignore any output:
*
* (1) Before the SYSLOG device has been initialized. This could happen
* from debug output that occurs early in the boot sequence before
* syslog_initialize() is called (SYSLOG_UNINITIALIZED).
* (2) While the device is being initialized. The case could happen if
* debug output is generated while syslog_initialize() executes
* (SYSLOG_INITIALIZING).
* (3) While we are generating SYSLOG output. The case could happen if
* debug output is generated while syslog_putc() executes
* (This case is actually handled inside of syslog_semtake()).
* (4) Any debug output generated from interrupt handlers. A disadvantage
* of using the generic character device for the SYSLOG is that it
* cannot handle debug output generated from interrupt level handlers.
* (5) Any debug output generated from the IDLE loop. The character
* driver interface is blocking and the IDLE thread is not permitted
* to block.
* (6) If an irrecoverable failure occurred during initialization. In
* this case, we won't ever bother to try again (ever).
*
* NOTE: That the third case is different. It applies only to the thread
* that currently holds the sl_sem sempaphore. Other threads should wait.
* that is why that case is handled in syslog_semtake().
*/
/* Cases (4) and (5) */
if (up_interrupt_context() || getpid() == 0)
{
errcode = ENOSYS;
goto errout_with_errcode;
}
/* We can save checks in the usual case: That after the SYSLOG device
* has been successfully opened.
*/
if (g_sysdev.sl_state != SYSLOG_OPENED)
{
/* Case (1) and (2) */
if (g_sysdev.sl_state == SYSLOG_UNINITIALIZED ||
g_sysdev.sl_state == SYSLOG_INITIALIZING)
{
errcode = EAGAIN; /* Can't access the SYSLOG now... maybe next time? */
goto errout_with_errcode;
}
/* Case (6) */
if (g_sysdev.sl_state == SYSLOG_FAILURE)
{
errcode = ENXIO; /* There is no SYSLOG device */
goto errout_with_errcode;
}
/* syslog_initialize() is called as soon as enough of the operating
* system is in place to support the open operation... but it is
* possible that the SYSLOG device is not yet registered at that time.
* In this case, we know that the system is sufficiently initialized
* to support an attempt to re-open the SYSLOG device.
*
* NOTE that the scheduler is locked. That is because we do not have
* fully initialized semaphore capability until the SYSLOG device is
* successfully initialized
*/
sched_lock();
if (g_sysdev.sl_state == SYSLOG_REOPEN)
{
/* Try again to initialize the device. We may do this repeatedly
* because the log device might be something that was not ready
* the first time that syslog_initializee() was called (such as a
* USB serial device that has not yet been connected or a file in
* an NFS mounted file system that has not yet been mounted).
*/
ret = syslog_initialize();
if (ret < 0)
{
sched_unlock();
errcode = -ret;
goto errout_with_errcode;
}
}
sched_unlock();
DEBUGASSERT(g_sysdev.sl_state == SYSLOG_OPENED);
}
/* Ignore carriage returns */
if (ch == '\r')
{
return ch;
}
/* The syslog device is ready for writing and we have something of
* value to write.
*/
ret = syslog_takesem();
if (ret < 0)
{
/* We probably already hold the semaphore and were probably
* re-entered by the logic kicked off by syslog_write().
* We might also have been interrupted by a signal. Either
* way, we are outta here.
*/
errcode = -ret;
goto errout_with_errcode;
}
/* Pre-pend a newline with a carriage return. */
if (ch == '\n')
{
/* Write the CR-LF sequence */
nbytes = syslog_write(g_syscrlf, 2);
/* Synchronize the file when each CR-LF is encountered (i.e.,
* implements line buffering always).
*/
#ifndef CONFIG_DISABLE_MOUNTPOINT
if (nbytes > 0)
{
syslog_flush();
}
#endif
}
else
{
/* Write the non-newline character (and don't flush) */
uch = (uint8_t)ch;
nbytes = syslog_write(&uch, 1);
}
syslog_givesem();
/* Check if the write was successful. If not, nbytes will be
* a negated errno value.
*/
if (nbytes < 0)
{
errcode = -ret;
goto errout_with_errcode;
}
return ch;
errout_with_errcode:
set_errno(errcode);
return EOF;
}
#endif /* CONFIG_SYSLOG && CONFIG_SYSLOG_CHAR */