1beacf11bSopenharmony_ci/**************************************************************************** 2beacf11bSopenharmony_ci * fs/driver/fs_devsyslog.c 3beacf11bSopenharmony_ci * 4beacf11bSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5beacf11bSopenharmony_ci * Based on NuttX originally written by Gregory Nutt 6beacf11bSopenharmony_ci * 7beacf11bSopenharmony_ci * Copyright (C) 2012 Gregory Nutt. All rights reserved. 8beacf11bSopenharmony_ci * Author: Gregory Nutt <gnutt@nuttx.org> 9beacf11bSopenharmony_ci * 10beacf11bSopenharmony_ci * Redistribution and use in source and binary forms, with or without 11beacf11bSopenharmony_ci * modification, are permitted provided that the following conditions 12beacf11bSopenharmony_ci * are met: 13beacf11bSopenharmony_ci * 14beacf11bSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 15beacf11bSopenharmony_ci * notice, this list of conditions and the following disclaimer. 16beacf11bSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 17beacf11bSopenharmony_ci * notice, this list of conditions and the following disclaimer in 18beacf11bSopenharmony_ci * the documentation and/or other materials provided with the 19beacf11bSopenharmony_ci * distribution. 20beacf11bSopenharmony_ci * 3. Neither the name NuttX nor the names of its contributors may be 21beacf11bSopenharmony_ci * used to endorse or promote products derived from this software 22beacf11bSopenharmony_ci * without specific prior written permission. 23beacf11bSopenharmony_ci * 24beacf11bSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25beacf11bSopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26beacf11bSopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27beacf11bSopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28beacf11bSopenharmony_ci * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29beacf11bSopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30beacf11bSopenharmony_ci * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 31beacf11bSopenharmony_ci * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32beacf11bSopenharmony_ci * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33beacf11bSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34beacf11bSopenharmony_ci * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35beacf11bSopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 36beacf11bSopenharmony_ci * 37beacf11bSopenharmony_ci ****************************************************************************/ 38beacf11bSopenharmony_ci 39beacf11bSopenharmony_ci/**************************************************************************** 40beacf11bSopenharmony_ci * Included Files 41beacf11bSopenharmony_ci ****************************************************************************/ 42beacf11bSopenharmony_ci 43beacf11bSopenharmony_ci#include "los_task.h" 44beacf11bSopenharmony_ci#include "vfs_config.h" 45beacf11bSopenharmony_ci#include "sys/types.h" 46beacf11bSopenharmony_ci#include "stdint.h" 47beacf11bSopenharmony_ci#include "stdio.h" 48beacf11bSopenharmony_ci#include "unistd.h" 49beacf11bSopenharmony_ci#include "fcntl.h" 50beacf11bSopenharmony_ci#include "semaphore.h" 51beacf11bSopenharmony_ci#include "assert.h" 52beacf11bSopenharmony_ci#include "fs/driver.h" 53beacf11bSopenharmony_ci#include "inode/inode.h" 54beacf11bSopenharmony_ci 55beacf11bSopenharmony_ci#if defined(CONFIG_SYSLOG) && defined(CONFIG_SYSLOG_CHAR) 56beacf11bSopenharmony_ci 57beacf11bSopenharmony_ci/**************************************************************************** 58beacf11bSopenharmony_ci * Pre-processor Definitions 59beacf11bSopenharmony_ci ****************************************************************************/ 60beacf11bSopenharmony_ci 61beacf11bSopenharmony_ci/* Open the device/file write-only, try to create (file) it if it doesn't 62beacf11bSopenharmony_ci * exist, if the file that already exists, then append the new log data to 63beacf11bSopenharmony_ci * end of the file. 64beacf11bSopenharmony_ci */ 65beacf11bSopenharmony_ci 66beacf11bSopenharmony_ci#define SYSLOG_OFLAGS (O_WRONLY | O_CREAT | O_APPEND) 67beacf11bSopenharmony_ci 68beacf11bSopenharmony_ci/* An invalid thread ID */ 69beacf11bSopenharmony_ci 70beacf11bSopenharmony_ci#define NO_HOLDER ((pid_t)-1) 71beacf11bSopenharmony_ci 72beacf11bSopenharmony_ci/**************************************************************************** 73beacf11bSopenharmony_ci * Private Types 74beacf11bSopenharmony_ci ****************************************************************************/ 75beacf11bSopenharmony_ci 76beacf11bSopenharmony_ci/* This enumeration represents the state of the SYSLOG device interface */ 77beacf11bSopenharmony_ci 78beacf11bSopenharmony_cienum syslog_state_e 79beacf11bSopenharmony_ci{ 80beacf11bSopenharmony_ci SYSLOG_UNINITIALIZED = 0, /* SYSLOG has not been initialized */ 81beacf11bSopenharmony_ci SYSLOG_INITIALIZING, /* SYSLOG is being initialized */ 82beacf11bSopenharmony_ci SYSLOG_REOPEN, /* SYSLOG open failed... try again later */ 83beacf11bSopenharmony_ci SYSLOG_FAILURE, /* SYSLOG open failed... don't try again */ 84beacf11bSopenharmony_ci SYSLOG_OPENED, /* SYSLOG device is open and ready to use */ 85beacf11bSopenharmony_ci}; 86beacf11bSopenharmony_ci 87beacf11bSopenharmony_ci/* This structure contains all SYSLOGing state information */ 88beacf11bSopenharmony_ci 89beacf11bSopenharmony_cistruct syslog_dev_s 90beacf11bSopenharmony_ci{ 91beacf11bSopenharmony_ci uint8_t sl_state; /* See enum syslog_state_e */ 92beacf11bSopenharmony_ci sem_t sl_sem; /* Enforces mutually exclusive access */ 93beacf11bSopenharmony_ci pid_t sl_holder; /* PID of the thread that holds the semaphore */ 94beacf11bSopenharmony_ci struct file sl_file; /* The syslog file structure */ 95beacf11bSopenharmony_ci}; 96beacf11bSopenharmony_ci 97beacf11bSopenharmony_ci/**************************************************************************** 98beacf11bSopenharmony_ci * Private Function Prototypes 99beacf11bSopenharmony_ci ****************************************************************************/ 100beacf11bSopenharmony_ci 101beacf11bSopenharmony_ci/**************************************************************************** 102beacf11bSopenharmony_ci * Private Data 103beacf11bSopenharmony_ci ****************************************************************************/ 104beacf11bSopenharmony_ci 105beacf11bSopenharmony_ci/* This is the device structure for the console or syslogging function. */ 106beacf11bSopenharmony_ci 107beacf11bSopenharmony_cistatic struct syslog_dev_s g_sysdev; 108beacf11bSopenharmony_cistatic const uint8_t g_syscrlf[2] = 109beacf11bSopenharmony_ci{ 110beacf11bSopenharmony_ci '\r', '\n' 111beacf11bSopenharmony_ci}; 112beacf11bSopenharmony_ci 113beacf11bSopenharmony_ci/**************************************************************************** 114beacf11bSopenharmony_ci * Private Functions 115beacf11bSopenharmony_ci ****************************************************************************/ 116beacf11bSopenharmony_ci 117beacf11bSopenharmony_ci/**************************************************************************** 118beacf11bSopenharmony_ci * Name: syslog_takesem 119beacf11bSopenharmony_ci * 120beacf11bSopenharmony_ci * Description: 121beacf11bSopenharmony_ci * Write to the syslog device 122beacf11bSopenharmony_ci * 123beacf11bSopenharmony_ci ****************************************************************************/ 124beacf11bSopenharmony_ci 125beacf11bSopenharmony_cistatic inline int syslog_takesem(void) 126beacf11bSopenharmony_ci{ 127beacf11bSopenharmony_ci pid_t me = getpid(); 128beacf11bSopenharmony_ci int ret; 129beacf11bSopenharmony_ci 130beacf11bSopenharmony_ci /* Does this thread already hold the semaphore? That could happen if 131beacf11bSopenharmony_ci * we wer called recursively, i.e., if the logic kicked off by 132beacf11bSopenharmony_ci * syslog_write() where to generate more debug output. Return an error 133beacf11bSopenharmony_ci * in that case. 134beacf11bSopenharmony_ci */ 135beacf11bSopenharmony_ci 136beacf11bSopenharmony_ci if (g_sysdev.sl_holder == me) 137beacf11bSopenharmony_ci { 138beacf11bSopenharmony_ci /* Return an error (instead of deadlocking) */ 139beacf11bSopenharmony_ci 140beacf11bSopenharmony_ci return -EWOULDBLOCK; 141beacf11bSopenharmony_ci } 142beacf11bSopenharmony_ci 143beacf11bSopenharmony_ci /* Either the semaphore is available or is currently held by another 144beacf11bSopenharmony_ci * thread. Wait for it to become available. 145beacf11bSopenharmony_ci */ 146beacf11bSopenharmony_ci 147beacf11bSopenharmony_ci ret = sem_wait(&g_sysdev.sl_sem); 148beacf11bSopenharmony_ci if (ret < 0) 149beacf11bSopenharmony_ci { 150beacf11bSopenharmony_ci return -get_errno(); 151beacf11bSopenharmony_ci } 152beacf11bSopenharmony_ci 153beacf11bSopenharmony_ci /* We hold the semaphore. We can safely mark ourself as the holder 154beacf11bSopenharmony_ci * of the semaphore. 155beacf11bSopenharmony_ci */ 156beacf11bSopenharmony_ci 157beacf11bSopenharmony_ci g_sysdev.sl_holder = me; 158beacf11bSopenharmony_ci return OK; 159beacf11bSopenharmony_ci} 160beacf11bSopenharmony_ci 161beacf11bSopenharmony_ci/**************************************************************************** 162beacf11bSopenharmony_ci * Name: syslog_givesem 163beacf11bSopenharmony_ci * 164beacf11bSopenharmony_ci * Description: 165beacf11bSopenharmony_ci * Write to the syslog device 166beacf11bSopenharmony_ci * 167beacf11bSopenharmony_ci ****************************************************************************/ 168beacf11bSopenharmony_ci 169beacf11bSopenharmony_cistatic inline void syslog_givesem(void) 170beacf11bSopenharmony_ci{ 171beacf11bSopenharmony_ci#ifdef CONFIG_DEBUG 172beacf11bSopenharmony_ci pid_t me = getpid(); 173beacf11bSopenharmony_ci DEBUGASSERT(g_sysdev.sl_holder == me); 174beacf11bSopenharmony_ci#endif 175beacf11bSopenharmony_ci 176beacf11bSopenharmony_ci /* Relinquish the semaphore */ 177beacf11bSopenharmony_ci 178beacf11bSopenharmony_ci g_sysdev.sl_holder = NO_HOLDER; 179beacf11bSopenharmony_ci (void)sem_post(&g_sysdev.sl_sem); 180beacf11bSopenharmony_ci} 181beacf11bSopenharmony_ci 182beacf11bSopenharmony_ci/**************************************************************************** 183beacf11bSopenharmony_ci * Name: syslog_write 184beacf11bSopenharmony_ci * 185beacf11bSopenharmony_ci * Description: 186beacf11bSopenharmony_ci * Write to the syslog device 187beacf11bSopenharmony_ci * 188beacf11bSopenharmony_ci ****************************************************************************/ 189beacf11bSopenharmony_ci 190beacf11bSopenharmony_cistatic inline ssize_t syslog_write(const void *buf, size_t nbytes) 191beacf11bSopenharmony_ci{ 192beacf11bSopenharmony_ci struct inode *inode_ptr; 193beacf11bSopenharmony_ci 194beacf11bSopenharmony_ci /* Let the driver perform the write */ 195beacf11bSopenharmony_ci 196beacf11bSopenharmony_ci inode_ptr = g_sysdev.sl_file.f_inode; 197beacf11bSopenharmony_ci return inode_ptr->u.i_ops->write(&g_sysdev.sl_file, (const char *)buf, nbytes); 198beacf11bSopenharmony_ci} 199beacf11bSopenharmony_ci 200beacf11bSopenharmony_ci/**************************************************************************** 201beacf11bSopenharmony_ci * Name: syslog_flush 202beacf11bSopenharmony_ci * 203beacf11bSopenharmony_ci * Description: 204beacf11bSopenharmony_ci * Flush any buffer data in the file system to media. 205beacf11bSopenharmony_ci * 206beacf11bSopenharmony_ci ****************************************************************************/ 207beacf11bSopenharmony_ci 208beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_MOUNTPOINT 209beacf11bSopenharmony_cistatic inline void syslog_flush(void) 210beacf11bSopenharmony_ci{ 211beacf11bSopenharmony_ci struct inode *inode_ptr = g_sysdev.sl_file.f_inode; 212beacf11bSopenharmony_ci 213beacf11bSopenharmony_ci /* Is this a mountpoint? Does it support the sync method? */ 214beacf11bSopenharmony_ci 215beacf11bSopenharmony_ci if (INODE_IS_MOUNTPT(inode_ptr) && inode_ptr->u.i_mops->sync) 216beacf11bSopenharmony_ci { 217beacf11bSopenharmony_ci /* Yes... synchronize to the stream */ 218beacf11bSopenharmony_ci 219beacf11bSopenharmony_ci (void)inode_ptr->u.i_mops->sync(&g_sysdev.sl_file); 220beacf11bSopenharmony_ci } 221beacf11bSopenharmony_ci} 222beacf11bSopenharmony_ci#endif 223beacf11bSopenharmony_ci 224beacf11bSopenharmony_ci/**************************************************************************** 225beacf11bSopenharmony_ci * Public Functions 226beacf11bSopenharmony_ci ****************************************************************************/ 227beacf11bSopenharmony_ci 228beacf11bSopenharmony_ci/**************************************************************************** 229beacf11bSopenharmony_ci * Name: syslog_initialize 230beacf11bSopenharmony_ci * 231beacf11bSopenharmony_ci * Description: 232beacf11bSopenharmony_ci * Initialize to use the character device (or file) at 233beacf11bSopenharmony_ci * CONFIG_SYSLOG_DEVPATH as the SYSLOG sink. 234beacf11bSopenharmony_ci * 235beacf11bSopenharmony_ci * NOTE that this implementation excludes using a network connection as 236beacf11bSopenharmony_ci * SYSLOG device. That would be a good extension. 237beacf11bSopenharmony_ci * 238beacf11bSopenharmony_ci ****************************************************************************/ 239beacf11bSopenharmony_ci 240beacf11bSopenharmony_ciint syslog_initialize(void) 241beacf11bSopenharmony_ci{ 242beacf11bSopenharmony_ci struct inode *inode_ptr; 243beacf11bSopenharmony_ci const char *relpath = NULL; 244beacf11bSopenharmony_ci int ret; 245beacf11bSopenharmony_ci struct inode_search_s desc; 246beacf11bSopenharmony_ci 247beacf11bSopenharmony_ci /* At this point, the only expected states are SYSLOG_UNINITIALIZED or 248beacf11bSopenharmony_ci * SYSLOG_REOPEN.. Not SYSLOG_INITIALIZING, SYSLOG_FAILURE, SYSLOG_OPENED. 249beacf11bSopenharmony_ci */ 250beacf11bSopenharmony_ci 251beacf11bSopenharmony_ci DEBUGASSERT(g_sysdev.sl_state == SYSLOG_UNINITIALIZED || 252beacf11bSopenharmony_ci g_sysdev.sl_state == SYSLOG_REOPEN); 253beacf11bSopenharmony_ci 254beacf11bSopenharmony_ci g_sysdev.sl_state = SYSLOG_INITIALIZING; 255beacf11bSopenharmony_ci 256beacf11bSopenharmony_ci /* Try to open the device. 257beacf11bSopenharmony_ci * 258beacf11bSopenharmony_ci * Note that we cannot just call open. The syslog device must work on all 259beacf11bSopenharmony_ci * threads. Open returns a file descriptor that is valid only for the 260beacf11bSopenharmony_ci * task that opened the device (and its pthread children). Instead, we 261beacf11bSopenharmony_ci * essentially re-implement the guts of open() here so that we can get to 262beacf11bSopenharmony_ci * the thread-independent structures of the inode. 263beacf11bSopenharmony_ci */ 264beacf11bSopenharmony_ci 265beacf11bSopenharmony_ci /* Get an inode for this file/device */ 266beacf11bSopenharmony_ci 267beacf11bSopenharmony_ci SETUP_SEARCH(&desc, CONFIG_SYSLOG_DEVPATH, false); 268beacf11bSopenharmony_ci ret = inode_find(&desc); 269beacf11bSopenharmony_ci 270beacf11bSopenharmony_ci /* Get the search results */ 271beacf11bSopenharmony_ci 272beacf11bSopenharmony_ci if (ret < 0) 273beacf11bSopenharmony_ci { 274beacf11bSopenharmony_ci /* The inode was not found. In this case, we will attempt to re-open 275beacf11bSopenharmony_ci * the device repeatedly. The assumption is that the device path is 276beacf11bSopenharmony_ci * valid but that the driver has not yet been registered. 277beacf11bSopenharmony_ci */ 278beacf11bSopenharmony_ci 279beacf11bSopenharmony_ci g_sysdev.sl_state = SYSLOG_REOPEN; 280beacf11bSopenharmony_ci return -EACCES; 281beacf11bSopenharmony_ci } 282beacf11bSopenharmony_ci inode_ptr = desc.node; 283beacf11bSopenharmony_ci relpath = desc.relpath; 284beacf11bSopenharmony_ci 285beacf11bSopenharmony_ci /* Verify that the inode is valid and either a character driver or a 286beacf11bSopenharmony_ci * mountpoint. 287beacf11bSopenharmony_ci */ 288beacf11bSopenharmony_ci 289beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_MOUNTPOINT 290beacf11bSopenharmony_ci if ((!INODE_IS_DRIVER(inode_ptr) && !INODE_IS_MOUNTPT(inode_ptr))) 291beacf11bSopenharmony_ci#else 292beacf11bSopenharmony_ci if (!INODE_IS_DRIVER(inode_ptr)) 293beacf11bSopenharmony_ci#endif 294beacf11bSopenharmony_ci { 295beacf11bSopenharmony_ci ret = -ENXIO; 296beacf11bSopenharmony_ci goto errout_with_inode; 297beacf11bSopenharmony_ci } 298beacf11bSopenharmony_ci 299beacf11bSopenharmony_ci /* Make sure that the "entity" at this inode supports write access */ 300beacf11bSopenharmony_ci 301beacf11bSopenharmony_ci if (!inode_ptr->u.i_ops || !inode_ptr->u.i_ops->write) 302beacf11bSopenharmony_ci { 303beacf11bSopenharmony_ci ret = -EACCES; 304beacf11bSopenharmony_ci goto errout_with_inode; 305beacf11bSopenharmony_ci } 306beacf11bSopenharmony_ci 307beacf11bSopenharmony_ci /* Initialize the file structure */ 308beacf11bSopenharmony_ci 309beacf11bSopenharmony_ci g_sysdev.sl_file.f_oflags = SYSLOG_OFLAGS; 310beacf11bSopenharmony_ci g_sysdev.sl_file.f_pos = 0; 311beacf11bSopenharmony_ci g_sysdev.sl_file.f_inode = inode_ptr; 312beacf11bSopenharmony_ci 313beacf11bSopenharmony_ci /* Perform the low-level open operation. */ 314beacf11bSopenharmony_ci 315beacf11bSopenharmony_ci ret = OK; 316beacf11bSopenharmony_ci if (inode_ptr->u.i_ops->open) 317beacf11bSopenharmony_ci { 318beacf11bSopenharmony_ci /* Is the inode a mountpoint? */ 319beacf11bSopenharmony_ci 320beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_MOUNTPOINT 321beacf11bSopenharmony_ci if (INODE_IS_MOUNTPT(inode_ptr)) 322beacf11bSopenharmony_ci { 323beacf11bSopenharmony_ci /* Yes. Open the device write-only, try to create it if it 324beacf11bSopenharmony_ci * doesn't exist, if the file that already exists, then append the 325beacf11bSopenharmony_ci * new log data to end of the file. 326beacf11bSopenharmony_ci */ 327beacf11bSopenharmony_ci 328beacf11bSopenharmony_ci ret = inode_ptr->u.i_mops->open(&g_sysdev.sl_file, relpath, 329beacf11bSopenharmony_ci SYSLOG_OFLAGS, 0666); 330beacf11bSopenharmony_ci } 331beacf11bSopenharmony_ci 332beacf11bSopenharmony_ci /* No... then it must be a character driver in the NuttX pseudo- 333beacf11bSopenharmony_ci * file system. 334beacf11bSopenharmony_ci */ 335beacf11bSopenharmony_ci 336beacf11bSopenharmony_ci else 337beacf11bSopenharmony_ci#endif 338beacf11bSopenharmony_ci { 339beacf11bSopenharmony_ci ret = inode_ptr->u.i_ops->open(&g_sysdev.sl_file); 340beacf11bSopenharmony_ci } 341beacf11bSopenharmony_ci } 342beacf11bSopenharmony_ci 343beacf11bSopenharmony_ci /* Was the file/device successfully opened? */ 344beacf11bSopenharmony_ci 345beacf11bSopenharmony_ci if (ret < 0) 346beacf11bSopenharmony_ci { 347beacf11bSopenharmony_ci ret = -ret; 348beacf11bSopenharmony_ci goto errout_with_inode; 349beacf11bSopenharmony_ci } 350beacf11bSopenharmony_ci 351beacf11bSopenharmony_ci /* The SYSLOG device is open and ready for writing. */ 352beacf11bSopenharmony_ci 353beacf11bSopenharmony_ci (void)sem_init(&g_sysdev.sl_sem, 0, 1); 354beacf11bSopenharmony_ci g_sysdev.sl_holder = NO_HOLDER; 355beacf11bSopenharmony_ci g_sysdev.sl_state = SYSLOG_OPENED; 356beacf11bSopenharmony_ci return OK; 357beacf11bSopenharmony_ci 358beacf11bSopenharmony_cierrout_with_inode: 359beacf11bSopenharmony_ci inode_release(inode_ptr); 360beacf11bSopenharmony_ci g_sysdev.sl_state = SYSLOG_FAILURE; 361beacf11bSopenharmony_ci return ret; 362beacf11bSopenharmony_ci} 363beacf11bSopenharmony_ci 364beacf11bSopenharmony_ci/**************************************************************************** 365beacf11bSopenharmony_ci * Name: syslog_putc 366beacf11bSopenharmony_ci * 367beacf11bSopenharmony_ci * Description: 368beacf11bSopenharmony_ci * This is the low-level system logging interface. The debugging/syslogging 369beacf11bSopenharmony_ci * interfaces are syslog() and lowsyslog(). The difference is is that 370beacf11bSopenharmony_ci * the syslog() function writes to syslogging device (usually fd=1, stdout) 371beacf11bSopenharmony_ci * whereas lowsyslog() uses a lower level interface that works from 372beacf11bSopenharmony_ci * interrupt handlers. This function is a a low-level interface used to 373beacf11bSopenharmony_ci * implement lowsyslog(). 374beacf11bSopenharmony_ci * 375beacf11bSopenharmony_ci ****************************************************************************/ 376beacf11bSopenharmony_ci 377beacf11bSopenharmony_ciint syslog_putc(int ch) 378beacf11bSopenharmony_ci{ 379beacf11bSopenharmony_ci ssize_t nbytes; 380beacf11bSopenharmony_ci uint8_t uch; 381beacf11bSopenharmony_ci int errcode; 382beacf11bSopenharmony_ci int ret; 383beacf11bSopenharmony_ci 384beacf11bSopenharmony_ci /* Ignore any output: 385beacf11bSopenharmony_ci * 386beacf11bSopenharmony_ci * (1) Before the SYSLOG device has been initialized. This could happen 387beacf11bSopenharmony_ci * from debug output that occurs early in the boot sequence before 388beacf11bSopenharmony_ci * syslog_initialize() is called (SYSLOG_UNINITIALIZED). 389beacf11bSopenharmony_ci * (2) While the device is being initialized. The case could happen if 390beacf11bSopenharmony_ci * debug output is generated while syslog_initialize() executes 391beacf11bSopenharmony_ci * (SYSLOG_INITIALIZING). 392beacf11bSopenharmony_ci * (3) While we are generating SYSLOG output. The case could happen if 393beacf11bSopenharmony_ci * debug output is generated while syslog_putc() executes 394beacf11bSopenharmony_ci * (This case is actually handled inside of syslog_semtake()). 395beacf11bSopenharmony_ci * (4) Any debug output generated from interrupt handlers. A disadvantage 396beacf11bSopenharmony_ci * of using the generic character device for the SYSLOG is that it 397beacf11bSopenharmony_ci * cannot handle debug output generated from interrupt level handlers. 398beacf11bSopenharmony_ci * (5) Any debug output generated from the IDLE loop. The character 399beacf11bSopenharmony_ci * driver interface is blocking and the IDLE thread is not permitted 400beacf11bSopenharmony_ci * to block. 401beacf11bSopenharmony_ci * (6) If an irrecoverable failure occurred during initialization. In 402beacf11bSopenharmony_ci * this case, we won't ever bother to try again (ever). 403beacf11bSopenharmony_ci * 404beacf11bSopenharmony_ci * NOTE: That the third case is different. It applies only to the thread 405beacf11bSopenharmony_ci * that currently holds the sl_sem sempaphore. Other threads should wait. 406beacf11bSopenharmony_ci * that is why that case is handled in syslog_semtake(). 407beacf11bSopenharmony_ci */ 408beacf11bSopenharmony_ci 409beacf11bSopenharmony_ci /* Cases (4) and (5) */ 410beacf11bSopenharmony_ci 411beacf11bSopenharmony_ci if (OS_INT_ACTIVE || getpid() == 0) 412beacf11bSopenharmony_ci { 413beacf11bSopenharmony_ci errcode = ENOSYS; 414beacf11bSopenharmony_ci goto errout_with_errcode; 415beacf11bSopenharmony_ci } 416beacf11bSopenharmony_ci 417beacf11bSopenharmony_ci /* We can save checks in the usual case: That after the SYSLOG device 418beacf11bSopenharmony_ci * has been successfully opened. 419beacf11bSopenharmony_ci */ 420beacf11bSopenharmony_ci 421beacf11bSopenharmony_ci if (g_sysdev.sl_state != SYSLOG_OPENED) 422beacf11bSopenharmony_ci { 423beacf11bSopenharmony_ci /* Case (1) and (2) */ 424beacf11bSopenharmony_ci 425beacf11bSopenharmony_ci if (g_sysdev.sl_state == SYSLOG_UNINITIALIZED || 426beacf11bSopenharmony_ci g_sysdev.sl_state == SYSLOG_INITIALIZING) 427beacf11bSopenharmony_ci { 428beacf11bSopenharmony_ci errcode = EAGAIN; /* Can't access the SYSLOG now... maybe next time? */ 429beacf11bSopenharmony_ci goto errout_with_errcode; 430beacf11bSopenharmony_ci } 431beacf11bSopenharmony_ci 432beacf11bSopenharmony_ci /* Case (6) */ 433beacf11bSopenharmony_ci 434beacf11bSopenharmony_ci if (g_sysdev.sl_state == SYSLOG_FAILURE) 435beacf11bSopenharmony_ci { 436beacf11bSopenharmony_ci errcode = ENXIO; /* There is no SYSLOG device */ 437beacf11bSopenharmony_ci goto errout_with_errcode; 438beacf11bSopenharmony_ci } 439beacf11bSopenharmony_ci 440beacf11bSopenharmony_ci /* syslog_initialize() is called as soon as enough of the operating 441beacf11bSopenharmony_ci * system is in place to support the open operation... but it is 442beacf11bSopenharmony_ci * possible that the SYSLOG device is not yet registered at that time. 443beacf11bSopenharmony_ci * In this case, we know that the system is sufficiently initialized 444beacf11bSopenharmony_ci * to support an attempt to re-open the SYSLOG device. 445beacf11bSopenharmony_ci * 446beacf11bSopenharmony_ci * NOTE that the scheduler is locked. That is because we do not have 447beacf11bSopenharmony_ci * fully initialized semaphore capability until the SYSLOG device is 448beacf11bSopenharmony_ci * successfully initialized 449beacf11bSopenharmony_ci */ 450beacf11bSopenharmony_ci 451beacf11bSopenharmony_ci LOS_TaskLock(); 452beacf11bSopenharmony_ci if (g_sysdev.sl_state == SYSLOG_REOPEN) 453beacf11bSopenharmony_ci { 454beacf11bSopenharmony_ci /* Try again to initialize the device. We may do this repeatedly 455beacf11bSopenharmony_ci * because the log device might be something that was not ready 456beacf11bSopenharmony_ci * the first time that syslog_initializee() was called (such as a 457beacf11bSopenharmony_ci * USB serial device that has not yet been connected or a file in 458beacf11bSopenharmony_ci * an NFS mounted file system that has not yet been mounted). 459beacf11bSopenharmony_ci */ 460beacf11bSopenharmony_ci 461beacf11bSopenharmony_ci ret = syslog_initialize(); 462beacf11bSopenharmony_ci if (ret < 0) 463beacf11bSopenharmony_ci { 464beacf11bSopenharmony_ci LOS_TaskUnlock(); 465beacf11bSopenharmony_ci errcode = -ret; 466beacf11bSopenharmony_ci goto errout_with_errcode; 467beacf11bSopenharmony_ci } 468beacf11bSopenharmony_ci } 469beacf11bSopenharmony_ci 470beacf11bSopenharmony_ci LOS_TaskUnlock(); 471beacf11bSopenharmony_ci DEBUGASSERT(g_sysdev.sl_state == SYSLOG_OPENED); 472beacf11bSopenharmony_ci } 473beacf11bSopenharmony_ci 474beacf11bSopenharmony_ci /* Ignore carriage returns */ 475beacf11bSopenharmony_ci 476beacf11bSopenharmony_ci if (ch == '\r') 477beacf11bSopenharmony_ci { 478beacf11bSopenharmony_ci return ch; 479beacf11bSopenharmony_ci } 480beacf11bSopenharmony_ci 481beacf11bSopenharmony_ci /* The syslog device is ready for writing and we have something of 482beacf11bSopenharmony_ci * value to write. 483beacf11bSopenharmony_ci */ 484beacf11bSopenharmony_ci 485beacf11bSopenharmony_ci ret = syslog_takesem(); 486beacf11bSopenharmony_ci if (ret < 0) 487beacf11bSopenharmony_ci { 488beacf11bSopenharmony_ci /* We probably already hold the semaphore and were probably 489beacf11bSopenharmony_ci * re-entered by the logic kicked off by syslog_write(). 490beacf11bSopenharmony_ci * We might also have been interrupted by a signal. Either 491beacf11bSopenharmony_ci * way, we are outta here. 492beacf11bSopenharmony_ci */ 493beacf11bSopenharmony_ci 494beacf11bSopenharmony_ci errcode = -ret; 495beacf11bSopenharmony_ci goto errout_with_errcode; 496beacf11bSopenharmony_ci } 497beacf11bSopenharmony_ci 498beacf11bSopenharmony_ci /* Pre-pend a newline with a carriage return. */ 499beacf11bSopenharmony_ci 500beacf11bSopenharmony_ci if (ch == '\n') 501beacf11bSopenharmony_ci { 502beacf11bSopenharmony_ci /* Write the CR-LF sequence */ 503beacf11bSopenharmony_ci 504beacf11bSopenharmony_ci nbytes = syslog_write(g_syscrlf, 2); 505beacf11bSopenharmony_ci 506beacf11bSopenharmony_ci /* Synchronize the file when each CR-LF is encountered (i.e., 507beacf11bSopenharmony_ci * implements line buffering always). 508beacf11bSopenharmony_ci */ 509beacf11bSopenharmony_ci 510beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_MOUNTPOINT 511beacf11bSopenharmony_ci if (nbytes > 0) 512beacf11bSopenharmony_ci { 513beacf11bSopenharmony_ci syslog_flush(); 514beacf11bSopenharmony_ci } 515beacf11bSopenharmony_ci#endif 516beacf11bSopenharmony_ci } 517beacf11bSopenharmony_ci else 518beacf11bSopenharmony_ci { 519beacf11bSopenharmony_ci /* Write the non-newline character (and don't flush) */ 520beacf11bSopenharmony_ci 521beacf11bSopenharmony_ci uch = (uint8_t)ch; 522beacf11bSopenharmony_ci nbytes = syslog_write(&uch, 1); 523beacf11bSopenharmony_ci } 524beacf11bSopenharmony_ci 525beacf11bSopenharmony_ci syslog_givesem(); 526beacf11bSopenharmony_ci 527beacf11bSopenharmony_ci /* Check if the write was successful. If not, nbytes will be 528beacf11bSopenharmony_ci * a negated errno value. 529beacf11bSopenharmony_ci */ 530beacf11bSopenharmony_ci 531beacf11bSopenharmony_ci if (nbytes < 0) 532beacf11bSopenharmony_ci { 533beacf11bSopenharmony_ci errcode = -ret; 534beacf11bSopenharmony_ci goto errout_with_errcode; 535beacf11bSopenharmony_ci } 536beacf11bSopenharmony_ci 537beacf11bSopenharmony_ci return ch; 538beacf11bSopenharmony_ci 539beacf11bSopenharmony_cierrout_with_errcode: 540beacf11bSopenharmony_ci if (errcode != 0) 541beacf11bSopenharmony_ci { 542beacf11bSopenharmony_ci set_errno(errcode); 543beacf11bSopenharmony_ci } 544beacf11bSopenharmony_ci return EOF; 545beacf11bSopenharmony_ci} 546beacf11bSopenharmony_ci 547beacf11bSopenharmony_ci#endif /* CONFIG_SYSLOG && CONFIG_SYSLOG_CHAR */ 548