(root)/
glibc-2.38/
misc/
syslog.c
       1  /*
       2   * Copyright (c) 1983, 1988, 1993
       3   *	The Regents of the University of California.  All rights reserved.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted provided that the following conditions
       7   * are met:
       8   * 1. Redistributions of source code must retain the above copyright
       9   *    notice, this list of conditions and the following disclaimer.
      10   * 2. Redistributions in binary form must reproduce the above copyright
      11   *    notice, this list of conditions and the following disclaimer in the
      12   *    documentation and/or other materials provided with the distribution.
      13   * 4. Neither the name of the University nor the names of its contributors
      14   *    may be used to endorse or promote products derived from this software
      15   *    without specific prior written permission.
      16   *
      17   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      18   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      20   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      21   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      22   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      23   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      24   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      25   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      26   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      27   * SUCH DAMAGE.
      28   */
      29  
      30  #if defined(LIBC_SCCS) && !defined(lint)
      31  static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
      32  #endif /* LIBC_SCCS and not lint */
      33  
      34  #include <libio/libioP.h>
      35  #include <paths.h>
      36  #include <stdarg.h>
      37  #include <stdlib.h>
      38  #include <stdio.h>
      39  #include <stdio_ext.h>
      40  #include <sys/socket.h>
      41  #include <sys/uio.h>
      42  #include <sys/un.h>
      43  #include <syslog.h>
      44  
      45  static int LogType = SOCK_DGRAM;	/* type of socket connection */
      46  static int LogFile = -1;		/* fd for log */
      47  static bool connected;			/* have done connect */
      48  static int LogStat;			/* status bits, set by openlog() */
      49  static const char *LogTag;		/* string to tag the entry with */
      50  static int LogFacility = LOG_USER;	/* default facility code */
      51  static int LogMask = 0xff;		/* mask of priorities to be logged */
      52  extern char *__progname;		/* Program name, from crt0. */
      53  
      54  /* Define the lock.  */
      55  __libc_lock_define_initialized (static, syslog_lock)
      56  static void openlog_internal (const char *, int, int);
      57  static void closelog_internal (void);
      58  
      59  struct cleanup_arg
      60  {
      61    void *buf;
      62    struct sigaction *oldaction;
      63  };
      64  
      65  static void
      66  cancel_handler (void *ptr)
      67  {
      68    /* Restore the old signal handler.  */
      69    struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
      70  
      71    if (clarg != NULL)
      72      /* Free the memstream buffer,  */
      73      free (clarg->buf);
      74  
      75    /* Free the lock.  */
      76    __libc_lock_unlock (syslog_lock);
      77  }
      78  
      79  
      80  /*
      81   * syslog, vsyslog --
      82   *	print message on log file; output is intended for syslogd(8).
      83   */
      84  void
      85  __syslog (int pri, const char *fmt, ...)
      86  {
      87    va_list ap;
      88  
      89    va_start (ap, fmt);
      90    __vsyslog_internal (pri, fmt, ap, 0);
      91    va_end (ap);
      92  }
      93  ldbl_hidden_def (__syslog, syslog)
      94  ldbl_strong_alias (__syslog, syslog)
      95  
      96  void
      97  __vsyslog (int pri, const char *fmt, va_list ap)
      98  {
      99    __vsyslog_internal (pri, fmt, ap, 0);
     100  }
     101  ldbl_weak_alias (__vsyslog, vsyslog)
     102  
     103  void
     104  ___syslog_chk (int pri, int flag, const char *fmt, ...)
     105  {
     106    va_list ap;
     107  
     108    va_start (ap, fmt);
     109    __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
     110    va_end (ap);
     111  }
     112  ldbl_hidden_def (___syslog_chk, __syslog_chk)
     113  ldbl_strong_alias (___syslog_chk, __syslog_chk)
     114  
     115  void
     116  __vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
     117  {
     118    __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
     119  }
     120  
     121  void
     122  __vsyslog_internal (int pri, const char *fmt, va_list ap,
     123  		    unsigned int mode_flags)
     124  {
     125    /* Try to use a static buffer as an optimization.  */
     126    char bufs[1024];
     127    char *buf = NULL;
     128    size_t bufsize = 0;
     129    int msgoff;
     130    int saved_errno = errno;
     131  
     132  #define	INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
     133    /* Check for invalid bits. */
     134    if (pri & ~(LOG_PRIMASK | LOG_FACMASK))
     135      {
     136        syslog (INTERNALLOG, "syslog: unknown facility/priority: %x", pri);
     137        pri &= LOG_PRIMASK | LOG_FACMASK;
     138      }
     139  
     140    /* Prepare for multiple users.  We have to take care: most syscalls we are
     141       using are cancellation points.  */
     142    struct cleanup_arg clarg = { NULL, NULL };
     143    __libc_cleanup_push (cancel_handler, &clarg);
     144    __libc_lock_lock (syslog_lock);
     145  
     146    /* Check priority against setlogmask values. */
     147    if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
     148      goto out;
     149  
     150    /* Set default facility if none specified. */
     151    if ((pri & LOG_FACMASK) == 0)
     152      pri |= LogFacility;
     153  
     154    pid_t pid = LogStat & LOG_PID ? __getpid () : 0;
     155  
     156    /* "%b %e %H:%M:%S "  */
     157    char timestamp[sizeof "MMM DD hh:mm:ss "];
     158    __time64_t now = time64_now ();
     159    struct tm now_tm;
     160    struct tm *now_tmp = __localtime64_r (&now, &now_tm);
     161    bool has_ts = now_tmp != NULL;
     162  
     163    /* In the unlikely case of localtime_r failure (tm_year out of int range)
     164       skip the hostname so the message is handled as valid PRI but without
     165       TIMESTAMP or invalid TIMESTAMP (which should force the relay to add the
     166       timestamp itself).  */
     167    if (has_ts)
     168      __strftime_l (timestamp, sizeof timestamp, "%h %e %T ", now_tmp,
     169  		  _nl_C_locobj_ptr);
     170  
     171  #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
     172    "<%d>%s%n%s%s%.0d%s: ",                                \
     173    __pri, __timestamp, __msgoff,                          \
     174    LogTag == NULL ? __progname : LogTag,                  \
     175    "[" + (pid == 0), pid, "]" + (pid == 0)
     176  
     177  #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff)        \
     178    "<%d>: %n", __pri, __msgoff
     179  
     180    int l;
     181    if (has_ts)
     182      l = __snprintf (bufs, sizeof bufs,
     183  		    SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
     184    else
     185      l = __snprintf (bufs, sizeof bufs,
     186  		    SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
     187    if (0 <= l && l < sizeof bufs)
     188      {
     189        va_list apc;
     190        va_copy (apc, ap);
     191  
     192        /* Restore errno for %m format.  */
     193        __set_errno (saved_errno);
     194  
     195        int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
     196                                       mode_flags);
     197        if (0 <= vl && vl < sizeof bufs - l)
     198          buf = bufs;
     199        bufsize = l + vl;
     200  
     201        va_end (apc);
     202      }
     203  
     204    if (buf == NULL)
     205      {
     206        buf = malloc ((bufsize + 1) * sizeof (char));
     207        if (buf != NULL)
     208  	{
     209  	  /* Tell the cancellation handler to free this buffer.  */
     210  	  clarg.buf = buf;
     211  
     212  	  if (has_ts)
     213  	    __snprintf (buf, l + 1,
     214  			SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
     215  	  else
     216  	    __snprintf (buf, l + 1,
     217  			SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
     218  
     219  	  va_list apc;
     220  	  va_copy (apc, ap);
     221  	  __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
     222  				mode_flags);
     223  	  va_end (apc);
     224  	}
     225        else
     226          {
     227  	  /* Nothing much to do but emit an error message.  */
     228            bufsize = __snprintf (bufs, sizeof bufs,
     229                                  "out of memory[%d]", __getpid ());
     230            buf = bufs;
     231          }
     232      }
     233  
     234    /* Output to stderr if requested. */
     235    if (LogStat & LOG_PERROR)
     236      __dprintf (STDERR_FILENO, "%s%s", buf + msgoff,
     237  	       "\n" + (buf[bufsize - 1] == '\n'));
     238  
     239    /* Get connected, output the message to the local logger.  */
     240    if (!connected)
     241      openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
     242  
     243    /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record
     244       terminator.  */
     245    if (LogType == SOCK_STREAM)
     246      ++bufsize;
     247  
     248    if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
     249      {
     250        if (connected)
     251  	{
     252  	  /* Try to reopen the syslog connection.  Maybe it went down.  */
     253  	  closelog_internal ();
     254  	  openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
     255  	}
     256  
     257        if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
     258  	{
     259  	  closelog_internal ();	/* attempt re-open next time */
     260  	  /*
     261  	   * Output the message to the console; don't worry
     262  	   * about blocking, if console blocks everything will.
     263  	   * Make sure the error reported is the one from the
     264  	   * syslogd failure.
     265  	   */
     266  	  int fd;
     267  	  if (LogStat & LOG_CONS &&
     268  	      (fd = __open (_PATH_CONSOLE, O_WRONLY | O_NOCTTY
     269  			    | O_CLOEXEC, 0)) >= 0)
     270  	    {
     271  	      __dprintf (fd, "%s\r\n", buf + msgoff);
     272  	      __close (fd);
     273  	    }
     274  	}
     275      }
     276  
     277  out:
     278    /* End of critical section.  */
     279    __libc_cleanup_pop (0);
     280    __libc_lock_unlock (syslog_lock);
     281  
     282    if (buf != bufs)
     283      free (buf);
     284  }
     285  
     286  /* AF_UNIX address of local logger  */
     287  static const struct sockaddr_un SyslogAddr =
     288    {
     289      .sun_family = AF_UNIX,
     290      .sun_path = _PATH_LOG
     291    };
     292  
     293  static void
     294  openlog_internal (const char *ident, int logstat, int logfac)
     295  {
     296    if (ident != NULL)
     297      LogTag = ident;
     298    LogStat = logstat;
     299    if ((logfac & ~LOG_FACMASK) == 0)
     300      LogFacility = logfac;
     301  
     302    int retry = 0;
     303    while (retry < 2)
     304      {
     305        if (LogFile == -1)
     306  	{
     307  	  if (LogStat & LOG_NDELAY)
     308  	    {
     309  	      LogFile = __socket (AF_UNIX, LogType | SOCK_CLOEXEC, 0);
     310  	      if (LogFile == -1)
     311  		return;
     312  	    }
     313  	}
     314        if (LogFile != -1 && !connected)
     315  	{
     316  	  int old_errno = errno;
     317  	  if (__connect (LogFile, &SyslogAddr, sizeof (SyslogAddr)) == -1)
     318  	    {
     319  	      int saved_errno = errno;
     320  	      int fd = LogFile;
     321  	      LogFile = -1;
     322  	      __close (fd);
     323  	      __set_errno (old_errno);
     324  	      if (saved_errno == EPROTOTYPE)
     325  		{
     326  		  /* retry with the other type: */
     327  		  LogType = LogType == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
     328  		  ++retry;
     329  		  continue;
     330  		}
     331  	    }
     332  	  else
     333  	    connected = true;
     334  	}
     335        break;
     336      }
     337  }
     338  
     339  void
     340  openlog (const char *ident, int logstat, int logfac)
     341  {
     342    /* Protect against multiple users and cancellation.  */
     343    __libc_cleanup_push (cancel_handler, NULL);
     344    __libc_lock_lock (syslog_lock);
     345  
     346    openlog_internal (ident, logstat, logfac);
     347  
     348    __libc_cleanup_pop (1);
     349  }
     350  
     351  static void
     352  closelog_internal (void)
     353  {
     354    if (!connected)
     355      return;
     356  
     357    __close (LogFile);
     358    LogFile = -1;
     359    connected = false;
     360  }
     361  
     362  void
     363  closelog (void)
     364  {
     365    /* Protect against multiple users and cancellation.  */
     366    __libc_cleanup_push (cancel_handler, NULL);
     367    __libc_lock_lock (syslog_lock);
     368  
     369    closelog_internal ();
     370    LogTag = NULL;
     371    LogType = SOCK_DGRAM; /* this is the default */
     372  
     373    /* Free the lock.  */
     374    __libc_cleanup_pop (1);
     375  }
     376  
     377  /* setlogmask -- set the log mask level */
     378  int
     379  setlogmask (int pmask)
     380  {
     381    int omask;
     382  
     383    /* Protect against multiple users.  */
     384    __libc_lock_lock (syslog_lock);
     385  
     386    omask = LogMask;
     387    if (pmask != 0)
     388      LogMask = pmask;
     389  
     390    __libc_lock_unlock (syslog_lock);
     391  
     392    return (omask);
     393  }