Back to index

glibc  2.9
syslog.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1983, 1988, 1993
00003  *     The Regents of the University of California.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 4. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #if defined(LIBC_SCCS) && !defined(lint)
00031 static char sccsid[] = "@(#)syslog.c      8.4 (Berkeley) 3/18/94";
00032 #endif /* LIBC_SCCS and not lint */
00033 
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <sys/syslog.h>
00037 #include <sys/uio.h>
00038 #include <sys/un.h>
00039 #include <netdb.h>
00040 
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <paths.h>
00044 #include <stdio.h>
00045 #include <stdio_ext.h>
00046 #include <string.h>
00047 #include <time.h>
00048 #include <unistd.h>
00049 #include <stdlib.h>
00050 #include <bits/libc-lock.h>
00051 #include <signal.h>
00052 #include <locale.h>
00053 
00054 #if __STDC__
00055 #include <stdarg.h>
00056 #else
00057 #include <varargs.h>
00058 #endif
00059 
00060 #include <libio/iolibio.h>
00061 #include <math_ldbl_opt.h>
00062 
00063 #define ftell(s) INTUSE(_IO_ftell) (s)
00064 
00065 static int    LogType = SOCK_DGRAM;       /* type of socket connection */
00066 static int    LogFile = -1;        /* fd for log */
00067 static int    connected;           /* have done connect */
00068 static int    LogStat;             /* status bits, set by openlog() */
00069 static const char *LogTag;         /* string to tag the entry with */
00070 static int    LogFacility = LOG_USER;     /* default facility code */
00071 static int    LogMask = 0xff;             /* mask of priorities to be logged */
00072 extern char   *__progname;         /* Program name, from crt0. */
00073 
00074 /* Define the lock.  */
00075 __libc_lock_define_initialized (static, syslog_lock)
00076 
00077 static void openlog_internal(const char *, int, int) internal_function;
00078 static void closelog_internal(void);
00079 #ifndef NO_SIGPIPE
00080 static void sigpipe_handler (int);
00081 #endif
00082 
00083 #ifndef send_flags
00084 # define send_flags 0
00085 #endif
00086 
00087 struct cleanup_arg
00088 {
00089   void *buf;
00090   struct sigaction *oldaction;
00091 };
00092 
00093 static void
00094 cancel_handler (void *ptr)
00095 {
00096 #ifndef NO_SIGPIPE
00097   /* Restore the old signal handler.  */
00098   struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
00099 
00100   if (clarg != NULL && clarg->oldaction != NULL)
00101     __sigaction (SIGPIPE, clarg->oldaction, NULL);
00102 #endif
00103 
00104   /* Free the lock.  */
00105   __libc_lock_unlock (syslog_lock);
00106 }
00107 
00108 
00109 /*
00110  * syslog, vsyslog --
00111  *     print message on log file; output is intended for syslogd(8).
00112  */
00113 void
00114 __syslog(int pri, const char *fmt, ...)
00115 {
00116        va_list ap;
00117 
00118        va_start(ap, fmt);
00119        __vsyslog_chk(pri, -1, fmt, ap);
00120        va_end(ap);
00121 }
00122 ldbl_hidden_def (__syslog, syslog)
00123 ldbl_strong_alias (__syslog, syslog)
00124 
00125 void
00126 __syslog_chk(int pri, int flag, const char *fmt, ...)
00127 {
00128        va_list ap;
00129 
00130        va_start(ap, fmt);
00131        __vsyslog_chk(pri, flag, fmt, ap);
00132        va_end(ap);
00133 }
00134 
00135 void
00136 __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
00137 {
00138        struct tm now_tm;
00139        time_t now;
00140        int fd;
00141        FILE *f;
00142        char *buf = 0;
00143        size_t bufsize = 0;
00144        size_t prioff, msgoff;
00145 #ifndef NO_SIGPIPE
00146        struct sigaction action, oldaction;
00147        int sigpipe;
00148 #endif
00149        int saved_errno = errno;
00150        char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"];
00151 
00152 #define       INTERNALLOG   LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
00153        /* Check for invalid bits. */
00154        if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
00155               syslog(INTERNALLOG,
00156                   "syslog: unknown facility/priority: %x", pri);
00157               pri &= LOG_PRIMASK|LOG_FACMASK;
00158        }
00159 
00160        /* Check priority against setlogmask values. */
00161        if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
00162               return;
00163 
00164        /* Set default facility if none specified. */
00165        if ((pri & LOG_FACMASK) == 0)
00166               pri |= LogFacility;
00167 
00168        /* Build the message in a memory-buffer stream.  */
00169        f = open_memstream (&buf, &bufsize);
00170        if (f == NULL)
00171          {
00172            /* We cannot get a stream.  There is not much we can do but
00173               emitting an error messages.  */
00174            char numbuf[3 * sizeof (pid_t)];
00175            char *nump;
00176            char *endp = __stpcpy (failbuf, "out of memory [");
00177            pid_t pid = __getpid ();
00178 
00179            nump = numbuf + sizeof (numbuf);
00180            /* The PID can never be zero.  */
00181            do
00182              *--nump = '0' + pid % 10;
00183            while ((pid /= 10) != 0);
00184 
00185            endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump);
00186            *endp++ = ']';
00187            *endp = '\0';
00188            buf = failbuf;
00189            bufsize = endp - failbuf;
00190            msgoff = 0;
00191          }
00192        else
00193          {
00194            __fsetlocking (f, FSETLOCKING_BYCALLER);
00195            prioff = fprintf (f, "<%d>", pri);
00196            (void) time (&now);
00197            f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr,
00198                                          f->_IO_write_end
00199                                          - f->_IO_write_ptr,
00200                                          "%h %e %T ",
00201                                          __localtime_r (&now, &now_tm),
00202                                          _nl_C_locobj_ptr);
00203            msgoff = ftell (f);
00204            if (LogTag == NULL)
00205              LogTag = __progname;
00206            if (LogTag != NULL)
00207              fputs_unlocked (LogTag, f);
00208            if (LogStat & LOG_PID)
00209              fprintf (f, "[%d]", (int) __getpid ());
00210            if (LogTag != NULL)
00211              {
00212               putc_unlocked (':', f);
00213               putc_unlocked (' ', f);
00214              }
00215 
00216            /* Restore errno for %m format.  */
00217            __set_errno (saved_errno);
00218 
00219            /* We have the header.  Print the user's format into the
00220                buffer.  */
00221            if (flag == -1)
00222              vfprintf (f, fmt, ap);
00223            else
00224              __vfprintf_chk (f, flag, fmt, ap);
00225 
00226            /* Close the memory stream; this will finalize the data
00227               into a malloc'd buffer in BUF.  */
00228            fclose (f);
00229          }
00230 
00231        /* Output to stderr if requested. */
00232        if (LogStat & LOG_PERROR) {
00233               struct iovec iov[2];
00234               register struct iovec *v = iov;
00235 
00236               v->iov_base = buf + msgoff;
00237               v->iov_len = bufsize - msgoff;
00238               /* Append a newline if necessary.  */
00239               if (buf[bufsize - 1] != '\n')
00240                 {
00241                   ++v;
00242                   v->iov_base = (char *) "\n";
00243                   v->iov_len = 1;
00244                 }
00245 
00246               __libc_cleanup_push (free, buf == failbuf ? NULL : buf);
00247 
00248               /* writev is a cancellation point.  */
00249               (void)__writev(STDERR_FILENO, iov, v - iov + 1);
00250 
00251               __libc_cleanup_pop (0);
00252        }
00253 
00254        /* Prepare for multiple users.  We have to take care: open and
00255           write are cancellation points.  */
00256        struct cleanup_arg clarg;
00257        clarg.buf = buf;
00258        clarg.oldaction = NULL;
00259        __libc_cleanup_push (cancel_handler, &clarg);
00260        __libc_lock_lock (syslog_lock);
00261 
00262 #ifndef NO_SIGPIPE
00263        /* Prepare for a broken connection.  */
00264        memset (&action, 0, sizeof (action));
00265        action.sa_handler = sigpipe_handler;
00266        sigemptyset (&action.sa_mask);
00267        sigpipe = __sigaction (SIGPIPE, &action, &oldaction);
00268        if (sigpipe == 0)
00269          clarg.oldaction = &oldaction;
00270 #endif
00271 
00272        /* Get connected, output the message to the local logger. */
00273        if (!connected)
00274               openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
00275 
00276        /* If we have a SOCK_STREAM connection, also send ASCII NUL as
00277           a record terminator.  */
00278        if (LogType == SOCK_STREAM)
00279          ++bufsize;
00280 
00281        if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
00282          {
00283            if (connected)
00284              {
00285               /* Try to reopen the syslog connection.  Maybe it went
00286                  down.  */
00287               closelog_internal ();
00288               openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
00289              }
00290 
00291            if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
00292              {
00293               closelog_internal ();       /* attempt re-open next time */
00294               /*
00295                * Output the message to the console; don't worry
00296                * about blocking, if console blocks everything will.
00297                * Make sure the error reported is the one from the
00298                * syslogd failure.
00299                */
00300               if (LogStat & LOG_CONS &&
00301                   (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0)
00302                 {
00303                   dprintf (fd, "%s\r\n", buf + msgoff);
00304                   (void)__close(fd);
00305                 }
00306              }
00307          }
00308 
00309 #ifndef NO_SIGPIPE
00310        if (sigpipe == 0)
00311               __sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL);
00312 #endif
00313 
00314        /* End of critical section.  */
00315        __libc_cleanup_pop (0);
00316        __libc_lock_unlock (syslog_lock);
00317 
00318        if (buf != failbuf)
00319               free (buf);
00320 }
00321 libc_hidden_def (__vsyslog_chk)
00322 
00323 void
00324 __vsyslog(int pri, const char *fmt, va_list ap)
00325 {
00326   __vsyslog_chk (pri, -1, fmt, ap);
00327 }
00328 ldbl_hidden_def (__vsyslog, vsyslog)
00329 ldbl_strong_alias (__vsyslog, vsyslog)
00330 
00331 static struct sockaddr_un SyslogAddr;     /* AF_UNIX address of local logger */
00332 
00333 
00334 static void
00335 internal_function
00336 openlog_internal(const char *ident, int logstat, int logfac)
00337 {
00338        if (ident != NULL)
00339               LogTag = ident;
00340        LogStat = logstat;
00341        if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
00342               LogFacility = logfac;
00343 
00344        int retry = 0;
00345        while (retry < 2) {
00346               if (LogFile == -1) {
00347                      SyslogAddr.sun_family = AF_UNIX;
00348                      (void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
00349                                   sizeof(SyslogAddr.sun_path));
00350                      if (LogStat & LOG_NDELAY) {
00351 #ifdef SOCK_CLOEXEC
00352 # ifndef __ASSUME_SOCK_CLOEXEC
00353                             if (__have_sock_cloexec >= 0) {
00354 # endif
00355                                    LogFile = __socket(AF_UNIX,
00356                                                     LogType
00357                                                     | SOCK_CLOEXEC, 0);
00358 # ifndef __ASSUME_SOCK_CLOEXEC
00359                                    if (__have_sock_cloexec == 0)
00360                                           __have_sock_cloexec
00361                                             = ((LogFile != -1
00362                                                 || errno != EINVAL)
00363                                                ? 1 : -1);
00364                             }
00365 # endif
00366 #endif
00367 #ifndef __ASSUME_SOCK_CLOEXEC
00368 # ifdef SOCK_CLOEXEC
00369                             if (__have_sock_cloexec < 0)
00370 # endif
00371                               LogFile = __socket(AF_UNIX, LogType, 0);
00372 #endif
00373                             if (LogFile == -1)
00374                                    return;
00375 #ifndef __ASSUME_SOCK_CLOEXEC
00376 # ifdef SOCK_CLOEXEC
00377                             if (__have_sock_cloexec < 0)
00378 # endif
00379                                    __fcntl(LogFile, F_SETFD, FD_CLOEXEC);
00380 #endif
00381                      }
00382               }
00383               if (LogFile != -1 && !connected)
00384               {
00385                      int old_errno = errno;
00386                      if (__connect(LogFile, &SyslogAddr, sizeof(SyslogAddr))
00387                          == -1)
00388                      {
00389                             int saved_errno = errno;
00390                             int fd = LogFile;
00391                             LogFile = -1;
00392                             (void)__close(fd);
00393                             __set_errno (old_errno);
00394                             if (saved_errno == EPROTOTYPE)
00395                             {
00396                                    /* retry with the other type: */
00397                                    LogType = (LogType == SOCK_DGRAM
00398                                              ? SOCK_STREAM : SOCK_DGRAM);
00399                                    ++retry;
00400                                    continue;
00401                             }
00402                      } else
00403                             connected = 1;
00404               }
00405               break;
00406        }
00407 }
00408 
00409 void
00410 openlog (const char *ident, int logstat, int logfac)
00411 {
00412   /* Protect against multiple users and cancellation.  */
00413   __libc_cleanup_push (cancel_handler, NULL);
00414   __libc_lock_lock (syslog_lock);
00415 
00416   openlog_internal (ident, logstat, logfac);
00417 
00418   __libc_cleanup_pop (1);
00419 }
00420 
00421 #ifndef NO_SIGPIPE
00422 static void
00423 sigpipe_handler (int signo)
00424 {
00425   closelog_internal ();
00426 }
00427 #endif
00428 
00429 static void
00430 closelog_internal()
00431 {
00432   if (!connected)
00433     return;
00434 
00435   __close (LogFile);
00436   LogFile = -1;
00437   connected = 0;
00438 }
00439 
00440 void
00441 closelog ()
00442 {
00443   /* Protect against multiple users and cancellation.  */
00444   __libc_cleanup_push (cancel_handler, NULL);
00445   __libc_lock_lock (syslog_lock);
00446 
00447   closelog_internal ();
00448   LogTag = NULL;
00449   LogType = SOCK_DGRAM; /* this is the default */
00450 
00451   /* Free the lock.  */
00452   __libc_cleanup_pop (1);
00453 }
00454 
00455 /* setlogmask -- set the log mask level */
00456 int
00457 setlogmask(pmask)
00458        int pmask;
00459 {
00460        int omask;
00461 
00462        omask = LogMask;
00463        if (pmask != 0)
00464               LogMask = pmask;
00465        return (omask);
00466 }