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