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