1 /* $NetBSD: syslog.c,v 1.19 1998/11/13 12:31:53 christos 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.19 1998/11/13 12:31:53 christos 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 <netdb.h> 51 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <paths.h> 55 #include <stdio.h> 56 #include <string.h> 57 #include <time.h> 58 #include <unistd.h> 59 60 #if __STDC__ 61 #include <stdarg.h> 62 #else 63 #include <varargs.h> 64 #endif 65 66 #ifdef __weak_alias 67 __weak_alias(closelog,_closelog); 68 __weak_alias(openlog,_openlog); 69 __weak_alias(setlogmask,_setlogmask); 70 __weak_alias(syslog,_syslog); 71 __weak_alias(vsyslog,_vsyslog); 72 #endif 73 74 static int LogFile = -1; /* fd for log */ 75 static int connected; /* have done connect */ 76 static int LogStat = 0; /* status bits, set by openlog() */ 77 static const char *LogTag = NULL; /* string to tag the entry with */ 78 static int LogFacility = LOG_USER; /* default facility code */ 79 static int LogMask = 0xff; /* mask of priorities to be logged */ 80 extern char *__progname; /* Program name, from crt0. */ 81 82 #ifdef lint 83 static const int ZERO = 0; 84 #else 85 #define ZERO 0 86 #endif 87 88 /* 89 * syslog, vsyslog -- 90 * print message on log file; output is intended for syslogd(8). 91 */ 92 void 93 #if __STDC__ 94 syslog(int pri, const char *fmt, ...) 95 #else 96 syslog(pri, fmt, va_alist) 97 int pri; 98 char *fmt; 99 va_dcl 100 #endif 101 { 102 va_list ap; 103 104 #if __STDC__ 105 va_start(ap, fmt); 106 #else 107 va_start(ap); 108 #endif 109 vsyslog(pri, fmt, ap); 110 va_end(ap); 111 } 112 113 void 114 vsyslog(pri, fmt, ap) 115 int pri; 116 const char *fmt; 117 va_list ap; 118 { 119 size_t cnt; 120 char ch, *p, *t; 121 time_t now; 122 struct tm tmnow; 123 int fd, saved_errno; 124 #define TBUF_LEN 2048 125 #define FMT_LEN 1024 126 char *stdp = NULL; /* pacify gcc */ 127 char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; 128 size_t tbuf_left, fmt_left, prlen; 129 130 #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID 131 /* Check for invalid bits. */ 132 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { 133 syslog(INTERNALLOG, 134 "syslog: unknown facility/priority: %x", pri); 135 pri &= LOG_PRIMASK|LOG_FACMASK; 136 } 137 138 /* Check priority against setlogmask values. */ 139 if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) 140 return; 141 142 saved_errno = errno; 143 144 /* Set default facility if none specified. */ 145 if ((pri & LOG_FACMASK) == 0) 146 pri |= LogFacility; 147 148 /* Build the message. */ 149 150 /* 151 * Although it's tempting, we can't ignore the possibility of 152 * overflowing the buffer when assembling the "fixed" portion 153 * of the message. Strftime's "%h" directive expands to the 154 * locale's abbreviated month name, but if the user has the 155 * ability to construct to his own locale files, it may be 156 * arbitrarily long. 157 */ 158 (void)time(&now); 159 160 p = tbuf; 161 tbuf_left = TBUF_LEN; 162 163 #define DEC() \ 164 do { \ 165 if (prlen >= tbuf_left) \ 166 prlen = tbuf_left - 1; \ 167 p += prlen; \ 168 tbuf_left -= prlen; \ 169 } while (ZERO) 170 171 prlen = snprintf(p, tbuf_left, "<%d>", pri); 172 DEC(); 173 174 tzset(); /* strftime() implies tzset(), localtime_r() doesn't. */ 175 prlen = strftime(p, tbuf_left, "%h %e %T ", localtime_r(&now, &tmnow)); 176 DEC(); 177 178 if (LogStat & LOG_PERROR) 179 stdp = p; 180 if (LogTag == NULL) 181 LogTag = __progname; 182 if (LogTag != NULL) { 183 prlen = snprintf(p, tbuf_left, "%s", LogTag); 184 DEC(); 185 } 186 if (LogStat & LOG_PID) { 187 prlen = snprintf(p, tbuf_left, "[%d]", getpid()); 188 DEC(); 189 } 190 if (LogTag != NULL) { 191 if (tbuf_left > 1) { 192 *p++ = ':'; 193 tbuf_left--; 194 } 195 if (tbuf_left > 1) { 196 *p++ = ' '; 197 tbuf_left--; 198 } 199 } 200 201 /* 202 * We wouldn't need this mess if printf handled %m, or if 203 * strerror() had been invented before syslog(). 204 */ 205 for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) { 206 if (ch == '%' && fmt[1] == 'm') { 207 ++fmt; 208 prlen = snprintf(t, fmt_left, "%s", 209 strerror(saved_errno)); 210 if (prlen >= fmt_left) 211 prlen = fmt_left - 1; 212 t += prlen; 213 fmt_left -= prlen; 214 } else { 215 if (fmt_left > 1) { 216 *t++ = ch; 217 fmt_left--; 218 } 219 } 220 } 221 *t = '\0'; 222 223 prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap); 224 DEC(); 225 cnt = p - tbuf; 226 227 /* Output to stderr if requested. */ 228 if (LogStat & LOG_PERROR) { 229 struct iovec iov[2]; 230 231 iov[0].iov_base = stdp; 232 iov[0].iov_len = cnt - (stdp - tbuf); 233 iov[1].iov_base = "\n"; 234 iov[1].iov_len = 1; 235 (void)writev(STDERR_FILENO, iov, 2); 236 } 237 238 /* Get connected, output the message to the local logger. */ 239 if (!connected) 240 openlog(LogTag, LogStat | LOG_NDELAY, 0); 241 if (send(LogFile, tbuf, cnt, 0) >= 0) 242 return; 243 244 /* 245 * Output the message to the console; don't worry about blocking, 246 * if console blocks everything will. Make sure the error reported 247 * is the one from the syslogd failure. 248 */ 249 if (LogStat & LOG_CONS && 250 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) { 251 struct iovec iov[2]; 252 253 p = strchr(tbuf, '>') + 1; 254 iov[0].iov_base = p; 255 iov[0].iov_len = cnt - (p - tbuf); 256 iov[1].iov_base = "\r\n"; 257 iov[1].iov_len = 2; 258 (void)writev(fd, iov, 2); 259 (void)close(fd); 260 } 261 } 262 263 static struct sockaddr SyslogAddr; /* AF_LOCAL address of local logger */ 264 265 void 266 openlog(ident, logstat, logfac) 267 const char *ident; 268 int logstat, logfac; 269 { 270 if (ident != NULL) 271 LogTag = ident; 272 LogStat = logstat; 273 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 274 LogFacility = logfac; 275 276 if (LogFile == -1) { 277 SyslogAddr.sa_family = AF_LOCAL; 278 (void)strncpy(SyslogAddr.sa_data, _PATH_LOG, 279 sizeof(SyslogAddr.sa_data)); 280 if (LogStat & LOG_NDELAY) { 281 if ((LogFile = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) 282 return; 283 (void)fcntl(LogFile, F_SETFD, 1); 284 } 285 } 286 if (LogFile != -1 && !connected) { 287 if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) { 288 (void)close(LogFile); 289 LogFile = -1; 290 } else 291 connected = 1; 292 } 293 } 294 295 void 296 closelog() 297 { 298 (void)close(LogFile); 299 LogFile = -1; 300 connected = 0; 301 } 302 303 /* setlogmask -- set the log mask level */ 304 int 305 setlogmask(pmask) 306 int pmask; 307 { 308 int omask; 309 310 omask = LogMask; 311 if (pmask != 0) 312 LogMask = pmask; 313 return (omask); 314 } 315