#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <notify.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <crt_externs.h>
#define LOG_NO_NOTIFY 0x1000
#ifdef BUILDING_VARIANT
__private_extern__ int _sl_LogFile;
__private_extern__ int _sl_connected;
__private_extern__ int _sl_LogStat;
__private_extern__ const char *_sl_LogTag;
__private_extern__ int _sl_LogFacility;
__private_extern__ int _sl_LogMask;
__private_extern__ int _sl_NotifyToken;
__private_extern__ int _sl_NotifyMaster;
#else
__private_extern__ int _sl_LogFile = -1;
__private_extern__ int _sl_connected = 0;
__private_extern__ int _sl_LogStat = 0;
__private_extern__ const char *_sl_LogTag = NULL;
__private_extern__ int _sl_LogFacility = LOG_USER;
__private_extern__ int _sl_LogMask = 0xff;
__private_extern__ int _sl_NotifyToken = -1;
__private_extern__ int _sl_NotifyMaster = -1;
#endif
__private_extern__ void _sl_init_notify();
#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
uint32_t notify_get_state(int token, int *state);
uint32_t notify_register_plain(const char *name, int *out_token);
void
#ifdef __STDC__
syslog(int pri, const char *fmt, ...)
#else
syslog(pri, fmt, va_alist)
int pri;
char *fmt;
va_dcl
#endif
{
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
vsyslog(pri, fmt, ap);
va_end(ap);
}
void
vsyslog(pri, fmt, ap)
int pri;
register const char *fmt;
va_list ap;
{
register int cnt;
register char ch, *p, *t;
time_t now;
int fd, saved_errno, filter, cval, rc_filter, primask;
#define TBUF_LEN 2048
#define FMT_LEN 1024
char *stdp, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
int tbuf_left, fmt_left, prlen;
#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
if (pri & ~(LOG_PRIMASK|LOG_FACMASK))
{
syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri);
pri &= LOG_PRIMASK|LOG_FACMASK;
}
filter = _sl_LogMask;
rc_filter = 0;
_sl_init_notify();
if (_sl_NotifyToken >= 0)
{
if (notify_get_state(_sl_NotifyToken, &cval) == NOTIFY_STATUS_OK)
{
if (cval != 0)
{
filter = cval;
rc_filter = 1;
}
}
}
if ((rc_filter == 0) && (_sl_NotifyMaster >= 0))
{
if (notify_get_state(_sl_NotifyMaster, &cval) == NOTIFY_STATUS_OK)
{
if (cval != 0)
{
filter = cval;
}
}
}
primask = LOG_MASK(LOG_PRI(pri));
if ((primask & filter) == 0) return;
saved_errno = errno;
if ((pri & LOG_FACMASK) == 0) pri |= _sl_LogFacility;
(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 (_sl_LogStat & LOG_PERROR) stdp = p;
if (_sl_LogTag == NULL) _sl_LogTag = *(*_NSGetArgv());
if (_sl_LogTag != NULL)
{
prlen = snprintf(p, tbuf_left, "%s", _sl_LogTag);
DEC();
}
if (_sl_LogStat & LOG_PID)
{
prlen = snprintf(p, tbuf_left, "[%d]", getpid());
DEC();
}
if (_sl_LogTag != NULL)
{
if (tbuf_left > 1)
{
*p++ = ':';
tbuf_left--;
}
if (tbuf_left > 1)
{
*p++ = ' ';
tbuf_left--;
}
}
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--;
}
}
}
*t = '\0';
prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
DEC();
cnt = p - tbuf;
if (_sl_LogStat & LOG_PERROR)
{
struct iovec iov[2];
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 (_sl_connected == 0) openlog(_sl_LogTag, _sl_LogStat | LOG_NDELAY, 0);
if (send(_sl_LogFile, tbuf, cnt, 0) >= 0) return;
if (_sl_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);
}
}
#ifndef BUILDING_VARIANT
static struct sockaddr_un SyslogAddr;
__private_extern__ void
_sl_init_notify()
{
int status;
char *notify_name;
const char *prefix;
if (_sl_LogStat & LOG_NO_NOTIFY)
{
_sl_NotifyMaster = -2;
_sl_NotifyToken = -2;
return;
}
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;
notify_name = NULL;
prefix = NOTIFY_PREFIX_USER;
if (getuid() == 0) prefix = NOTIFY_PREFIX_SYSTEM;
asprintf(¬ify_name, "%s.%d", prefix, getpid());
if (notify_name != NULL)
{
status = notify_register_plain(notify_name, &_sl_NotifyToken);
free(notify_name);
if (status != NOTIFY_STATUS_OK) _sl_NotifyToken = -2;
}
}
}
void
openlog(ident, logstat, logfac)
const char *ident;
int logstat, logfac;
{
if (ident != NULL) _sl_LogTag = ident;
_sl_LogStat = logstat;
if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) _sl_LogFacility = logfac;
if (_sl_LogFile == -1)
{
SyslogAddr.sun_family = AF_UNIX;
(void)strncpy(SyslogAddr.sun_path, _PATH_LOG, sizeof(SyslogAddr.sun_path));
if (_sl_LogStat & LOG_NDELAY)
{
if ((_sl_LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return;
(void)fcntl(_sl_LogFile, F_SETFD, 1);
}
}
if ((_sl_LogFile != -1) && (_sl_connected == 0))
{
if (connect(_sl_LogFile, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)) == -1)
{
(void)close(_sl_LogFile);
_sl_LogFile = -1;
}
else
{
_sl_connected = 1;
}
}
_sl_init_notify();
}
void
closelog()
{
(void)close(_sl_LogFile);
_sl_LogFile = -1;
_sl_connected = 0;
}
int
setlogmask(pmask)
int pmask;
{
int omask;
omask = _sl_LogMask;
if (pmask != 0) _sl_LogMask = pmask;
return (omask);
}
#endif