X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/59e0d9fe772464b93d835d2a2964457702469a43..51282358e8fdbfc483c0c34e7eae9b89b51f2570:/gen/syslog.c diff --git a/gen/syslog.c b/gen/syslog.c index 216ce85..1ef8aa2 100644 --- a/gen/syslog.c +++ b/gen/syslog.c @@ -1,24 +1,23 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." * * @APPLE_LICENSE_HEADER_END@ */ @@ -56,19 +55,28 @@ */ #include +#include #include #include #include #include #include - +#include +#include #include #include #include #include +#include +#include #include #include +#include #include +#include +#include +#include +#include #ifdef __STDC__ #include @@ -77,13 +85,47 @@ #endif #include - -static int LogFile = -1; /* fd for log */ -static int connected; /* have done connect */ -static int LogStat = 0; /* status bits, set by openlog() */ -static const char *LogTag = NULL; /* string to tag the entry with */ -static int LogFacility = LOG_USER; /* default facility code */ -static int LogMask = 0xff; /* mask of priorities to be logged */ + +#define LOG_NO_NOTIFY 0x1000 +#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID + +#ifdef BUILDING_VARIANT +__private_extern__ int _sl_LogStat; /* status bits, set by openlog() */ +__private_extern__ const char *_sl_LogTag; /* string to tag the entry with */ +__private_extern__ int _sl_LogFacility; /* default facility code */ +__private_extern__ int _sl_LogMask; /* local mask of priorities to be logged */ +__private_extern__ int _sl_MasterLogMask; /* master (remote control) mask of priorities to be logged */ +__private_extern__ int _sl_ProcLogMask; /* process-specific (remote control) mask of priorities to be logged */ +__private_extern__ int _sl_RCToken; /* for remote control change notification */ +__private_extern__ int _sl_NotifyToken; /* for remote control of priority filter */ +__private_extern__ int _sl_NotifyMaster; /* for remote control of priority filter */ +__private_extern__ int _sl_pid; /* pid */ +#else /* !BUILDING_VARIANT */ +__private_extern__ int _sl_LogStat = 0; /* status bits, set by openlog() */ +__private_extern__ const char *_sl_LogTag = NULL; /* string to tag the entry with */ +__private_extern__ int _sl_LogFacility = LOG_USER; /* default facility code */ +__private_extern__ int _sl_LogMask = 0xff; /* mask of priorities to be logged */ +__private_extern__ int _sl_MasterLogMask = 0; /* master mask of priorities to be logged */ +__private_extern__ int _sl_ProcLogMask = 0; /* process-specific mask of priorities to be logged */ +__private_extern__ int _sl_RCToken = -1; /* for remote control change notification */ +__private_extern__ int _sl_NotifyToken = -1; /* for remote control of max logged priority */ +__private_extern__ int _sl_NotifyMaster = -1; /* for remote control of max logged priority */ +__private_extern__ int _sl_pid = -1; /* pid */ +#endif /* BUILDING_VARIANT */ + +__private_extern__ void _sl_init_notify(); + +#define ASL_SERVICE_NAME "com.apple.system.logger" +static mach_port_t asl_server_port = MACH_PORT_NULL; + +#define NOTIFY_SYSTEM_MASTER "com.apple.system.syslog.master" +#define NOTIFY_PREFIX_SYSTEM "com.apple.system.syslog" +#define NOTIFY_PREFIX_USER "user.syslog" +#define NOTIFY_STATE_OFFSET 1000 + +/* notify SPI */ +uint32_t notify_register_plain(const char *name, int *out_token); +const char *asl_syslog_faciliy_num_to_name(int); /* * syslog, vsyslog -- @@ -111,200 +153,415 @@ syslog(pri, fmt, va_alist) } void -vsyslog(pri, fmt, ap) - int pri; - register const char *fmt; - va_list ap; +vsyslog(int pri, const char *fmt, va_list ap) { - register int cnt; - register char ch, *p, *t; - time_t now; - int fd, saved_errno; -#define TBUF_LEN 2048 -#define FMT_LEN 1024 - char *stdp, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; - int tbuf_left, fmt_left, prlen; + int status, i, saved_errno, filter, check, rc_filter; + time_t tick; + struct timeval tval; + uint32_t elen, count, outlen; + char *p, *str, *expanded, *err_str, hname[MAXHOSTNAMELEN+1]; + const char *val; + uint64_t cval; + int fd, mask, level, facility; + aslmsg msg; + kern_return_t kstatus; + caddr_t out; + + saved_errno = errno; + + if (_sl_pid == -1) _sl_pid = getpid(); -#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ - if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { - syslog(INTERNALLOG, - "syslog: unknown facility/priority: %x", pri); - pri &= LOG_PRIMASK|LOG_FACMASK; + if (pri & ~(LOG_PRIMASK | LOG_FACMASK)) + { + syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); + pri &= (LOG_PRIMASK | LOG_FACMASK); } - /* Check priority against setlogmask values. */ - if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) - return; + level = LOG_PRI(pri); + facility = pri & LOG_FACMASK; - saved_errno = errno; + if (facility == 0) facility = _sl_LogFacility; + + _sl_init_notify(); + + /* initialize or re-check process-specific and master filters */ + if (_sl_RCToken >= 0) + { + check = 0; + status = notify_check(_sl_RCToken, &check); + if ((status == NOTIFY_STATUS_OK) && (check != 0)) + { + if (_sl_NotifyMaster >= 0) + { + cval = 0; + if (notify_get_state(_sl_NotifyMaster, &cval) == NOTIFY_STATUS_OK) _sl_MasterLogMask = cval; + } + + if (_sl_NotifyToken >= 0) + { + cval = 0; + if (notify_get_state(_sl_NotifyToken, &cval) == NOTIFY_STATUS_OK) _sl_ProcLogMask = cval; + } + } + } + + filter = _sl_LogMask; + rc_filter = 0; + + /* master filter overrides local filter */ + if (_sl_MasterLogMask != 0) + { + filter = _sl_MasterLogMask; + rc_filter = 1; + } + + /* process-specific filter overrides local and master */ + if (_sl_ProcLogMask != 0) + { + filter = _sl_ProcLogMask; + rc_filter = 1; + } - /* Set default facility if none specified. */ - if ((pri & LOG_FACMASK) == 0) - pri |= LogFacility; + mask = LOG_MASK(level); + if ((mask & filter) == 0) return; /* Build the message. */ - - /* - * Although it's tempting, we can't ignore the possibility of - * overflowing the buffer when assembling the "fixed" portion - * of the message. Strftime's "%h" directive expands to the - * locale's abbreviated month name, but if the user has the - * ability to construct to his own locale files, it may be - * arbitrarily long. - */ - (void)time(&now); - - p = tbuf; - tbuf_left = TBUF_LEN; - -#define DEC() \ - do { \ - if (prlen >= tbuf_left) \ - prlen = tbuf_left - 1; \ - p += prlen; \ - tbuf_left -= prlen; \ - } while (0) - - prlen = snprintf(p, tbuf_left, "<%d>", pri); - DEC(); - - prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now)); - DEC(); - - if (LogStat & LOG_PERROR) - stdp = p; - if (LogTag == NULL) - LogTag = *(*_NSGetArgv()); - if (LogTag != NULL) { - prlen = snprintf(p, tbuf_left, "%s", LogTag); - DEC(); + msg = asl_new(ASL_TYPE_MSG); + + if (_sl_LogTag == NULL) _sl_LogTag = *(*_NSGetArgv()); + if (_sl_LogTag != NULL) + { + asl_set(msg, ASL_KEY_SENDER, _sl_LogTag); } - if (LogStat & LOG_PID) { - prlen = snprintf(p, tbuf_left, "[%d]", getpid()); - DEC(); + + str = (char *)asl_syslog_faciliy_num_to_name(facility); + if (str != NULL) asl_set(msg, ASL_KEY_FACILITY, str); + + str = NULL; + memset(&tval, 0, sizeof(struct timeval)); + + status = gettimeofday(&tval, NULL); + if (status == 0) + { + str = NULL; + asprintf(&str, "%lu", tval.tv_sec); + if (str != NULL) + { + asl_set(msg, ASL_KEY_TIME, str); + free(str); + } + + str = NULL; + asprintf(&str, "%lu", tval.tv_usec * 1000); + if (str != NULL) + { + asl_set(msg, ASL_KEY_TIME_NSEC, str); + free(str); + } } - if (LogTag != NULL) { - if (tbuf_left > 1) { - *p++ = ':'; - tbuf_left--; + else + { + tick = time(NULL); + str = NULL; + asprintf(&str, "%lu", tick); + if (str != NULL) + { + asl_set(msg, ASL_KEY_TIME, str); + free(str); } - if (tbuf_left > 1) { - *p++ = ' '; - tbuf_left--; + } + + str = NULL; + asprintf(&str, "%u", _sl_pid); + if (str != NULL) + { + asl_set(msg, ASL_KEY_PID, str); + free(str); + } + + str = NULL; + asprintf(&str, "%d", getuid()); + if (str != NULL) + { + asl_set(msg, ASL_KEY_UID, str); + free(str); + } + + str = NULL; + asprintf(&str, "%u", getgid()); + if (str != NULL) + { + asl_set(msg, ASL_KEY_GID, str); + free(str); + } + + str = NULL; + asprintf(&str, "%u", level); + if (str != NULL) + { + asl_set(msg, ASL_KEY_LEVEL, str); + free(str); + } + + status = gethostname(hname, MAXHOSTNAMELEN); + if (status < 0) asl_set(msg, ASL_KEY_HOST, "localhost"); + else asl_set(msg, ASL_KEY_HOST, hname); + + /* check for %m */ + count = 0; + for (i = 0; fmt[i] != '\0'; i++) + { + if ((fmt[i] == '%') && (fmt[i+1] == 'm')) count++; + } + + expanded = NULL; + elen = 0; + err_str = NULL; + + /* deal with malloc failures gracefully */ + if (count > 0) + { + err_str = strdup(strerror(saved_errno)); + if (err_str == NULL) count = 0; + else + { + elen = strlen(err_str); + expanded = malloc(i + (count * elen)); + if (expanded == NULL) count = 0; } } - /* - * We wouldn't need this mess if printf handled %m, or if - * strerror() had been invented before syslog(). - */ - for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) { - if (ch == '%' && fmt[1] == 'm') { - ++fmt; - prlen = snprintf(t, fmt_left, "%s", - strerror(saved_errno)); - if (prlen >= fmt_left) - prlen = fmt_left - 1; - t += prlen; - fmt_left -= prlen; - } else { - if (fmt_left > 1) { - *t++ = ch; - fmt_left--; + if (expanded == NULL) expanded = (char *)fmt; + if (count > 0) + { + p = expanded; + + for (i = 0; fmt[i] != '\0'; i++) + { + if ((fmt[i] == '%') && (fmt[i+1] == 'm')) + { + memcpy(p, err_str, elen); + p += elen; + i++; + } + else + { + *p++ = fmt[i]; } } + + *p = '\0'; } - *t = '\0'; - prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap); - DEC(); - cnt = p - tbuf; + if (err_str != NULL) free(err_str); - /* Output to stderr if requested. */ - if (LogStat & LOG_PERROR) { - struct iovec iov[2]; + vasprintf(&str, expanded, ap); + if (count > 0) free(expanded); - iov[0].iov_base = stdp; - iov[0].iov_len = cnt - (stdp - tbuf); - iov[1].iov_base = "\n"; - iov[1].iov_len = 1; - (void)writev(STDERR_FILENO, iov, 2); + if (str != NULL) + { + asl_set(msg, ASL_KEY_MSG, str); + + /* Output to stderr if requested. */ + if (_sl_LogStat & LOG_PERROR) + { + p = NULL; + if (_sl_LogStat & LOG_PID) asprintf(&p, "%s[%u]: %s", (_sl_LogTag == NULL) ? "???" : _sl_LogTag, _sl_pid, str); + else asprintf(&p, "%s: %s", (_sl_LogTag == NULL) ? "???" : _sl_LogTag, str); + + if (p != NULL) + { + struct iovec iov[2]; + + iov[0].iov_base = p; + iov[0].iov_len = strlen(p); + iov[1].iov_base = "\n"; + iov[1].iov_len = 1; + writev(STDERR_FILENO, iov, 2); + free(p); + } + } + + free(str); } - /* Get connected, output the message to the local logger. */ - if (!connected) - openlog(LogTag, LogStat | LOG_NDELAY, 0); - if (send(LogFile, tbuf, cnt, 0) >= 0) - return; + /* Set "ASLOption store" if remote control is active */ + if (rc_filter != 0) + { + val = asl_get(msg, ASL_KEY_OPTION); + if (val == NULL) + { + asl_set(msg, ASL_KEY_OPTION, ASL_OPT_STORE); + } + else + { + str = NULL; + asprintf(&str, "%s %s", ASL_OPT_STORE, val); + if (str != NULL) + { + asl_set(msg, ASL_KEY_OPTION, str); + free(str); + str = NULL; + } + } + } + + /* send a mach message to syslogd */ + str = asl_format_message(msg, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, ASL_ENCODE_ASL, &count); + if (str != NULL) + { + outlen = count + 11; + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&out, outlen + 1, TRUE); + if (kstatus == KERN_SUCCESS) + { + memset(out, 0, outlen + 1); + snprintf((char *)out, outlen, "%10u %s", count, str); + + status = 0; + if (asl_server_port == MACH_PORT_NULL) kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); + + if (kstatus == KERN_SUCCESS) kstatus = _asl_server_message(asl_server_port, (caddr_t)out, outlen + 1); + else vm_deallocate(mach_task_self(), (vm_address_t)out, outlen + 1); + + if (kstatus == KERN_SUCCESS) + { + free(str); + asl_free(msg); + return; + } + } + + free(str); + } /* - * Output the message to the console; don't worry about blocking, - * if console blocks everything will. Make sure the error reported - * is the one from the syslogd failure. + * Output the message to the console. */ - if (LogStat & LOG_CONS && - (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) { - struct iovec iov[2]; - - p = strchr(tbuf, '>') + 1; - iov[0].iov_base = p; - iov[0].iov_len = cnt - (p - tbuf); - iov[1].iov_base = "\r\n"; - iov[1].iov_len = 2; - (void)writev(fd, iov, 2); - (void)close(fd); + if (_sl_LogStat & LOG_CONS && (fd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) + { + count = 0; + + p = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &count); + if (p != NULL) + { + struct iovec iov; + + /* count includes trailing nul */ + iov.iov_len = count - 1; + iov.iov_base = p; + writev(fd, &iov, 1); + + free(p); + } + + close(fd); } + + asl_free(msg); } -static struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ +#ifndef BUILDING_VARIANT -void -openlog(ident, logstat, logfac) - const char *ident; - int logstat, logfac; +__private_extern__ void +_syslog_fork_child() { - if (ident != NULL) - LogTag = ident; - LogStat = logstat; - if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) - LogFacility = logfac; - - if (LogFile == -1) { - SyslogAddr.sun_family = AF_UNIX; - (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, - sizeof(SyslogAddr.sun_path)); - if (LogStat & LOG_NDELAY) { - if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) - return; - (void)fcntl(LogFile, F_SETFD, 1); + _sl_RCToken = -1; + _sl_NotifyToken = -1; + _sl_NotifyMaster = -1; + + asl_server_port = MACH_PORT_NULL; + + _sl_pid = getpid(); +} + +__private_extern__ void +_sl_init_notify() +{ + int status; + char *notify_name; + uint32_t euid; + + if (_sl_LogStat & LOG_NO_NOTIFY) + { + _sl_RCToken = -2; + _sl_NotifyMaster = -2; + _sl_NotifyToken = -2; + return; + } + + if (_sl_RCToken == -1) + { + status = notify_register_check(NOTIFY_RC, &_sl_RCToken); + if (status != NOTIFY_STATUS_OK) _sl_RCToken = -2; + } + + if (_sl_NotifyMaster == -1) + { + status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_sl_NotifyMaster); + if (status != NOTIFY_STATUS_OK) _sl_NotifyMaster = -2; + } + + if (_sl_NotifyToken == -1) + { + _sl_NotifyToken = -2; + + euid = geteuid(); + notify_name = NULL; + if (euid == 0) asprintf(¬ify_name, "%s.%d", NOTIFY_PREFIX_SYSTEM, getpid()); + else asprintf(¬ify_name, "user.uid.%d.syslog.%d", euid, getpid()); + + if (notify_name != NULL) + { + status = notify_register_plain(notify_name, &_sl_NotifyToken); + free(notify_name); + if (status != NOTIFY_STATUS_OK) _sl_NotifyToken = -2; } } - if (LogFile != -1 && !connected) - if (connect(LogFile, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)) == -1) { - (void)close(LogFile); - LogFile = -1; - } else - connected = 1; +} + +void +openlog(const char *ident, int logstat, int logfac) +{ + kern_return_t kstatus; + + if (ident != NULL) _sl_LogTag = ident; + + _sl_LogStat = logstat; + + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) _sl_LogFacility = logfac; + + if (asl_server_port == MACH_PORT_NULL) + { + kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); + } + + _sl_pid = getpid(); + _sl_init_notify(); } void closelog() { - (void)close(LogFile); - LogFile = -1; - connected = 0; + if (asl_server_port != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), asl_server_port); + asl_server_port = MACH_PORT_NULL; + + if (_sl_NotifyToken != -1) notify_cancel(_sl_NotifyToken); + _sl_NotifyToken = -1; + + if (_sl_NotifyMaster != -1) notify_cancel(_sl_NotifyMaster); + _sl_NotifyMaster = -1; } /* setlogmask -- set the log mask level */ int -setlogmask(pmask) - int pmask; +setlogmask(int pmask) { int omask; - omask = LogMask; - if (pmask != 0) - LogMask = pmask; + omask = _sl_LogMask; + if (pmask != 0) _sl_LogMask = pmask; return (omask); } + +#endif /* !BUILDING_VARIANT */