Remove Linux kernel version ambiguity in comment added by previous commit.
[platform/upstream/glibc.git] / 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 <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/syslog.h>
37 #include <sys/uio.h>
38 #include <sys/un.h>
39 #include <netdb.h>
40
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <paths.h>
44 #include <stdio.h>
45 #include <stdio_ext.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <bits/libc-lock.h>
51 #include <signal.h>
52 #include <locale.h>
53
54 #include <stdarg.h>
55
56 #include <libio/iolibio.h>
57 #include <math_ldbl_opt.h>
58
59 #include <kernel-features.h>
60
61 #define ftell(s) _IO_ftell (s)
62
63 static int      LogType = SOCK_DGRAM;   /* type of socket connection */
64 static int      LogFile = -1;           /* fd for log */
65 static int      connected;              /* have done connect */
66 static int      LogStat;                /* status bits, set by openlog() */
67 static const char *LogTag;              /* string to tag the entry with */
68 static int      LogFacility = LOG_USER; /* default facility code */
69 static int      LogMask = 0xff;         /* mask of priorities to be logged */
70 extern char     *__progname;            /* Program name, from crt0. */
71
72 /* Define the lock.  */
73 __libc_lock_define_initialized (static, syslog_lock)
74
75 static void openlog_internal(const char *, int, int) internal_function;
76 static void closelog_internal(void);
77 #ifndef NO_SIGPIPE
78 static void sigpipe_handler (int);
79 #endif
80
81 #ifndef send_flags
82 # define send_flags 0
83 #endif
84
85 struct cleanup_arg
86 {
87   void *buf;
88   struct sigaction *oldaction;
89 };
90
91 static void
92 cancel_handler (void *ptr)
93 {
94 #ifndef NO_SIGPIPE
95   /* Restore the old signal handler.  */
96   struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
97
98   if (clarg != NULL && clarg->oldaction != NULL)
99     __sigaction (SIGPIPE, clarg->oldaction, NULL);
100 #endif
101
102   /* Free the lock.  */
103   __libc_lock_unlock (syslog_lock);
104 }
105
106
107 /*
108  * syslog, vsyslog --
109  *      print message on log file; output is intended for syslogd(8).
110  */
111 void
112 __syslog(int pri, const char *fmt, ...)
113 {
114         va_list ap;
115
116         va_start(ap, fmt);
117         __vsyslog_chk(pri, -1, fmt, ap);
118         va_end(ap);
119 }
120 ldbl_hidden_def (__syslog, syslog)
121 ldbl_strong_alias (__syslog, syslog)
122
123 void
124 __syslog_chk(int pri, int flag, const char *fmt, ...)
125 {
126         va_list ap;
127
128         va_start(ap, fmt);
129         __vsyslog_chk(pri, flag, fmt, ap);
130         va_end(ap);
131 }
132
133 void
134 __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
135 {
136         struct tm now_tm;
137         time_t now;
138         int fd;
139         FILE *f;
140         char *buf = 0;
141         size_t bufsize = 0;
142         size_t msgoff;
143 #ifndef NO_SIGPIPE
144         struct sigaction action, oldaction;
145         int sigpipe;
146 #endif
147         int saved_errno = errno;
148         char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"];
149
150 #define INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
151         /* Check for invalid bits. */
152         if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
153                 syslog(INTERNALLOG,
154                     "syslog: unknown facility/priority: %x", pri);
155                 pri &= LOG_PRIMASK|LOG_FACMASK;
156         }
157
158         /* Check priority against setlogmask values. */
159         if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
160                 return;
161
162         /* Set default facility if none specified. */
163         if ((pri & LOG_FACMASK) == 0)
164                 pri |= LogFacility;
165
166         /* Build the message in a memory-buffer stream.  */
167         f = open_memstream (&buf, &bufsize);
168         if (f == NULL)
169           {
170             /* We cannot get a stream.  There is not much we can do but
171                emitting an error messages.  */
172             char numbuf[3 * sizeof (pid_t)];
173             char *nump;
174             char *endp = __stpcpy (failbuf, "out of memory [");
175             pid_t pid = __getpid ();
176
177             nump = numbuf + sizeof (numbuf);
178             /* The PID can never be zero.  */
179             do
180               *--nump = '0' + pid % 10;
181             while ((pid /= 10) != 0);
182
183             endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump);
184             *endp++ = ']';
185             *endp = '\0';
186             buf = failbuf;
187             bufsize = endp - failbuf;
188             msgoff = 0;
189           }
190         else
191           {
192             __fsetlocking (f, FSETLOCKING_BYCALLER);
193             fprintf (f, "<%d>", pri);
194             (void) time (&now);
195             f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr,
196                                               f->_IO_write_end
197                                               - f->_IO_write_ptr,
198                                               "%h %e %T ",
199                                               __localtime_r (&now, &now_tm),
200                                               _nl_C_locobj_ptr);
201             msgoff = ftell (f);
202             if (LogTag == NULL)
203               LogTag = __progname;
204             if (LogTag != NULL)
205               fputs_unlocked (LogTag, f);
206             if (LogStat & LOG_PID)
207               fprintf (f, "[%d]", (int) __getpid ());
208             if (LogTag != NULL)
209               {
210                 putc_unlocked (':', f);
211                 putc_unlocked (' ', f);
212               }
213
214             /* Restore errno for %m format.  */
215             __set_errno (saved_errno);
216
217             /* We have the header.  Print the user's format into the
218                buffer.  */
219             if (flag == -1)
220               vfprintf (f, fmt, ap);
221             else
222               __vfprintf_chk (f, flag, fmt, ap);
223
224             /* Close the memory stream; this will finalize the data
225                into a malloc'd buffer in BUF.  */
226             fclose (f);
227           }
228
229         /* Output to stderr if requested. */
230         if (LogStat & LOG_PERROR) {
231                 struct iovec iov[2];
232                 struct iovec *v = iov;
233
234                 v->iov_base = buf + msgoff;
235                 v->iov_len = bufsize - msgoff;
236                 /* Append a newline if necessary.  */
237                 if (buf[bufsize - 1] != '\n')
238                   {
239                     ++v;
240                     v->iov_base = (char *) "\n";
241                     v->iov_len = 1;
242                   }
243
244                 __libc_cleanup_push (free, buf == failbuf ? NULL : buf);
245
246                 /* writev is a cancellation point.  */
247                 (void)__writev(STDERR_FILENO, iov, v - iov + 1);
248
249                 __libc_cleanup_pop (0);
250         }
251
252         /* Prepare for multiple users.  We have to take care: open and
253            write are cancellation points.  */
254         struct cleanup_arg clarg;
255         clarg.buf = buf;
256         clarg.oldaction = NULL;
257         __libc_cleanup_push (cancel_handler, &clarg);
258         __libc_lock_lock (syslog_lock);
259
260 #ifndef NO_SIGPIPE
261         /* Prepare for a broken connection.  */
262         memset (&action, 0, sizeof (action));
263         action.sa_handler = sigpipe_handler;
264         sigemptyset (&action.sa_mask);
265         sigpipe = __sigaction (SIGPIPE, &action, &oldaction);
266         if (sigpipe == 0)
267           clarg.oldaction = &oldaction;
268 #endif
269
270         /* Get connected, output the message to the local logger. */
271         if (!connected)
272                 openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
273
274         /* If we have a SOCK_STREAM connection, also send ASCII NUL as
275            a record terminator.  */
276         if (LogType == SOCK_STREAM)
277           ++bufsize;
278
279         if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
280           {
281             if (connected)
282               {
283                 /* Try to reopen the syslog connection.  Maybe it went
284                    down.  */
285                 closelog_internal ();
286                 openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
287               }
288
289             if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
290               {
291                 closelog_internal ();   /* attempt re-open next time */
292                 /*
293                  * Output the message to the console; don't worry
294                  * about blocking, if console blocks everything will.
295                  * Make sure the error reported is the one from the
296                  * syslogd failure.
297                  */
298                 if (LogStat & LOG_CONS &&
299                     (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0)
300                   {
301                     dprintf (fd, "%s\r\n", buf + msgoff);
302                     (void)__close(fd);
303                   }
304               }
305           }
306
307 #ifndef NO_SIGPIPE
308         if (sigpipe == 0)
309                 __sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL);
310 #endif
311
312         /* End of critical section.  */
313         __libc_cleanup_pop (0);
314         __libc_lock_unlock (syslog_lock);
315
316         if (buf != failbuf)
317                 free (buf);
318 }
319 libc_hidden_def (__vsyslog_chk)
320
321 void
322 __vsyslog(int pri, const char *fmt, va_list ap)
323 {
324   __vsyslog_chk (pri, -1, fmt, ap);
325 }
326 ldbl_hidden_def (__vsyslog, vsyslog)
327 ldbl_strong_alias (__vsyslog, vsyslog)
328
329 static struct sockaddr_un SyslogAddr;   /* AF_UNIX address of local logger */
330
331
332 static void
333 internal_function
334 openlog_internal(const char *ident, int logstat, int logfac)
335 {
336         if (ident != NULL)
337                 LogTag = ident;
338         LogStat = logstat;
339         if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
340                 LogFacility = logfac;
341
342         int retry = 0;
343         while (retry < 2) {
344                 if (LogFile == -1) {
345                         SyslogAddr.sun_family = AF_UNIX;
346                         (void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
347                                       sizeof(SyslogAddr.sun_path));
348                         if (LogStat & LOG_NDELAY) {
349 #ifdef SOCK_CLOEXEC
350 # ifndef __ASSUME_SOCK_CLOEXEC
351                                 if (__have_sock_cloexec >= 0) {
352 # endif
353                                         LogFile = __socket(AF_UNIX,
354                                                            LogType
355                                                            | SOCK_CLOEXEC, 0);
356 # ifndef __ASSUME_SOCK_CLOEXEC
357                                         if (__have_sock_cloexec == 0)
358                                                 __have_sock_cloexec
359                                                   = ((LogFile != -1
360                                                       || errno != EINVAL)
361                                                      ? 1 : -1);
362                                 }
363 # endif
364 #endif
365 #ifndef __ASSUME_SOCK_CLOEXEC
366 # ifdef SOCK_CLOEXEC
367                                 if (__have_sock_cloexec < 0)
368 # endif
369                                   LogFile = __socket(AF_UNIX, LogType, 0);
370 #endif
371                                 if (LogFile == -1)
372                                         return;
373 #ifndef __ASSUME_SOCK_CLOEXEC
374 # ifdef SOCK_CLOEXEC
375                                 if (__have_sock_cloexec < 0)
376 # endif
377                                         __fcntl(LogFile, F_SETFD, FD_CLOEXEC);
378 #endif
379                         }
380                 }
381                 if (LogFile != -1 && !connected)
382                 {
383                         int old_errno = errno;
384                         if (__connect(LogFile, &SyslogAddr, sizeof(SyslogAddr))
385                             == -1)
386                         {
387                                 int saved_errno = errno;
388                                 int fd = LogFile;
389                                 LogFile = -1;
390                                 (void)__close(fd);
391                                 __set_errno (old_errno);
392                                 if (saved_errno == EPROTOTYPE)
393                                 {
394                                         /* retry with the other type: */
395                                         LogType = (LogType == SOCK_DGRAM
396                                                    ? SOCK_STREAM : SOCK_DGRAM);
397                                         ++retry;
398                                         continue;
399                                 }
400                         } else
401                                 connected = 1;
402                 }
403                 break;
404         }
405 }
406
407 void
408 openlog (const char *ident, int logstat, int logfac)
409 {
410   /* Protect against multiple users and cancellation.  */
411   __libc_cleanup_push (cancel_handler, NULL);
412   __libc_lock_lock (syslog_lock);
413
414   openlog_internal (ident, logstat, logfac);
415
416   __libc_cleanup_pop (1);
417 }
418
419 #ifndef NO_SIGPIPE
420 static void
421 sigpipe_handler (int signo)
422 {
423   closelog_internal ();
424 }
425 #endif
426
427 static void
428 closelog_internal (void)
429 {
430   if (!connected)
431     return;
432
433   __close (LogFile);
434   LogFile = -1;
435   connected = 0;
436 }
437
438 void
439 closelog (void)
440 {
441   /* Protect against multiple users and cancellation.  */
442   __libc_cleanup_push (cancel_handler, NULL);
443   __libc_lock_lock (syslog_lock);
444
445   closelog_internal ();
446   LogTag = NULL;
447   LogType = SOCK_DGRAM; /* this is the default */
448
449   /* Free the lock.  */
450   __libc_cleanup_pop (1);
451 }
452
453 /* setlogmask -- set the log mask level */
454 int
455 setlogmask(pmask)
456         int pmask;
457 {
458         int omask;
459
460         omask = LogMask;
461         if (pmask != 0)
462                 LogMask = pmask;
463         return (omask);
464 }