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