* locale/xlocale.c (_nl_C_locobj): Mark as const.
[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 <netdb.h>
39
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <paths.h>
43 #include <stdio.h>
44 #include <stdio_ext.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <bits/libc-lock.h>
50 #include <signal.h>
51 #include <locale.h>
52
53 #if __STDC__
54 #include <stdarg.h>
55 #else
56 #include <varargs.h>
57 #endif
58
59 #include <libio/iolibio.h>
60 #define ftell(s) INTUSE(_IO_ftell) (s)
61
62 static int      LogType = SOCK_DGRAM;   /* type of socket connection */
63 static int      LogFile = -1;           /* fd for log */
64 static int      connected;              /* have done connect */
65 static int      LogStat;                /* status bits, set by openlog() */
66 static const char *LogTag;              /* string to tag the entry with */
67 static int      LogFacility = LOG_USER; /* default facility code */
68 static int      LogMask = 0xff;         /* mask of priorities to be logged */
69 extern char     *__progname;            /* Program name, from crt0. */
70
71 /* Define the lock.  */
72 __libc_lock_define_initialized (static, syslog_lock)
73
74 static void openlog_internal(const char *, int, int) internal_function;
75 static void closelog_internal(void);
76 #ifndef NO_SIGPIPE
77 static void sigpipe_handler (int);
78 #endif
79
80 #ifndef send_flags
81 # define send_flags 0
82 #endif
83
84 struct cleanup_arg
85 {
86   void *buf;
87   struct sigaction *oldaction;
88 };
89
90 static void
91 cancel_handler (void *ptr)
92 {
93 #ifndef NO_SIGPIPE
94   /* Restore the old signal handler.  */
95   struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
96
97   if (clarg != NULL && clarg->oldaction != NULL)
98     __sigaction (SIGPIPE, clarg->oldaction, NULL);
99 #endif
100
101   /* Free the lock.  */
102   __libc_lock_unlock (syslog_lock);
103 }
104
105
106 /*
107  * syslog, vsyslog --
108  *      print message on log file; output is intended for syslogd(8).
109  */
110 void
111 syslog(int pri, const char *fmt, ...)
112 {
113         va_list ap;
114
115         va_start(ap, fmt);
116         __vsyslog_chk(pri, -1, fmt, ap);
117         va_end(ap);
118 }
119 libc_hidden_def (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 prioff, 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             prioff = 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(pri, fmt, ap)
321         int pri;
322         register const char *fmt;
323         va_list ap;
324 {
325   __vsyslog_chk (pri, -1, fmt, ap);
326 }
327 libc_hidden_def (vsyslog)
328
329 static struct sockaddr 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.sa_family = AF_UNIX;
346                         (void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
347                                       sizeof(SyslogAddr.sa_data));
348                         if (LogStat & LOG_NDELAY) {
349                                 if ((LogFile = __socket(AF_UNIX, LogType, 0))
350                                     == -1)
351                                         return;
352                                 (void)__fcntl(LogFile, F_SETFD, 1);
353                         }
354                 }
355                 if (LogFile != -1 && !connected)
356                 {
357                         int old_errno = errno;
358                         if (__connect(LogFile, &SyslogAddr, sizeof(SyslogAddr))
359                             == -1)
360                         {
361                                 int saved_errno = errno;
362                                 int fd = LogFile;
363                                 LogFile = -1;
364                                 (void)__close(fd);
365                                 __set_errno (old_errno);
366                                 if (saved_errno == EPROTOTYPE)
367                                 {
368                                         /* retry with the other type: */
369                                         LogType = (LogType == SOCK_DGRAM
370                                                    ? SOCK_STREAM : SOCK_DGRAM);
371                                         ++retry;
372                                         continue;
373                                 }
374                         } else
375                                 connected = 1;
376                 }
377                 break;
378         }
379 }
380
381 void
382 openlog (const char *ident, int logstat, int logfac)
383 {
384   /* Protect against multiple users and cancellation.  */
385   __libc_cleanup_push (cancel_handler, NULL);
386   __libc_lock_lock (syslog_lock);
387
388   openlog_internal (ident, logstat, logfac);
389
390   __libc_cleanup_pop (1);
391 }
392
393 #ifndef NO_SIGPIPE
394 static void
395 sigpipe_handler (int signo)
396 {
397   closelog_internal ();
398 }
399 #endif
400
401 static void
402 closelog_internal()
403 {
404   if (!connected)
405     return;
406
407   __close (LogFile);
408   LogFile = -1;
409   connected = 0;
410 }
411
412 void
413 closelog ()
414 {
415   /* Protect against multiple users and cancellation.  */
416   __libc_cleanup_push (cancel_handler, NULL);
417   __libc_lock_lock (syslog_lock);
418
419   closelog_internal ();
420   LogTag = NULL;
421   LogType = SOCK_DGRAM; /* this is the default */
422
423   /* Free the lock.  */
424   __libc_cleanup_pop (1);
425 }
426
427 /* setlogmask -- set the log mask level */
428 int
429 setlogmask(pmask)
430         int pmask;
431 {
432         int omask;
433
434         omask = LogMask;
435         if (pmask != 0)
436                 LogMask = pmask;
437         return (omask);
438 }