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