1 /* $NetBSD: syslog.c,v 1.24 2000/01/22 22:19:12 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #if defined(LIBC_SCCS) && !defined(lint) 38 #if 0 39 static char sccsid[] = "@(#)syslog.c 8.5 (Berkeley) 4/29/95"; 40 #else 41 __RCSID("$NetBSD: syslog.c,v 1.24 2000/01/22 22:19:12 mycroft Exp $"); 42 #endif 43 #endif /* LIBC_SCCS and not lint */ 44 45 #include "namespace.h" 46 #include <sys/types.h> 47 #include <sys/socket.h> 48 #include <sys/syslog.h> 49 #include <sys/uio.h> 50 #include <sys/un.h> 51 #include <netdb.h> 52 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <paths.h> 56 #include <stdio.h> 57 #include <string.h> 58 #include <time.h> 59 #include <unistd.h> 60 #include "reentrant.h" 61 62 #if __STDC__ 63 #include <stdarg.h> 64 #else 65 #include <varargs.h> 66 #endif 67 68 #ifdef __weak_alias 69 __weak_alias(closelog,_closelog) 70 __weak_alias(openlog,_openlog) 71 __weak_alias(setlogmask,_setlogmask) 72 __weak_alias(syslog,_syslog) 73 __weak_alias(vsyslog,_vsyslog) 74 #endif 75 76 static int LogFile = -1; /* fd for log */ 77 static int connected; /* have done connect */ 78 static int LogStat = 0; /* status bits, set by openlog() */ 79 static const char *LogTag = NULL; /* string to tag the entry with */ 80 static int LogFacility = LOG_USER; /* default facility code */ 81 static int LogMask = 0xff; /* mask of priorities to be logged */ 82 extern char *__progname; /* Program name, from crt0. */ 83 84 static void openlog_unlocked __P((const char *, int, int)); 85 static void closelog_unlocked __P((void)); 86 87 #ifdef _REENT 88 static mutex_t syslog_mutex = MUTEX_INITIALIZER; 89 #endif 90 91 #ifdef lint 92 static const int ZERO = 0; 93 #else 94 #define ZERO 0 95 #endif 96 97 /* 98 * syslog, vsyslog -- 99 * print message on log file; output is intended for syslogd(8). 100 */ 101 void 102 #if __STDC__ 103 syslog(int pri, const char *fmt, ...) 104 #else 105 syslog(pri, fmt, va_alist) 106 int pri; 107 char *fmt; 108 va_dcl 109 #endif 110 { 111 va_list ap; 112 113 #if __STDC__ 114 va_start(ap, fmt); 115 #else 116 va_start(ap); 117 #endif 118 vsyslog(pri, fmt, ap); 119 va_end(ap); 120 } 121 122 void 123 vsyslog(pri, fmt, ap) 124 int pri; 125 const char *fmt; 126 va_list ap; 127 { 128 size_t cnt; 129 char ch, *p, *t; 130 time_t now; 131 struct tm tmnow; 132 int fd, saved_errno; 133 #define TBUF_LEN 2048 134 #define FMT_LEN 1024 135 char *stdp = NULL; /* pacify gcc */ 136 char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; 137 size_t tbuf_left, fmt_left, prlen; 138 139 #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID 140 /* Check for invalid bits. */ 141 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { 142 syslog(INTERNALLOG, 143 "syslog: unknown facility/priority: %x", pri); 144 pri &= LOG_PRIMASK|LOG_FACMASK; 145 } 146 147 /* Check priority against setlogmask values. */ 148 if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) 149 return; 150 151 saved_errno = errno; 152 153 /* Set default facility if none specified. */ 154 if ((pri & LOG_FACMASK) == 0) 155 pri |= LogFacility; 156 157 /* Build the message. */ 158 159 /* 160 * Although it's tempting, we can't ignore the possibility of 161 * overflowing the buffer when assembling the "fixed" portion 162 * of the message. Strftime's "%h" directive expands to the 163 * locale's abbreviated month name, but if the user has the 164 * ability to construct to his own locale files, it may be 165 * arbitrarily long. 166 */ 167 (void)time(&now); 168 169 p = tbuf; 170 tbuf_left = TBUF_LEN; 171 172 #define DEC() \ 173 do { \ 174 if (prlen >= tbuf_left) \ 175 prlen = tbuf_left - 1; \ 176 p += prlen; \ 177 tbuf_left -= prlen; \ 178 } while (ZERO) 179 180 prlen = snprintf(p, tbuf_left, "<%d>", pri); 181 DEC(); 182 183 tzset(); /* strftime() implies tzset(), localtime_r() doesn't. */ 184 prlen = strftime(p, tbuf_left, "%h %e %T ", localtime_r(&now, &tmnow)); 185 DEC(); 186 187 if (LogStat & LOG_PERROR) 188 stdp = p; 189 if (LogTag == NULL) 190 LogTag = __progname; 191 if (LogTag != NULL) { 192 prlen = snprintf(p, tbuf_left, "%s", LogTag); 193 DEC(); 194 } 195 if (LogStat & LOG_PID) { 196 prlen = snprintf(p, tbuf_left, "[%d]", getpid()); 197 DEC(); 198 } 199 if (LogTag != NULL) { 200 if (tbuf_left > 1) { 201 *p++ = ':'; 202 tbuf_left--; 203 } 204 if (tbuf_left > 1) { 205 *p++ = ' '; 206 tbuf_left--; 207 } 208 } 209 210 /* 211 * We wouldn't need this mess if printf handled %m, or if 212 * strerror() had been invented before syslog(). 213 */ 214 for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) { 215 if (ch == '%' && fmt[1] == 'm') { 216 ++fmt; 217 prlen = snprintf(t, fmt_left, "%s", 218 strerror(saved_errno)); 219 if (prlen >= fmt_left) 220 prlen = fmt_left - 1; 221 t += prlen; 222 fmt_left -= prlen; 223 } else { 224 if (fmt_left > 1) { 225 *t++ = ch; 226 fmt_left--; 227 } 228 } 229 } 230 *t = '\0'; 231 232 prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap); 233 DEC(); 234 cnt = p - tbuf; 235 236 /* Output to stderr if requested. */ 237 if (LogStat & LOG_PERROR) { 238 struct iovec iov[2]; 239 240 iov[0].iov_base = stdp; 241 iov[0].iov_len = cnt - (stdp - tbuf); 242 iov[1].iov_base = "\n"; 243 iov[1].iov_len = 1; 244 (void)writev(STDERR_FILENO, iov, 2); 245 } 246 247 /* Get connected, output the message to the local logger. */ 248 mutex_lock(&syslog_mutex); 249 if (!connected) 250 openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); 251 if (send(LogFile, tbuf, cnt, 0) >= 0) { 252 mutex_unlock(&syslog_mutex); 253 return; 254 } 255 mutex_unlock(&syslog_mutex); 256 257 /* 258 * Output the message to the console; don't worry about blocking, 259 * if console blocks everything will. Make sure the error reported 260 * is the one from the syslogd failure. 261 */ 262 if (LogStat & LOG_CONS && 263 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) { 264 struct iovec iov[2]; 265 266 p = strchr(tbuf, '>') + 1; 267 iov[0].iov_base = p; 268 iov[0].iov_len = cnt - (p - tbuf); 269 iov[1].iov_base = "\r\n"; 270 iov[1].iov_len = 2; 271 (void)writev(fd, iov, 2); 272 (void)close(fd); 273 } 274 } 275 276 static struct sockaddr_un SyslogAddr; /* AF_LOCAL address of local logger */ 277 278 static void 279 openlog_unlocked(ident, logstat, logfac) 280 const char *ident; 281 int logstat, logfac; 282 { 283 284 if (ident != NULL) 285 LogTag = ident; 286 LogStat = logstat; 287 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 288 LogFacility = logfac; 289 290 if (LogFile == -1) { 291 SyslogAddr.sun_family = AF_LOCAL; 292 (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, 293 sizeof(SyslogAddr.sun_path)); 294 if (LogStat & LOG_NDELAY) { 295 if ((LogFile = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) 296 return; 297 (void)fcntl(LogFile, F_SETFD, 1); 298 } 299 } 300 if (LogFile != -1 && !connected) { 301 if (connect(LogFile, (struct sockaddr *)(void *)&SyslogAddr, 302 SUN_LEN(&SyslogAddr)) == -1) { 303 (void)close(LogFile); 304 LogFile = -1; 305 } else 306 connected = 1; 307 } 308 } 309 310 void 311 openlog(ident, logstat, logfac) 312 const char *ident; 313 int logstat, logfac; 314 { 315 316 mutex_lock(&syslog_mutex); 317 openlog_unlocked(ident, logstat, logfac); 318 mutex_unlock(&syslog_mutex); 319 } 320 321 static void 322 closelog_unlocked() 323 { 324 (void)close(LogFile); 325 LogFile = -1; 326 connected = 0; 327 } 328 329 void 330 closelog() 331 { 332 333 mutex_lock(&syslog_mutex); 334 closelog_unlocked(); 335 mutex_unlock(&syslog_mutex); 336 } 337 338 /* setlogmask -- set the log mask level */ 339 int 340 setlogmask(pmask) 341 int pmask; 342 { 343 int omask; 344 345 omask = LogMask; 346 if (pmask != 0) 347 LogMask = pmask; 348 return (omask); 349 } 350