]> git.sur5r.net Git - openldap/blob - servers/slapd/syslog.c
47ea1c6d9d721d70986756e4c750831a63f95370
[openldap] / servers / slapd / syslog.c
1 /*      $OpenBSD: syslog.c,v 1.29 2007/11/09 18:40:19 millert Exp $ */
2 /*
3  * Copyright (c) 1983, 1988, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include "portable.h"
32
33 #include <sys/types.h>
34 #include <ac/socket.h>
35 #include <ac/syslog.h>
36 #include <sys/uio.h>
37 #include <sys/un.h>
38 #include <netdb.h>
39
40 #include <ac/errno.h>
41 #include <fcntl.h>
42 #include <paths.h>
43 #include <stdio.h>
44 #include <ac/string.h>
45 #include <ac/time.h>
46 #include <ac/unistd.h>
47 #include <ac/stdarg.h>
48
49 #include "slap.h"
50 #include "lutil.h"
51
52 static int      LogType = SOCK_DGRAM;   /* type of socket connection */
53 static int      LogFile = -1;           /* fd for log */
54 static int      connected;              /* have done connect */
55 static int      LogStat;                /* status bits, set by openlog() */
56 static const char *LogTag;              /* string to tag the entry with */
57 static int      LogFacility = LOG_USER; /* default facility code */
58
59 static void disconnectlog(void);
60 static void connectlog(void);
61
62 static void my_localtime(const time_t *t, struct tm *tm);
63
64 /*
65  * syslog
66  *      print message on log file; output is intended for syslogd(8).
67  */
68 void
69 syslog(int pri, const char *fmt, ...)
70 {
71         va_list ap;
72         char *p, *pend;
73 #define TBUF_LEN        2048
74 #define FMT_LEN         1024
75         char tbuf[TBUF_LEN];
76         int cnt;
77         int error;
78         int tbuf_left, prlen;
79
80         va_start(ap, fmt);
81
82         /* Check for invalid bits. */
83         if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
84                 if (LogTest(LOG_ERR))
85                         lutil_debug(slap_debug, LOG_ERR, 
86                             "syslog: unknown facility/priority: %x", pri);
87                 pri &= LOG_PRIMASK|LOG_FACMASK;
88         }
89
90         /* Set default facility if none specified. */
91         if ((pri & LOG_FACMASK) == 0)
92                 pri |= LogFacility;
93
94         p = tbuf;
95         pend = p + TBUF_LEN;
96
97         *p++ = '<';
98         p += sprintf(p, "%d", pri);
99         *p++ = '>';
100
101 #if 0
102         (void)time(&now);
103         my_localtime(&now, &tm);
104         p += strftime(p, tbuf_left, "%h %e %T ", &tm);
105 #endif
106
107         if (LogTag != NULL) {
108                 p = lutil_strcopy(p, LogTag);
109         }
110         if (LogStat & LOG_PID) {
111                 *p++ = '[';
112                 p += sprintf(p, "%ld", (long)getpid());
113                 *p++ = ']';
114         }
115         if (LogTag != NULL) {
116                 *p++ = ':';
117                 *p++ = ' ';
118         }
119
120         tbuf_left = pend - p;
121         prlen = vsnprintf(p, tbuf_left, fmt, ap);
122         va_end(ap);
123         if (prlen < 0)
124                 prlen = 0;
125         else if (prlen >= tbuf_left)
126                 prlen = tbuf_left - 1;
127         p += prlen;
128         cnt = p - tbuf;
129
130         /* Get connected, output the message to the local logger. */
131         if (LogFile == -1)
132                 openlog(LogTag, LogStat, 0);
133         connectlog();
134
135         /*
136          * If the send() failed, there are two likely scenarios:
137          *  1) syslogd was restarted
138          *  2) /dev/log is out of socket buffer space
139          * We attempt to reconnect to /dev/log to take care of
140          * case #1 and keep send()ing data to cover case #2
141          * to give syslogd a chance to empty its socket buffer.
142          */
143         if ((error = send(LogFile, tbuf, cnt, 0)) < 0) {
144                 if (errno != ENOBUFS) {
145                         disconnectlog();
146                         connectlog();
147                 }
148                 do {
149                         usleep(1);
150                         if ((error = send(LogFile, tbuf, cnt, 0)) >= 0)
151                                 break;
152                 } while (errno == ENOBUFS);
153         }
154 }
155
156 static void
157 disconnectlog(void)
158 {
159         /*
160          * If the user closed the FD and opened another in the same slot,
161          * that's their problem.  They should close it before calling on
162          * system services.
163          */
164         if (LogFile != -1) {
165                 close(LogFile);
166                 LogFile = -1;
167         }
168         connected = 0;          /* retry connect */
169 }
170
171 static void
172 connectlog(void)
173 {
174         struct sockaddr_un SyslogAddr;  /* AF_UNIX address of local logger */
175
176         if (LogFile == -1) {
177                 if ((LogFile = socket(AF_UNIX, LogType, 0)) == -1)
178                         return;
179                 (void)fcntl(LogFile, F_SETFD, FD_CLOEXEC);
180         }
181         if (LogFile != -1 && !connected) {
182                 memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
183 #ifdef _BSD
184                 SyslogAddr.sun_len = sizeof(SyslogAddr);
185 #endif
186                 SyslogAddr.sun_family = AF_UNIX;
187                 strncpy(SyslogAddr.sun_path, _PATH_LOG,
188                     sizeof(SyslogAddr.sun_path));
189                 if (connect(LogFile, (struct sockaddr *)&SyslogAddr,
190                     sizeof(SyslogAddr)) == -1) {
191                         (void)close(LogFile);
192                         LogFile = -1;
193                 } else
194                         connected = 1;
195         }
196 }
197
198 void
199 openlog(const char *ident, int logstat, int logfac)
200 {
201         if (ident != NULL)
202                 LogTag = ident;
203         LogStat = logstat;
204         if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
205                 LogFacility = logfac;
206
207         if (LogStat & LOG_NDELAY)       /* open immediately */
208                 connectlog();
209 }
210
211 void
212 closelog()
213 {
214         (void)close(LogFile);
215         LogFile = -1;
216         connected = 0;
217         LogTag = NULL;
218 }
219
220 #if 0
221 #define SECS_PER_HOUR   (60 * 60)
222 #define SECS_PER_DAY    (SECS_PER_HOUR * 24)
223
224 /* How many days come before each month (0-12).  */
225 static const unsigned short int __mon_yday[2][13] =
226   {
227     /* Normal years.  */
228     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
229     /* Leap years.  */
230     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
231   };
232
233 /* Compute the `struct tm' representation of *T,
234    and store year, yday, mon, mday, wday, hour, min, sec into *TP */
235 static void my_localtime(const time_t *t, struct tm *tm)
236 {
237   time_t days, rem, y;
238   const unsigned short int *ip;
239   int leap;
240
241   days = *t / SECS_PER_DAY;
242   rem = *t % SECS_PER_DAY;
243   rem -= timezone;
244   while (rem < 0)
245     {
246       rem += SECS_PER_DAY;
247       --days;
248     }
249   while (rem >= SECS_PER_DAY)
250     {
251       rem -= SECS_PER_DAY;
252       ++days;
253     }
254   tm->tm_hour = rem / SECS_PER_HOUR;
255   rem %= SECS_PER_HOUR;
256   tm->tm_min = rem / 60;
257   tm->tm_sec = rem % 60;
258   /* January 1, 1970 was a Thursday.  */
259   tm->tm_wday = (4 + days) % 7;
260   if (tm->tm_wday < 0)
261     tm->tm_wday += 7;
262   y = 1970;
263
264 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
265 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
266 #define ISLEAP(y)       ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
267
268   leap = ISLEAP(y);
269   while (days < 0 || days >= (leap ? 366 : 365))
270     {
271       /* Guess a corrected year, assuming 365 days per year.  */
272       time_t yg = y + days / 365 - (days % 365 < 0);
273
274       /* Adjust DAYS and Y to match the guessed year.  */
275       days -= ((yg - y) * 365
276                + LEAPS_THRU_END_OF (yg - 1)
277                - LEAPS_THRU_END_OF (y - 1));
278       y = yg;
279     }
280   tm->tm_year = y - 1900;
281   tm->tm_yday = days;
282   ip = __mon_yday[leap];
283   for (y = 11; days < (long int) ip[y]; --y)
284     continue;
285   days -= ip[y];
286   tm->tm_mon = y;
287   tm->tm_mday = days + 1;
288 }
289 #endif