diff --git a/drivers/syslog/Kconfig b/drivers/syslog/Kconfig index 6c6c8ed1430..f3ab33f9eb8 100644 --- a/drivers/syslog/Kconfig +++ b/drivers/syslog/Kconfig @@ -136,6 +136,20 @@ config SYSLOG_NONE endchoice +config SYSLOG_FILE + bool "Sylog file output" + default n + ---help--- + Build in support to use a file to collect SYSOG output. File SYSLOG + channels differ from other SYSLOG channels in that they cannot be + established until after fully booting and mounting the target file + system. The function syslog_file_channel() would need to be called + from board-specific bring-up logic AFTER mounting the file system + containing 'devpath'. + + NOTE interrupt level SYSLOG output will be lost in this case unless + the interrupt buffer is used. + config CONSOLE_SYSLOG bool "Use SYSLOG for /dev/console" default n diff --git a/drivers/syslog/Make.defs b/drivers/syslog/Make.defs index 6820c39e7d4..95583059e16 100644 --- a/drivers/syslog/Make.defs +++ b/drivers/syslog/Make.defs @@ -72,10 +72,14 @@ ifeq ($(CONFIG_SYSLOG_CHAR),y) CSRCS += syslog_devchannel.c endif -ifeq ($(CONFIG_DEV_CONSOLE),y) +ifeq ($(CONFIG_SYSLOG_CONSOLE),y) CSRCS += syslog_consolechannel.c endif +ifeq ($(CONFIG_SYSLOG_FILE),y) +CSRCS += syslog_filechannel.c +endif + # (Add other SYSLOG drivers here) ifeq ($(CONFIG_CONSOLE_SYSLOG),y) diff --git a/drivers/syslog/syslog.h b/drivers/syslog/syslog.h index c1c882c3cd4..3ebb480f00a 100644 --- a/drivers/syslog/syslog.h +++ b/drivers/syslog/syslog.h @@ -58,9 +58,15 @@ extern "C" #define EXTERN extern #endif -/* This is the current syslog channel in use */ +/* The default SYSLOG channel */ struct syslog_channel_s; /* Forward reference */ +EXTERN const struct syslog_channel_s g_default_syslog_channel; + +/* This is the current syslog channel in use. It initially points to + * g_default_syslog_channel. + */ + EXTERN FAR const struct syslog_channel_s *g_syslog_channel; /**************************************************************************** @@ -85,6 +91,8 @@ EXTERN FAR const struct syslog_channel_s *g_syslog_channel; * * Input Parameters: * devpath - The full path to the character device to be used. + * oflags - File open flags + * mode - File open mode (only if oflags include O_CREAT) * * Returned Value: * Zero (OK) is returned on success; a negated errno value is returned on @@ -93,9 +101,33 @@ EXTERN FAR const struct syslog_channel_s *g_syslog_channel; ****************************************************************************/ #if CONFIG_NFILE_DESCRIPTORS > 0 -int syslog_dev_initialize(FAR const char *devpath); +int syslog_dev_initialize(FAR const char *devpath, int oflags, int mode); #endif +/**************************************************************************** + * Name: syslog_dev_uninitialize + * + * Description: + * Called to disable the last device/file channel in preparation to use + * a different SYSLOG device. Currently only used for CONFIG_SYSLOG_FILE. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * The caller has already switched the SYSLOG source to some safe channel + * (the default channel). + * + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_SYSLOG_FILE) +int syslog_dev_uninitialize(void); +#endif /* CONFIG_SYSLOG_FILE */ + /**************************************************************************** * Name: syslog_dev_channel * @@ -151,7 +183,7 @@ int syslog_dev_channel(void); * ****************************************************************************/ -#ifdef CONFIG_DEV_CONSOLE +#ifdef CONFIG_SYSLOG_CONSOLE int syslog_console_channel(void); #endif diff --git a/drivers/syslog/syslog_channel.c b/drivers/syslog/syslog_channel.c index 38eb801b08f..2afee2a1ab2 100644 --- a/drivers/syslog/syslog_channel.c +++ b/drivers/syslog/syslog_channel.c @@ -63,25 +63,25 @@ static int syslog_default_putc(int ch); static int syslog_default_flush(void); /**************************************************************************** - * Private Data + * Public Data ****************************************************************************/ #if defined(CONFIG_RAMLOG_SYSLOG) -static const struct syslog_channel_s g_default_channel = +const struct syslog_channel_s g_default_channel = { ramlog_putc, ramlog_putc, syslog_default_flush }; #elif defined(CONFIG_SYSLOG_SERIAL_CONSOLE) && defined(CONFIG_ARCH_LOWPUTC) -static const struct syslog_channel_s g_default_channel = +const struct syslog_channel_s g_default_channel = { up_putc, up_putc, syslog_default_flush }; #else -static const struct syslog_channel_s g_default_channel = +const struct syslog_channel_s g_default_channel = { syslog_default_putc, syslog_default_putc, @@ -89,10 +89,6 @@ static const struct syslog_channel_s g_default_channel = }; #endif -/**************************************************************************** - * Public Data - ****************************************************************************/ - /* This is the current syslog channel in use */ FAR const struct syslog_channel_s *g_syslog_channel = &g_default_channel; diff --git a/drivers/syslog/syslog_consolechannel.c b/drivers/syslog/syslog_consolechannel.c index 2d33478f797..8ed6374ff65 100644 --- a/drivers/syslog/syslog_consolechannel.c +++ b/drivers/syslog/syslog_consolechannel.c @@ -39,6 +39,9 @@ #include +#include +#include + #include #include @@ -47,7 +50,7 @@ #ifdef CONFIG_SYSLOG_CONSOLE /**************************************************************************** - * Private Functions + * Pre-processor Definitions ****************************************************************************/ #undef HAVE_LOWPUTC @@ -55,6 +58,9 @@ # define HAVE_LOWPUTC 1 #endif +#define OPEN_FLAGS (O_WRONLY) +#define OPEN_MODE (S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR) + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -73,7 +79,7 @@ static int syslog_console_force(int ch); * Private Data ****************************************************************************/ -/* This structure describes the ITM SYSLOG channel */ +/* This structure describes the SYSLOG channel */ static const struct syslog_channel_s g_syslog_console_channel = { @@ -142,7 +148,7 @@ int syslog_console_channel(void) /* Initialize the character driver interface */ - ret = syslog_dev_initialize("/dev/console"); + ret = syslog_dev_initialize("/dev/console", OPEN_FLAGS, OPEN_MODE); if (ret < 0) { return ret; diff --git a/drivers/syslog/syslog_devchannel.c b/drivers/syslog/syslog_devchannel.c index 709b4c82b12..fc6c439d83a 100644 --- a/drivers/syslog/syslog_devchannel.c +++ b/drivers/syslog/syslog_devchannel.c @@ -39,6 +39,9 @@ #include +#include +#include + #include #include "syslog.h" @@ -46,9 +49,12 @@ #ifdef CONFIG_SYSLOG_CHAR /**************************************************************************** - * Private Functions + * Pre-processor Definitions ****************************************************************************/ +#define OPEN_FLAGS (O_WRONLY) +#define OPEN_MODE (S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR) + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -61,7 +67,7 @@ static int syslog_dev_force(int ch); * Private Data ****************************************************************************/ -/* This structure describes the ITM SYSLOG channel */ +/* This structure describes the SYSLOG channel */ static const struct syslog_channel_s g_syslog_dev_channel = { @@ -95,8 +101,8 @@ static int syslog_dev_force(int ch) * Name: syslog_dev_channel * * Description: - * Configure to use the character device (or file) at - * CONFIG_SYSLOG_DEVPATH as the SYSLOG channel. + * Configure to use the character device at CONFIG_SYSLOG_DEVPATH as the + * SYSLOG channel. * * This tiny function is simply a wrapper around syslog_dev_initialize() * and syslog_channel(). It calls syslog_dev_initialize() to configure @@ -121,7 +127,7 @@ int syslog_dev_channel(void) /* Initialize the character driver interface */ - ret = syslog_dev_initialize(CONFIG_SYSLOG_DEVPATH); + ret = syslog_dev_initialize(CONFIG_SYSLOG_DEVPATH, OPEN_FLAGS, OPEN_MODE); if (ret < 0) { return ret; diff --git a/drivers/syslog/syslog_device.c b/drivers/syslog/syslog_device.c index 71f905714de..25639e4b50c 100644 --- a/drivers/syslog/syslog_device.c +++ b/drivers/syslog/syslog_device.c @@ -45,13 +45,15 @@ #include #include #include +#include #include #include #include #include -#include #include +#include +#include #include #include "syslog.h" @@ -92,11 +94,13 @@ enum syslog_dev_state struct syslog_dev_s { - uint8_t sl_state; /* See enum syslog_dev_state */ - 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 */ - FAR const char *sl_devpath; /* Full path to the character device */ + uint8_t sl_state; /* See enum syslog_dev_state */ + uint8_t sl_oflags; /* Saved open mode (for re-open) */ + uint16_t sl_mode; /* Saved open flags (for re-open) */ + 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 */ + FAR char *sl_devpath; /* Full path to the character device */ }; /**************************************************************************** @@ -222,6 +226,8 @@ static inline ssize_t syslog_dev_write(FAR const void *buf, size_t nbytes) * * Input Parameters: * devpath - The full path to the character device to be used. + * oflags - File open flags + * mode - File open mode (only if oflags include O_CREAT) * * Returned Value: * Zero (OK) is returned on success; a negated errno value is returned on @@ -229,7 +235,7 @@ static inline ssize_t syslog_dev_write(FAR const void *buf, size_t nbytes) * ****************************************************************************/ -int syslog_dev_initialize(FAR const char *devpath) +int syslog_dev_initialize(FAR const char *devpath, int oflags, int mode) { int fd; int ret; @@ -262,6 +268,8 @@ int syslog_dev_initialize(FAR const char *devpath) */ DEBUGASSERT(g_syslog_dev.sl_devpath == NULL); + g_syslog_dev.sl_oflags = oflags; + g_syslog_dev.sl_mode = mode; g_syslog_dev.sl_devpath = strdup(devpath); DEBUGASSERT(g_syslog_dev.sl_devpath != NULL); } @@ -270,7 +278,7 @@ int syslog_dev_initialize(FAR const char *devpath) /* Open the device driver. */ - fd = open(devpath, O_WRONLY); + fd = open(devpath, oflags, mode); if (fd < 0) { int errcode = get_errno(); @@ -315,6 +323,57 @@ int syslog_dev_initialize(FAR const char *devpath) return OK; } +/**************************************************************************** + * Name: syslog_dev_uninitialize + * + * Description: + * Called to disable the last device/file channel in preparation to use + * a different SYSLOG device. Currently only used for CONFIG_SYSLOG_FILE. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * The caller has already switched the SYSLOG source to some safe channel + * (the default channel). + * + ****************************************************************************/ + +#ifdef CONFIG_SYSLOG_FILE /* Currently only used in this configuration */ +int syslog_dev_uninitialize(void) +{ + /* Attempt to flush any buffered data */ + + sched_lock(); + (void)syslog_dev_flush(); + + /* Close the detached file instance */ + + (void)file_close_detached(&g_syslog_dev.sl_file); + + /* Free the device path */ + + if (g_syslog_dev.sl_devpath != NULL) + { + kmm_free(g_syslog_dev.sl_devpath); + } + + /* Destroy the semaphore */ + + sem_destroy(&g_syslog_dev.sl_sem); + + /* Reset the state structure */ + + memset(&g_syslog_dev, 0, sizeof(struct syslog_dev_s)); + sched_unlock(); + return OK; +} +#endif /* CONFIG_SYSLOG_FILE */ + /**************************************************************************** * Name: syslog_dev_putc * @@ -416,7 +475,9 @@ int syslog_dev_putc(int ch) */ DEBUGASSERT(g_syslog_dev.sl_devpath != NULL); - ret = syslog_dev_initialize(g_syslog_dev.sl_devpath); + ret = syslog_dev_initialize(g_syslog_dev.sl_devpath, + (int)g_syslog_dev.sl_oflags, + (int)g_syslog_dev.sl_mode); if (ret < 0) { sched_unlock(); @@ -522,8 +583,7 @@ int syslog_dev_flush(void) /* Is this a mountpoint? Does it support the sync method? */ - DEBUGASSERT(inode != NULL); - if (inode->u.i_mops->sync) + if (inode && inode->u.i_mops->sync) { /* Yes... synchronize to the stream */ diff --git a/include/nuttx/syslog/syslog.h b/include/nuttx/syslog/syslog.h index 255a6e2f3aa..f7709261c37 100644 --- a/include/nuttx/syslog/syslog.h +++ b/include/nuttx/syslog/syslog.h @@ -194,6 +194,46 @@ int syslog_initialize(enum syslog_init_e phase); # define syslog_initialize(phase) #endif +/**************************************************************************** + * Name: syslog_file_channel + * + * Description: + * Configure to use a file in a mounted file system at 'devpath' as the + * SYSLOG channel. + * + * This tiny function is simply a wrapper around syslog_dev_initialize() + * and syslog_channel(). It calls syslog_dev_initialize() to configure + * the character file at 'devpath then calls syslog_channel() to use that + * device as the SYSLOG output channel. + * + * File SYSLOG channels differ from other SYSLOG channels in that they + * cannot be established until after fully booting and mounting the target + * file system. This function would need to be called from board-specific + * bring-up logic AFTER mounting the file system containing 'devpath'. + * + * SYSLOG data generated prior to calling syslog_file_channel will, of + * course, not be included in the file. + * + * NOTE interrupt level SYSLOG output will be lost in this case unless + * the interrupt buffer is used. + * + * Input Parameters: + * devpath - The full path to the file to be used for SYSLOG output. + * This may be an existing file or not. If the file exists, + * syslog_file_channel() will append new SYSLOG data to the end of the + * file. If it does not, then syslog_file_channel() will create the + * file. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SYSLOG_FILE +int syslog_file_channel(FAR const char *devpath); +#endif + /**************************************************************************** * Name: syslog_flush *