/*
- * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <dispatch/dispatch.h>
#include <libkern/OSAtomic.h>
#include <os/activity.h>
+#include <os/log.h>
+#include <os/log_private.h>
#include <asl_ipc.h>
#include <asl_client.h>
#include <asl_core.h>
#define FETCH_BATCH 256
-#define LEVEL_MASK 0x0000000f
-#define EVAL_MASK 0x000000f0
-#define EVAL_IGNORE 0x00000000
-#define EVAL_ASLFILE 0x00000010
-#define EVAL_SEND 0x00000020
-#define EVAL_TUNNEL 0x00000040
-#define EVAL_FILE 0x00000080
-#define EVAL_QUOTA 0x00000100
+#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
/*
* Clients get a max of 36000 messages per hour.
#define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
#define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
#define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
-#define QUOTA_LEVEL 2
-#define QUOTA_LEVEL_STR "2"
+#define QUOTA_LEVEL ASL_LEVEL_CRIT
+#define QUOTA_LEVEL_STR ASL_STRING_CRIT
+
+/*
+ * Limit the size of messages sent to syslogd.
+ */
+#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
+
+static const os_log_type_t shim_asl_to_log_type[8] = {
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_EMERG
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ALERT
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_CRIT
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ERR
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_WARNING
+ OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_NOTICE
+ OS_LOG_TYPE_INFO, // ASL_LEVEL_INFO
+ OS_LOG_TYPE_DEBUG // ASL_LEVEL_DEBUG
+};
/* forward */
static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
+static ASL_STATUS _asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring, bool shimmed);
__private_extern__ asl_client_t *_asl_open_default();
/* notify SPI */
/* fork handling in asl_fd.c */
extern void _asl_redirect_fork_child(void);
+#if TARGET_OS_OSX
+extern void _asl_mt_shim_fork_child(void);
+extern void _asl_mt_shim_send_message(asl_msg_t *msg);
+#endif
+
typedef struct
{
int fd;
time_t last_send;
time_t last_oq_msg;
uint32_t quota;
+ dispatch_once_t port_lookup_once;
mach_port_t server_port;
char *sender;
pthread_mutex_t lock;
asl_client_t *asl;
} _asl_global_t;
-__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
+__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
static const char *level_to_number_string[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
_asl_global.last_send = 0;
_asl_global.last_oq_msg = 0;
+ _asl_global.port_lookup_once = 0;
_asl_global.server_port = MACH_PORT_NULL;
pthread_mutex_init(&(_asl_global.lock), NULL);
_asl_redirect_fork_child();
+#if TARGET_OS_OSX
+ _asl_mt_shim_fork_child();
+#endif
}
/*
#endif
static void
-_asl_global_init(int reset)
+_asl_global_init()
{
- _asl_global.server_port = asl_core_get_service_port(reset);
+ dispatch_once(&_asl_global.port_lookup_once, ^{
+ char *str = getenv("ASL_DISABLE");
+ if ((str == NULL) || strcmp(str, "1"))
+ {
+ bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &_asl_global.server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ }
+ });
+}
+
+mach_port_t
+asl_core_get_service_port(__unused int reset)
+{
+ _asl_global_init();
+ return _asl_global.server_port;
}
#pragma mark -
asl_client_t *asl = asl_client_open(ident, facility, opts);
if (asl == NULL) return NULL;
- _asl_global_init(0);
+ _asl_global_init();
if (!(opts & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
return (asl_object_t)asl;
/*
* Evaluate client / message / level to determine what to do with a message.
- * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message
- * can be ignored. Otherwise it returns the bits below, ORed with the level.
+ * Checks filters, tunneling, and log files.
+ * Returns the bits below, ORed with the message level.
*
- * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
- * EVAL_SEND - will send to syslogd
- * EVAL_TUNNEL - will send to syslogd with tunneling enabled
- * EVAL_FILE - will write to file
+ * EVAL_SEND_ASL - send this message to syslogd
+ * EVAL_SEND_TRACE - log this message with Activity Tracing
+ * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file)
+ * EVAL_TEXT_FILE - write this message to a text file / stderr
+ * EVAL_TUNNEL - tunneling enabled when sending to syslogd
*/
uint32_t
_asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
int check;
uint64_t v64;
const char *val;
+ uint32_t eval;
level = ASL_LEVEL_DEBUG;
if (slevel >= 0) level = slevel;
-
+
val = NULL;
if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
-
+
if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
{
/* sending to something other than a client */
- return (level | EVAL_SEND);
+ return EVAL_ACTIVE | EVAL_SEND_ASL | level;
}
asl = (asl_client_t *)client;
+ if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
+
+ if (asl == NULL) asl = _asl_open_default();
if (asl == NULL)
{
- asl = _asl_open_default();
- if (asl == NULL) return EVAL_IGNORE;
+ eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
+ eval &= ~EVAL_SEND_ASL;
+ return eval;
}
- if (asl->aslfile != NULL) return (level | EVAL_ASLFILE);
-
- lmask = ASL_FILTER_MASK(level);
+ eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
filter = asl->filter & 0xff;
tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
+ if (tunnel != 0) eval |= EVAL_TUNNEL;
- if (!(asl->options & ASL_OPT_NO_REMOTE))
+ if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
{
pthread_mutex_lock(&_asl_global.lock);
}
}
- pthread_mutex_unlock(&_asl_global.lock);
- /* master filter overrides local filter */
- if (_asl_global.master_filter != 0)
+ if (_asl_global.master_filter & EVAL_ACTIVE)
{
- filter = _asl_global.master_filter;
- tunnel = 1;
+ /* clear bits and set according to master */
+ eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
+ eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
+ eval |= EVAL_TUNNEL;
+
+ if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
}
- /* process-specific filter overrides local and master */
- if (_asl_global.proc_filter != 0)
+ if (_asl_global.proc_filter & EVAL_ACTIVE)
{
- filter = _asl_global.proc_filter;
- tunnel = 1;
+ /* clear bits and set according to proc */
+ eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
+ eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
+ eval |= EVAL_TUNNEL;
+
+ if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
}
+
+ pthread_mutex_unlock(&_asl_global.lock);
}
- if ((filter != 0) && ((filter & lmask) != 0))
- {
- level |= EVAL_SEND;
- if (tunnel != 0) level |= EVAL_TUNNEL;
- if (asl->out_count > 0) level |= EVAL_FILE;
+ lmask = ASL_FILTER_MASK(level);
+ if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
+ if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
- return level;
+ /* don't send MessageTracer messages to Activity Tracing */
+ val = NULL;
+ if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL))
+ {
+ eval &= ~EVAL_SEND_TRACE;
+ eval |= EVAL_MT_SHIM;
}
- if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0))
+ /* don't send PowerManagement messages to Activity Tracing */
+ val = NULL;
+ if ((asl_msg_lookup(msg, ASL_KEY_POWERMANAGEMENT, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
+
+ /* don't send control messages to Activity Tracing */
+ val = NULL;
+ if ((asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
+
+ /* don't send CFLog messages to Activity Tracing */
+ val = NULL;
+ if ((asl_msg_lookup(msg, ASL_KEY_CFLOG_LOCAL_TIME, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
+
+ val = NULL;
+ if (((asl_msg_lookup(msg, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)) ||
+ ((asl_msg_lookup(asl->kvdict, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)))
{
- return EVAL_IGNORE;
+ /* don't send lastlog/utmp messages to Activity Tracing */
+ if (!strcmp(val, FACILITY_LASTLOG) || !strcmp(val, FACILITY_UTMPX)) eval &= ~EVAL_SEND_TRACE;
+
+ /* don't send LOG_INSTALL messages to Activity Tracing */
+ if (!strcmp(val, asl_syslog_faciliy_num_to_name(LOG_INSTALL))) eval &= ~EVAL_SEND_TRACE;
}
- if (asl->out_count > 0) return (level | EVAL_FILE);
+ return eval;
+}
+
+/*
+ * _asl_lib_vlog_text
+ * Internal routine used by asl_vlog.
+ * msg: an asl messsage
+ * eval: log level and send flags for the message
+ * format: A formating string
+ * ap: va_list for the format
+ * returns 0 for success, non-zero for failure
+ */
- return EVAL_IGNORE;
+__private_extern__ ASL_STATUS
+_asl_lib_vlog_text(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
+{
+ int saved_errno = errno;
+ int status;
+ char *str, *fmt, estr[NL_TEXTMAX];
+ uint32_t i, len, elen, expand;
+
+ if (format == NULL) return ASL_STATUS_INVALID_ARG;
+
+ /* insert strerror for %m */
+ len = 0;
+ elen = 0;
+
+ expand = 0;
+ for (i = 0; format[i] != '\0'; i++)
+ {
+ if (format[i] == '%')
+ {
+ if (format[i+1] == '\0') len++;
+ else if (format[i+1] == 'm')
+ {
+ expand = 1;
+ strerror_r(saved_errno, estr, sizeof(estr));
+ elen = strlen(estr);
+ len += elen;
+ i++;
+ }
+ else
+ {
+ len += 2;
+ i++;
+ }
+ }
+ else len++;
+ }
+
+ fmt = (char *)format;
+
+ if (expand != 0)
+ {
+ fmt = malloc(len + 1);
+ if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
+
+ len = 0;
+
+ for (i = 0; format[i] != '\0'; i++)
+ {
+ if (format[i] == '%')
+ {
+ if (format[i+1] == '\0')
+ {
+ }
+ else if ((format[i+1] == 'm') && (elen != 0))
+ {
+ memcpy(fmt+len, estr, elen);
+ len += elen;
+ i++;
+ }
+ else
+ {
+ fmt[len++] = format[i++];
+ fmt[len++] = format[i];
+ }
+ }
+ else fmt[len++] = format[i];
+ }
+
+ fmt[len] = '\0';
+ }
+
+ str = NULL;
+ vasprintf(&str, fmt, ap);
+ if (expand != 0) free(fmt);
+
+ if (str == NULL) return ASL_STATUS_NO_MEMORY;
+
+ status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, str, true);
+ free(str);
+
+ return status;
}
/*
* ap: va_list for the format
* returns 0 for success, non-zero for failure
*/
-static ASL_STATUS
+__private_extern__ ASL_STATUS
_asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
{
int saved_errno = errno;
if (expand != 0)
{
fmt = malloc(len + 1);
- if (fmt == NULL)
- {
- if (estr != NULL) free(estr);
- return ASL_STATUS_NO_MEMORY;
- }
+ if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
len = 0;
int
asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
{
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(client, msg, level);
- if (eval == EVAL_IGNORE) return 0;
+ void *addr = __builtin_return_address(0);
+
+ if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
+ {
+ va_list ap_copy;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ os_log_type_t type = shim_asl_to_log_type[level];
+
+ va_copy(ap_copy, ap);
+ os_log_with_args(OS_LOG_DEFAULT, type, format, ap_copy, addr);
+ va_end(ap_copy);
+
+ if (eval & EVAL_TEXT_FILE)
+ {
+ status = _asl_lib_vlog_text(client, eval, msg, format, ap);
+ }
+ }
+ else if (eval & EVAL_ASL)
+ {
+ status = _asl_lib_vlog(client, eval, msg, format, ap);
+ }
- ASL_STATUS status = _asl_lib_vlog(client, eval, msg, format, ap);
return (status == ASL_STATUS_OK) ? 0 : -1;
}
/*
* _asl_lib_log
- * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
+ * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
* forwards the call to _asl_lib_vlog.
* msg: an asl message
* eval: log level and send flags for the message
int
_asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
{
- int status;
- if (eval == EVAL_IGNORE) return 0;
+ int status = 0;
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(client, eval, msg, format, ap);
- va_end(ap);
+ if (eval & EVAL_ASL)
+ {
+ va_list ap;
+
+ va_start(ap, format);
+ status = _asl_lib_vlog(client, eval, msg, format, ap);
+ va_end(ap);
+ }
return status;
}
int
asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
{
- ASL_STATUS status;
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(client, msg, level);
- if (eval == EVAL_IGNORE) return 0;
+ void *addr = __builtin_return_address(0);
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(client, eval, msg, format, ap);
- va_end(ap);
+ if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
+ {
+ va_list ap;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ os_log_type_t type = shim_asl_to_log_type[level];
+
+ va_start(ap, format);
+ os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
+ va_end(ap);
+
+ if (eval & EVAL_TEXT_FILE)
+ {
+ va_list ap;
+ va_start(ap, format);
+ status = _asl_lib_vlog_text(client, eval, msg, format, ap);
+ va_end(ap);
+ }
+ }
+ else if (eval & EVAL_ASL)
+ {
+ va_list ap;
+ va_start(ap, format);
+ status = _asl_lib_vlog(client, eval, msg, format, ap);
+ va_end(ap);
+ }
return (status == ASL_STATUS_OK) ? 0 : -1;
}
int
asl_log_message(int level, const char *format, ...)
{
- int status;
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
- if (eval == EVAL_IGNORE) return 0;
+ void *addr = __builtin_return_address(0);
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
- va_end(ap);
+ if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
+ {
+ va_list ap;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ os_log_type_t type = shim_asl_to_log_type[level];
+
+ va_start(ap, format);
+ os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
+ va_end(ap);
+
+ if (eval & EVAL_TEXT_FILE)
+ {
+ va_list ap;
+ va_start(ap, format);
+ status = _asl_lib_vlog_text(NULL, eval, NULL, format, ap);
+ va_end(ap);
+ }
+ }
+ else if (eval & EVAL_ASL)
+ {
+ va_list ap;
+ va_start(ap, format);
+ status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
+ va_end(ap);
+ }
return (status == ASL_STATUS_OK) ? 0 : -1;
}
asl = (asl_client_t *)client;
if (asl == NULL) asl = asl_default;
- if (asl != NULL) l = asl->filter & 0xff;
+ if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
{
return 0;
}
+/* SPI for SHIM control */
+uint32_t
+asl_set_local_control(asl_object_t client, uint32_t filter)
+{
+ asl_client_t *asl = (asl_client_t *)client;
+ if (asl == NULL)
+ {
+ asl = _asl_open_default();
+ if (asl == NULL) return UINT32_MAX;
+ }
+ else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+ return asl_client_set_control(asl, filter);
+}
+
+uint32_t
+asl_get_local_control(asl_object_t client)
+{
+ asl_client_t *asl = (asl_client_t *)client;
+ if (asl == NULL)
+ {
+ asl = _asl_open_default();
+ if (asl == NULL) return UINT32_MAX;
+ }
+ else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+ return asl_client_get_control(asl);
+}
+
/*
- * Sets Host, PID, UID, GID, and OSActivityID values in a new message.
+ * Sets PID and OSActivityID values in a new message.
* Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
*/
asl_msg_t *
asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
{
char aux_val[64];
- char aux_host[_POSIX_HOST_NAME_MAX];
asl_msg_t *aux;
int status;
- unsigned int osacount = 1;
- os_activity_t osaid = 0;
+ os_activity_id_t osaid;
aux = asl_msg_new(ASL_TYPE_MSG);
if (aux == NULL) return NULL;
/* Time and TimeNanoSec */
if (tv != NULL)
{
- snprintf(aux_val, sizeof(aux_val), "%lu", tv->tv_sec);
+ snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
/* Message */
if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
- /* Host */
- memset(&aux_host, 0, _POSIX_HOST_NAME_MAX);
- if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0) asl_msg_set_key_val(aux, ASL_KEY_HOST, aux_host);
-
/* PID */
snprintf(aux_val, sizeof(aux_val), "%u", getpid());
asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
- /* UID */
- snprintf(aux_val, sizeof(aux_val), "%d", getuid());
- asl_msg_set_key_val(aux, ASL_KEY_UID, aux_val);
-
- /* GID */
- snprintf(aux_val, sizeof(aux_val), "%d", getgid());
- asl_msg_set_key_val(aux, ASL_KEY_GID, aux_val);
-
/* OSActivityID */
- if (os_activity_get_active(&osaid, &osacount) == 1)
+ osaid = os_activity_get_identifier(OS_ACTIVITY_CURRENT, NULL);
+ if (osaid)
{
- snprintf(aux_val, sizeof(aux_val), "0x%016llx", (uint64_t)osaid);
+ snprintf(aux_val, sizeof(aux_val), "0x%016llx", osaid);
asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val);
}
/* Sender */
- if (sstr == NULL)
+ if ((sstr == NULL) && (asl != NULL))
{
/* See if the client has a value for ASL_KEY_SENDER */
status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
/* Facility */
- if (fstr == NULL)
+ if ((fstr == NULL) && (asl != NULL))
{
status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
if (status != 0) fstr = NULL;
}
#endif
+static void
+_asl_set_option(asl_msg_t *msg, const char *opt)
+{
+ const char *val = NULL;
+ uint32_t status;
+
+ if (msg == NULL) return;
+ if (opt == NULL) return;
+
+ status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
+ if ((status != 0) || (val == NULL))
+ {
+ asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
+ }
+ else
+ {
+ char *option = NULL;
+ asprintf(&option, "%s %s", opt, val);
+ asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
+ free(option);
+ }
+}
+
+static ASL_STATUS
+_asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr, bool shimmed)
+{
+ int status;
+ uint32_t level, lmask;
+ asl_msg_t *release_sendmsg = NULL;
+
+ if (asl == NULL) {
+ if (obj == NULL) {
+ asl = _asl_open_default();
+ if (asl == NULL) return ASL_STATUS_FAILED;
+ } else {
+ uint32_t objtype = asl_get_type(obj);
+ if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
+ }
+ }
+
+ level = eval & EVAL_LEVEL_MASK;
+ if (level > 7) level = 7;
+ lmask = ASL_FILTER_MASK(level);
+
+ if (sendmsg == NULL) {
+ struct timeval tval = {0, 0};
+ const char *sstr, *fstr;
+
+ status = gettimeofday(&tval, NULL);
+ if (status != 0) {
+ time_t tick = time(NULL);
+ tval.tv_sec = tick;
+ tval.tv_usec = 0;
+ }
+
+ sstr = NULL;
+ status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
+ if (status != 0) {
+ sstr = NULL;
+ }
+
+ fstr = NULL;
+ status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
+ if (status != 0) {
+ fstr = NULL;
+ }
+ sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
+ if (sendmsg == NULL) {
+ return ASL_STATUS_FAILED;
+ }
+
+ release_sendmsg = sendmsg = asl_msg_merge(sendmsg, msg);
+ }
+
+ /* write to file descriptors */
+ for (uint32_t i = 0; i < asl->out_count; i++) {
+ if (shimmed) {
+ if ((asl->out_list[i].fd != STDOUT_FILENO) && (asl->out_list[i].fd != STDERR_FILENO)) {
+ continue; // new logging only support stdout/stderr
+ }
+ }
+
+ if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0)) {
+ char *str;
+
+ uint32_t len = 0;
+ str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
+ if (str == NULL) continue;
+
+ status = write(asl->out_list[i].fd, str, len - 1);
+ if (status < 0)
+ {
+ /* soft error for fd 2 (stderr) */
+ if (asl->out_list[i].fd == 2) status = 0;
+ asl->out_list[i].fd = -1;
+ } else {
+ status = 0;
+ }
+
+ free(str);
+ }
+ }
+ if (release_sendmsg) {
+ asl_msg_release(release_sendmsg);
+ }
+
+ return status;
+}
+
static ASL_STATUS
_asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
{
- uint32_t i, len, level, lmask, outstatus, objtype;
+ uint32_t len, level, lmask, outstatus, objtype;
const char *sstr, *fstr;
struct timeval tval = {0, 0};
int status;
asl_msg_t *qd_msg = NULL;
asl_client_t *asl = NULL;
static dispatch_once_t noquota_once;
+ __block int log_quota_msg = 0;
- if (eval == EVAL_IGNORE) return ASL_STATUS_OK;
+ if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
if (obj == NULL)
{
{
objtype = asl_get_type(obj);
if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
- else asl = _asl_open_default();
}
- level = eval & LEVEL_MASK;
+ level = eval & EVAL_LEVEL_MASK;
if (level > 7) level = 7;
- eval &= EVAL_MASK;
lmask = ASL_FILTER_MASK(level);
if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
if (sendmsg == NULL) return ASL_STATUS_FAILED;
/* Set "ASLOption store" if tunneling */
- if (eval & EVAL_TUNNEL)
- {
- const char *val = NULL;
- status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
- if ((status != 0) || (val == NULL))
- {
- asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, ASL_OPT_STORE);
- }
- else
- {
- char *option = NULL;
- asprintf(&option, "%s %s", ASL_OPT_STORE, val);
- asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, option);
- free(option);
- }
- }
+ if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
outstatus = -1;
return outstatus;
}
- _asl_global_init(0);
+ _asl_global_init();
outstatus = 0;
/*
* - Environment variable ASL_QUOTA_DISABLED == 1
* - /etc/asl/.noquota existed at the time that the process started
*
- * Note that we just check /etc/asl/.noquota once, since it would be
+ * We just check /etc/asl/.noquota once, since it would be
* expensive to stat() for every log message.
+ *
+ * We only check the Environment variable once, since getenv() is
+ * not thread safe. If someone is changing the environment,
+ * this can crash.
*/
-
+
dispatch_once(&noquota_once, ^{
struct stat sb;
memset(&sb, 0, sizeof(struct stat));
- if (stat(NOQUOTA_FILE_PATH, &sb) == 0) _asl_global.quota = UINT32_MAX;
- });
-
- if (_asl_global.quota != UINT32_MAX)
- {
- const char *qtest = getenv(NOQUOTA_ENV);
- if ((qtest != NULL) && (!strcmp(qtest, "1")))
+
+ int save_errno = errno;
+
+ if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
{
_asl_global.quota = UINT32_MAX;
-
- qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
- asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
}
+ else
+ {
+ const char *qtest = getenv(NOQUOTA_ENV);
+ if ((qtest != NULL) && (!strcmp(qtest, "1")))
+ {
+ _asl_global.quota = UINT32_MAX;
+ log_quota_msg = 1;
+ }
+ }
+
+ /* reset errno since we want stat() to fail silently */
+ errno = save_errno;
+ });
+
+ if (log_quota_msg != 0)
+ {
+ qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
+ asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
}
-
+
if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
{
time_t last_send = _asl_global.last_send;
}
else
{
- eval &= ~EVAL_SEND;
+ eval &= ~EVAL_SEND_ASL;
}
}
else
}
}
- if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND))
+#if TARGET_OS_OSX
+ if (eval & EVAL_MT_SHIM)
+ {
+ _asl_mt_shim_send_message(sendmsg);
+ }
+#endif
+
+ if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
{
asl_string_t *send_str;
const char *str;
len = asl_string_length(send_str);
vmsize = asl_string_allocated_size(send_str);
str = asl_string_release_return_bytes(send_str);
- if (len != 0) kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
- if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
+ if (len != 0)
+ {
+ kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
+ if (kstatus != KERN_SUCCESS)
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
+ }
+ }
+ else if (vmsize != 0)
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
+ }
asl_msg_release(qd_msg);
}
-
+
send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
len = asl_string_length(send_str);
+
+ if (len > LIBASL_MAX_MSG_SIZE)
+ {
+ char tmp[256];
+
+ snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
+ asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
+
+ asl_string_release(send_str);
+ len = 0;
+
+ if (limitmsg != NULL)
+ {
+ /* Set "ASLOption store" if tunneling */
+ if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
+
+ send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
+ len = asl_string_length(send_str);
+ asl_msg_release(limitmsg);
+ }
+ }
+
vmsize = asl_string_allocated_size(send_str);
str = asl_string_release_return_bytes(send_str);
kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
if (kstatus != KERN_SUCCESS)
{
- /* retry once if the call failed */
- _asl_global_init(1);
- kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
- if (kstatus != KERN_SUCCESS)
- {
- vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
- outstatus = -1;
- }
+ vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
+ outstatus = -1;
}
}
else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
if ((sendmsg != NULL) && (asl->out_count > 0))
{
- /* write to file descriptors */
- for (i = 0; i < asl->out_count; i++)
- {
- if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0))
- {
- char *str;
-
- len = 0;
- str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
- if (str == NULL) continue;
-
- status = write(asl->out_list[i].fd, str, len - 1);
- if (status < 0)
- {
- /* soft error for fd 2 (stderr) */
- if (asl->out_list[i].fd != 2) outstatus = -1;
- asl->out_list[i].fd = -1;
- }
-
- free(str);
- }
- }
+ status = _asl_send_message_text(asl, sendmsg, obj, eval, msg, mstr, false);
}
asl_msg_release(sendmsg);
return outstatus;
}
+static void
+os_log_with_args_wrapper(void *addr, int level, const char *format, ...)
+{
+ va_list ap;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ os_log_type_t type = shim_asl_to_log_type[level];
+
+ va_start(ap, format);
+ os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
+ va_end(ap);
+}
+
/*
* asl_send: send a message
* This routine may be used instead of asl_log() or asl_vlog() if asl_set()
* returns 0 for success, non-zero for failure
*/
__private_extern__ ASL_STATUS
-asl_client_internal_send(asl_object_t obj, asl_object_t msg)
+asl_client_internal_send(asl_object_t obj, asl_object_t msg, void *addr)
{
int status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(obj, msg, -1);
- if (eval != 0) status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
+
+ const char *message = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_MSG);
+
+ if ((eval & EVAL_SEND_TRACE) && message && message[0] && os_log_shim_enabled(addr))
+ {
+ int level = ASL_LEVEL_DEBUG;
+ const char *lval = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_LEVEL);
+ if (lval != NULL) level = atoi(lval);
+
+ /*
+ * If the return address and the format string are from different
+ * binaries, os_log_with_args will not record the return address.
+ * Work around this by passing a dynamic format string.
+ */
+ char dynamic_format[] = "%s";
+ os_log_with_args_wrapper(addr, level, dynamic_format, message);
+
+ if (eval & EVAL_TEXT_FILE)
+ {
+ status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, NULL, true);
+ }
+ }
+ else if (eval & EVAL_ASL)
+ {
+ status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
+ }
return status;
}
return ASL_STATUS_OK;
}
- _asl_global_init(0);
+ _asl_global_init();
if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED;
send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw");
kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
if (kstatus != KERN_SUCCESS)
{
- /* retry once if the call failed */
- _asl_global_init(1);
- kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
- if (kstatus != KERN_SUCCESS)
- {
- vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
- asl_msg_release(aux);
- return ASL_STATUS_FAILED;
- }
+ vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
+ asl_msg_release(aux);
+ return ASL_STATUS_FAILED;
}
if (status != 0)
asl_msg_t *m = NULL;
static const char ctlstr[] = "1\nQ [= ASLOption control]\n";
- _asl_global_init(0);
+ _asl_global_init();
if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
len = strlen(ctlstr) + 1;
res = NULL;
reslen = 0;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS) return NULL;
memmove(vmstr, ctlstr, len);
status = 0;
kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
- if (kstatus != KERN_SUCCESS)
- {
- /* retry once if the call failed */
- _asl_global_init(1);
- kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
- }
+ if (kstatus != KERN_SUCCESS) return NULL;
list = asl_msg_list_from_string(res);
vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
uint32_t reslen, status;
uint64_t cmax;
- _asl_global_init(0);
+ _asl_global_init();
if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
res = NULL;
status = ASL_STATUS_OK;
kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
- if (kstatus != KERN_SUCCESS)
- {
- /* retry once if the call failed */
- _asl_global_init(1);
- kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
- }
+ if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
/* res should never be returned, but just to be certain we don't leak VM ... */
if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
- if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
return ASL_STORE_LOCATION_FILE;
}
if (opts & ASL_OPT_CREATE_STORE)
{
if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
- return (asl_object_t)fout;
+ return (asl_object_t)sout;
}
else
{