1 /* $NetBSD: syslog.c,v 1.27 2001/07/30 04:12:33 atatat 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.27 2001/07/30 04:12:33 atatat 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 <stdlib.h> 58 #include <string.h> 59 #include <time.h> 60 #include <unistd.h> 61 #include "reentrant.h" 62 63 #if __STDC__ 64 #include <stdarg.h> 65 #else 66 #include <varargs.h> 67 #endif 68 69 #ifdef __weak_alias 70 __weak_alias(closelog,_closelog) 71 __weak_alias(openlog,_openlog) 72 __weak_alias(setlogmask,_setlogmask) 73 __weak_alias(syslog,_syslog) 74 __weak_alias(vsyslog,_vsyslog) 75 #endif 76 77 static int LogFile = -1; /* fd for log */ 78 static int connected; /* have done connect */ 79 static int LogStat = 0; /* status bits, set by openlog() */ 80 static const char *LogTag = NULL; /* string to tag the entry with */ 81 static int LogFacility = LOG_USER; /* default facility code */ 82 static int LogMask = 0xff; /* mask of priorities to be logged */ 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 _BSD_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, tries; 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 = getprogname(); 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 /* 250 * Try to send it twice. If the first try fails, we might 251 * be able to simply reconnect and send the message (which 252 * means syslogd was restarted since we connected the first 253 * time). If the second attempt doesn't work, then something 254 * else is wrong and there's probably not much we can do 255 * here. 256 */ 257 for (tries = 1; tries <= 2; tries++) { 258 if (!connected) 259 openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); 260 if (send(LogFile, tbuf, cnt, 0) >= 0) { 261 mutex_unlock(&syslog_mutex); 262 return; 263 } 264 else 265 closelog_unlocked(); 266 } 267 mutex_unlock(&syslog_mutex); 268 269 /* 270 * Output the message to the console; don't worry about blocking, 271 * if console blocks everything will. Make sure the error reported 272 * is the one from the syslogd failure. 273 */ 274 if (LogStat & LOG_CONS && 275 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) { 276 struct iovec iov[2]; 277 278 p = strchr(tbuf, '>') + 1; 279 iov[0].iov_base = p; 280 iov[0].iov_len = cnt - (p - tbuf); 281 iov[1].iov_base = "\r\n"; 282 iov[1].iov_len = 2; 283 (void)writev(fd, iov, 2); 284 (void)close(fd); 285 } 286 } 287 288 static struct sockaddr_un SyslogAddr; /* AF_LOCAL address of local logger */ 289 290 static void 291 openlog_unlocked(ident, logstat, logfac) 292 const char *ident; 293 int logstat, logfac; 294 { 295 296 if (ident != NULL) 297 LogTag = ident; 298 LogStat = logstat; 299 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 300 LogFacility = logfac; 301 302 if (LogFile == -1) { 303 SyslogAddr.sun_family = AF_LOCAL; 304 (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, 305 sizeof(SyslogAddr.sun_path)); 306 if (LogStat & LOG_NDELAY) { 307 if ((LogFile = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) 308 return; 309 (void)fcntl(LogFile, F_SETFD, 1); 310 } 311 } 312 if (LogFile != -1 && !connected) { 313 if (connect(LogFile, (struct sockaddr *)(void *)&SyslogAddr, 314 SUN_LEN(&SyslogAddr)) == -1) { 315 (void)close(LogFile); 316 LogFile = -1; 317 } else 318 connected = 1; 319 } 320 } 321 322 void 323 openlog(ident, logstat, logfac) 324 const char *ident; 325 int logstat, logfac; 326 { 327 328 mutex_lock(&syslog_mutex); 329 openlog_unlocked(ident, logstat, logfac); 330 mutex_unlock(&syslog_mutex); 331 } 332 333 static void 334 closelog_unlocked() 335 { 336 (void)close(LogFile); 337 LogFile = -1; 338 connected = 0; 339 } 340 341 void 342 closelog() 343 { 344 345 mutex_lock(&syslog_mutex); 346 closelog_unlocked(); 347 mutex_unlock(&syslog_mutex); 348 } 349 350 /* setlogmask -- set the log mask level */ 351 int 352 setlogmask(pmask) 353 int pmask; 354 { 355 int omask; 356 357 omask = LogMask; 358 if (pmask != 0) 359 LogMask = pmask; 360 return (omask); 361 } 362