Updated from ../gpl2lgpl.sed /home/gd/gnu/lib/error.c
[kopensolaris-gnu/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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)syslog.c    8.4 (Berkeley) 3/18/94";
36 #endif /* LIBC_SCCS and not lint */
37
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/syslog.h>
41 #include <sys/uio.h>
42 #include <netdb.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <paths.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52
53 #if __STDC__
54 #include <stdarg.h>
55 #else
56 #include <varargs.h>
57 #endif
58
59 static int      LogFile = -1;           /* fd for log */
60 static int      connected;              /* have done connect */
61 static int      LogStat = 0;            /* status bits, set by openlog() */
62 static const char *LogTag = NULL;       /* string to tag the entry with */
63 static int      LogFacility = LOG_USER; /* default facility code */
64 static int      LogMask = 0xff;         /* mask of priorities to be logged */
65 extern char     *__progname;            /* Program name, from crt0. */
66
67 /*
68  * syslog, vsyslog --
69  *      print message on log file; output is intended for syslogd(8).
70  */
71 void
72 #if __STDC__
73 syslog(int pri, const char *fmt, ...)
74 #else
75 syslog(pri, fmt, va_alist)
76         int pri;
77         char *fmt;
78         va_dcl
79 #endif
80 {
81         va_list ap;
82
83 #if __STDC__
84         va_start(ap, fmt);
85 #else
86         va_start(ap);
87 #endif
88         vsyslog(pri, fmt, ap);
89         va_end(ap);
90 }
91
92 void
93 vsyslog(pri, fmt, ap)
94         int pri;
95         register const char *fmt;
96         va_list ap;
97 {
98         time_t now;
99         int fd;
100         FILE *f;
101         char *buf = 0;
102         size_t bufsize = 0;
103         size_t prioff, msgoff;
104
105 #define INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
106         /* Check for invalid bits. */
107         if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
108                 syslog(INTERNALLOG,
109                     "syslog: unknown facility/priority: %x", pri);
110                 pri &= LOG_PRIMASK|LOG_FACMASK;
111         }
112
113         /* Check priority against setlogmask values. */
114         if (!LOG_MASK(LOG_PRI(pri)) & LogMask)
115                 return;
116
117         /* Set default facility if none specified. */
118         if ((pri & LOG_FACMASK) == 0)
119                 pri |= LogFacility;
120
121         /* Build the message in a memory-buffer stream.  */
122         f = open_memstream (&buf, &bufsize);
123         prioff = fprintf (f, "<%d>", pri);
124         (void) time (&now);
125 #ifdef USE_IN_LIBIO
126         f->_IO_write_ptr += strftime (f->_IO_write_ptr,
127                                       f->_IO_write_end - f->_IO_write_ptr,
128                                       "%h %e %T ", localtime (&now));
129 #else
130         f->__bufp += strftime (f->__bufp, f->__put_limit - f->__bufp,
131                                "%h %e %T ", localtime (&now));
132 #endif
133         msgoff = ftell (f);
134         if (LogTag == NULL)
135           LogTag = __progname;
136         if (LogTag != NULL)
137           fputs (LogTag, f);
138         if (LogStat & LOG_PID)
139           fprintf (f, "[%d]", getpid ());
140         if (LogTag != NULL)
141           putc (':', f), putc (' ', f);
142
143         /* We have the header.  Print the user's format into the buffer.  */
144         vfprintf (f, fmt, ap);
145
146         /* Close the memory stream; this will finalize the data
147            into a malloc'd buffer in BUF.  */
148         fclose (f);
149
150         /* Output to stderr if requested. */
151         if (LogStat & LOG_PERROR) {
152                 struct iovec iov[2];
153                 register struct iovec *v = iov;
154
155                 v->iov_base = buf + msgoff;
156                 v->iov_len = bufsize - msgoff;
157                 ++v;
158                 v->iov_base = (char *) "\n";
159                 v->iov_len = 1;
160                 (void)writev(STDERR_FILENO, iov, 2);
161         }
162
163         /* Get connected, output the message to the local logger. */
164         if (!connected)
165                 openlog(LogTag, LogStat | LOG_NDELAY, 0);
166         if (send(LogFile, buf, bufsize, 0) < 0)
167           {
168             /*
169              * Output the message to the console; don't worry about blocking,
170              * if console blocks everything will.  Make sure the error reported
171              * is the one from the syslogd failure.
172              */
173             if (LogStat & LOG_CONS &&
174                 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0)
175               {
176                 dprintf (fd, "%s\r\n", buf + msgoff);
177                 (void)close(fd);
178               }
179           }
180
181         free (buf);
182 }
183
184 static struct sockaddr SyslogAddr;      /* AF_UNIX address of local logger */
185
186 void
187 openlog(ident, logstat, logfac)
188         const char *ident;
189         int logstat, logfac;
190 {
191         if (ident != NULL)
192                 LogTag = ident;
193         LogStat = logstat;
194         if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
195                 LogFacility = logfac;
196
197         if (LogFile == -1) {
198                 SyslogAddr.sa_family = AF_UNIX;
199                 (void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
200                     sizeof(SyslogAddr.sa_data));
201                 if (LogStat & LOG_NDELAY) {
202                         if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
203                                 return;
204                         (void)fcntl(LogFile, F_SETFD, 1);
205                 }
206         }
207         if (LogFile != -1 && !connected)
208                 if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) {
209                         (void)close(LogFile);
210                         LogFile = -1;
211                 } else
212                         connected = 1;
213 }
214
215 void
216 closelog()
217 {
218         (void)close(LogFile);
219         LogFile = -1;
220         connected = 0;
221 }
222
223 /* setlogmask -- set the log mask level */
224 int
225 setlogmask(pmask)
226         int pmask;
227 {
228         int omask;
229
230         omask = LogMask;
231         if (pmask != 0)
232                 LogMask = pmask;
233         return (omask);
234 }