xref: /third_party/NuttX/fs/driver/fs_devsyslog.c (revision beacf11b)
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