]> git.saurik.com Git - apple/syslog.git/blobdiff - syslogd.tproj/daemon.c
syslog-356.200.4.tar.gz
[apple/syslog.git] / syslogd.tproj / daemon.c
index ba83182404981fd262995c66580ce14d3fed4f2a..746cd4249e985b5793030569b702ec3347f8ef85 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,6 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <TargetConditionals.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <pthread.h>
 #include <vproc_priv.h>
 #include <mach/mach.h>
-#include <assert.h>
 #include <libkern/OSAtomic.h>
+#include <libproc.h>
+#include <uuid/uuid.h>
+#include <asl_private.h>
 #include "daemon.h"
 
 #define LIST_SIZE_DELTA 256
+#define STATS_TABLE_SIZE 256
 
-#define streq(A,B) (strcmp(A,B)==0)
 #define forever for(;;)
 
 #define ASL_MSG_TYPE_MASK 0x0000000f
 #define VERIFY_STATUS_INVALID_MESSAGE 1
 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
 
-extern void disaster_message(aslmsg m);
+extern void disaster_message(asl_msg_t *m);
 extern int asl_action_reset(void);
+extern int asl_action_control_set_param(const char *s);
 
 static char myname[MAXHOSTNAMELEN + 1] = {0};
 static int name_change_token = -1;
 
 static OSSpinLock count_lock = 0;
 
-#ifndef CONFIG_IPHONE
+#if !TARGET_OS_EMBEDDED
 static vproc_transaction_t vproc_trans = {0};
 #endif
 
-#define QUOTA_TABLE_SIZE 8192
-#define QUOTA_TABLE_SLOTS 8
+#define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY
 
-#define QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit  -  remaining messages this second discarded ***"
 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***"
-#define QUOTA_EXCEEDED_LEVEL "3"
 
 #define DEFAULT_DB_FILE_MAX 25600000
-#define DEFAULT_DB_MEMORY_MAX 8192
-#define DEFAULT_DB_MINI_MAX 256
+#define DEFAULT_DB_MEMORY_MAX 256
+#define DEFAULT_DB_MEMORY_STR_MAX 1024000
 #define DEFAULT_MPS_LIMIT 500
 #define DEFAULT_REMOTE_DELAY 5000
 #define DEFAULT_BSD_MAX_DUP_SEC 30
 #define DEFAULT_MARK_SEC 0
 #define DEFAULT_UTMP_TTL_SEC 31622400
+#define DEFAULT_STATS_INTERVAL 600
 
-static time_t quota_table_time = 0;
-static pid_t quota_table_pid[QUOTA_TABLE_SIZE];
-static int32_t quota_table_quota[QUOTA_TABLE_SIZE];
+#define ASL_STATS_LEVEL 5
+
+static time_t quota_time = 0;
 static int32_t kern_quota;
 static int32_t kern_level;
 
@@ -107,269 +109,189 @@ static const char *kern_notify_key[] =
        "com.apple.system.log.kernel.debug"
 };
 
-static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 };
+static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
-static char **
-_insertString(char *s, char **l, uint32_t x)
+static stats_table_t *
+stats_table_new()
 {
-       int i, len;
+       stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t));
+       if (t == NULL) return NULL;
 
-       if (s == NULL) return l;
-       if (l == NULL) 
+       t->bucket_count = STATS_TABLE_SIZE;
+       t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *));
+       if (t->bucket == NULL)
        {
-               l = (char **)malloc(2 * sizeof(char *));
-               if (l == NULL) return NULL;
+               free(t);
+               return NULL;
+       }
 
-               l[0] = strdup(s);
-               if (l[0] == NULL)
-               {
-                       free(l);
-                       return NULL;
-               }
+       t->mcount = 0;
+       t->shim_count = 0;
 
-               l[1] = NULL;
-               return l;
-       }
+       return t;
+}
 
-       for (i = 0; l[i] != NULL; i++);
-       len = i + 1; /* count the NULL on the end of the list too! */
+static asl_msg_t *
+stats_table_final(stats_table_t *t)
+{
+       uint32_t i;
+       asl_msg_t *msg;
+       char val[64];
 
-       l = (char **)reallocf(l, (len + 1) * sizeof(char *));
-       if (l == NULL) return NULL;
+       if (t == NULL) return NULL;
 
-       if ((x >= (len - 1)) || (x == IndexNull))
-       {
-               l[len - 1] = strdup(s);
-               if (l[len - 1] == NULL)
+       msg = asl_msg_new(ASL_TYPE_MSG);
+       if (msg == NULL) return NULL;
+
+       asl_msg_set_key_val(msg, ASL_KEY_MSG, "ASL Sender Statistics");
+       asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+       asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "com.apple.asl.statistics");
+       snprintf(val, sizeof(val), "%d", global.pid);
+       asl_msg_set_key_val(msg, ASL_KEY_PID, val);
+       snprintf(val, sizeof(val), "%d", ASL_STATS_LEVEL);
+       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, val);
+       snprintf(val, sizeof(val), "%u", t->mcount);
+       asl_msg_set_key_val(msg, "MsgCount", val);
+       snprintf(val, sizeof(val), "%u", t->shim_count);
+       asl_msg_set_key_val(msg, "ShimCount", val);
+
+       for (i = 0; i < t->bucket_count; i++)
+       {
+               sender_stats_t *s;
+               s = t->bucket[i];
+               while (s != NULL)
                {
-                       free(l);
-                       return NULL;
+                       char val[64], *key = NULL;
+                       sender_stats_t *n = s->next;
+
+                       snprintf(val, sizeof(val), "%llu %llu", s->count, s->size);
+                       asprintf(&key, "*%s", s->sender);
+                       if (key != NULL) asl_msg_set_key_val(msg, key, val);
+                       free(key);
+                       free(s->sender);
+                       free(s);
+                       s = n;
                }
-
-               l[len] = NULL;
-               return l;
        }
 
-       for (i = len; i > x; i--) l[i] = l[i - 1];
-       l[x] = strdup(s);
-       if (l[x] == NULL) return NULL;
+       free(t->bucket);
+       free(t);
 
-       return l;
+       return msg;
 }
 
-char **
-explode(const char *s, const char *delim)
+static void
+stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size)
 {
-       char **l = NULL;
-       const char *p;
-       char *t, quote;
-       int i, n;
+       uint32_t i;
+       sender_stats_t *s;
+       uint8_t *p;
 
-       if (s == NULL) return NULL;
+       if (t == NULL) return;
+       if (sender == NULL) return;
 
-       quote = '\0';
+       /* hash */
+       i = 0;
+       for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p);
+       i %= STATS_TABLE_SIZE;
 
-       p = s;
-       while (p[0] != '\0')
+       for (s = t->bucket[i]; s != NULL; s = s->next)
        {
-               /* scan forward */
-               for (i = 0; p[i] != '\0'; i++)
+               if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0))
                {
-                       if (quote == '\0')
-                       {
-                               /* not inside a quoted string: check for delimiters and quotes */
-                               if (strchr(delim, p[i]) != NULL) break;
-                               else if (p[i] == '\'') quote = p[i];
-                               else if (p[i] == '"') quote = p[i];
-                       }
-                       else
-                       {
-                               /* inside a quoted string - look for matching quote */
-                               if (p[i] == quote) quote = '\0';
-                       }
+                       s->count++;
+                       s->size += msg_size;
+                       return;
                }
-
-               n = i;
-               t = malloc(n + 1);
-               if (t == NULL) return NULL;
-
-               for (i = 0; i < n; i++) t[i] = p[i];
-               t[n] = '\0';
-               l = _insertString(t, l, IndexNull);
-               free(t);
-               t = NULL;
-               if (p[i] == '\0') return l;
-               if (p[i + 1] == '\0') l = _insertString("", l, IndexNull);
-               p = p + i + 1;
        }
 
-       return l;
-}
-
-void
-freeList(char **l)
-{
-       int i;
+       s = (sender_stats_t *)malloc(sizeof(sender_stats_t));
+       s->sender = strdup(sender);
+       if (s->sender == NULL)
+       {
+               free(s);
+               return;
+       }
 
-       if (l == NULL) return;
-       for (i = 0; l[i] != NULL; i++) free(l[i]);
-       free(l);
+       s->count = 1;
+       s->size = msg_size;
+       s->next = t->bucket[i];
+       t->bucket[i] = s;
 }
 
-/*
- * Quotas are maintained using a very fast fixed-size table.
- * We hash into the pid table (quota_table_pid) using the last 10
- * bits of the pid, so the table has 1024 "buckets".  The table is
- * actually just an array with 8 entry slots (for collisions) per bucket.
- * If there are more than 8 pids that hash to the same bucket, we
- * re-use the one with the lowest message usage (highest remaining
- * quota).  This can lead to "generosity: if there are nine or more
- * pids with the same last 10 bits all logging like crazy, we may
- * end up allowing some of them to log more than their quota. 
- * That would be a remarkably rare occurrence.
- */
 static uint32_t
-quota_check(pid_t pid, time_t now, aslmsg msg, uint32_t level)
+kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
 {
-       int i, x, maxx, max;
        char *str, lstr[2];
 
        if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
        if (global.mps_limit == 0) return VERIFY_STATUS_OK;
 
-       if (quota_table_time != now)
+       if (quota_time != now)
        {
-               memset(quota_table_pid, 0, sizeof(quota_table_pid));
                kern_quota = global.mps_limit;
                kern_level = 7;
-               quota_table_time = now;
+               quota_time = now;
        }
 
-       /* kernel gets it's own quota */
-       if (pid == 0)
-       {
-               if (level < kern_level) kern_level = level;
-               if (kern_quota > 0) kern_quota--;
-
-               if (kern_quota > 0) return VERIFY_STATUS_OK;
-               if (kern_quota < 0)     return VERIFY_STATUS_EXCEEDED_QUOTA;
-
-               kern_quota = -1;
-
-               str = NULL;
-               asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit);
-               if (str != NULL)
-               {
-                       asl_set(msg, ASL_KEY_MSG, str);
-                       free(str);
-                       lstr[0] = kern_level + '0';
-                       lstr[1] = 0;
-                       asl_set(msg, ASL_KEY_LEVEL, lstr);
-               }
+       if (level < kern_level) kern_level = level;
+       if (kern_quota > 0) kern_quota--;
 
-               return VERIFY_STATUS_OK;
-       }
+       if (kern_quota > 0) return VERIFY_STATUS_OK;
+       if (kern_quota < 0)     return VERIFY_STATUS_EXCEEDED_QUOTA;
 
-       /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */
-       x = (pid & 0x000003ff) << 3;
-       maxx = x;
-       max = quota_table_quota[x];
+       kern_quota = -1;
 
-       for (i = 0; i < QUOTA_TABLE_SLOTS; i++)
+       str = NULL;
+       asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit);
+       if (str != NULL)
        {
-               if (quota_table_pid[x] == 0)
-               {
-                       quota_table_pid[x] = pid;
-                       quota_table_quota[x] = global.mps_limit;
-
-                       return VERIFY_STATUS_OK;
-               }
-
-               if (quota_table_pid[x] == pid)
-               {
-                       quota_table_quota[x] = quota_table_quota[x] - 1;
-
-                       if (quota_table_quota[x] == 0)
-                       {
-                               quota_table_quota[x] = -1;
-
-                               str = NULL;
-                               asprintf(&str, QUOTA_EXCEEDED_MESSAGE, (int)pid, global.mps_limit);
-                               if (str != NULL)
-                               {
-                                       asl_set(msg, ASL_KEY_MSG, str);
-                                       free(str);
-                                       asl_set(msg, ASL_KEY_LEVEL, QUOTA_EXCEEDED_LEVEL);
-                               }
-
-                               return VERIFY_STATUS_OK;
-                       }
-
-                       if (quota_table_quota[x] < 0)
-                       {
-                               return VERIFY_STATUS_EXCEEDED_QUOTA;
-                       }
-
-                       return VERIFY_STATUS_OK;
-               }
-
-               if (quota_table_quota[x] > max)
-               {
-                       maxx = x;
-                       max = quota_table_quota[x];
-               }
-
-               x += 1;
+               asl_msg_set_key_val(msg, ASL_KEY_MSG, str);
+               free(str);
+               lstr[0] = kern_level + '0';
+               lstr[1] = 0;
+               asl_msg_set_key_val(msg, ASL_KEY_LEVEL, lstr);
        }
 
-       /* can't find the pid and no slots were available - reuse slot with highest remaining quota */
-       asldebug("Quotas: reused slot %d pid %d quota %d for new pid %d\n", maxx, (int)quota_table_pid[maxx], quota_table_quota[maxx], (int)pid);
-       quota_table_pid[maxx] = pid;
-       quota_table_quota[maxx] = global.mps_limit;
-
        return VERIFY_STATUS_OK;
 }
 
-int
-asl_check_option(aslmsg msg, const char *opt)
+static void
+stats_msg(const char *sender, time_t now, asl_msg_t *msg)
 {
-       const char *p;
-       uint32_t len;
-
-       if (msg == NULL) return 0;
-       if (opt == NULL) return 0;
-
-       len = strlen(opt);
-       if (len == 0) return 0;
+       asl_msg_t *x;
+       uint64_t msize = 0;
 
-       p = asl_get(msg, ASL_KEY_OPTION);
-       if (p == NULL) return 0;
-
-       while (*p != '\0')
+       /* flush stats after N seconds */
+       if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL))
        {
-               while ((*p == ' ') || (*p == '\t') || (*p == ',')) p++;
-               if (*p == '\0') return 0;
+               asl_msg_t *msg = stats_table_final(global.stats);
+               process_message(msg, SOURCE_INTERNAL);
+               global.stats = NULL;
+               global.stats_last = now;
+       }
 
-               if (strncasecmp(p, opt, len) == 0)
-               {
-                       p += len;
-                       if ((*p == ' ') || (*p == '\t') || (*p == ',') || (*p == '\0')) return 1;
-               }
+       if (global.stats == NULL) global.stats = stats_table_new();
 
-               while ((*p != ' ') && (*p != '\t') && (*p != ',') && (*p != '\0')) p++;
-       }
+       for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
 
-       return 0;
+       const char *shim_vers = asl_msg_get_val_for_key(msg, "ASLSHIM");
+       global.stats->mcount++;
+       if (shim_vers != NULL) global.stats->shim_count++;
+
+       /* update count and total size - total and for this sender */
+       stats_table_update(global.stats, "*", msize);
+       stats_table_update(global.stats, sender, msize);
 }
 
-const char *
+static const char *
 whatsmyhostname()
 {
        static dispatch_once_t once;
-       char *dot;
        int check, status;
 
+       if (global.hostname != NULL) return global.hostname;
+
        dispatch_once(&once, ^{
                snprintf(myname, sizeof(myname), "%s", "localhost");
                notify_register_check(kNotifySCHostNameChange, &name_change_token);
@@ -388,6 +310,7 @@ whatsmyhostname()
        }
        else
        {
+               char *dot;
                dot = strchr(myname, '.');
                if (dot != NULL) *dot = '\0';
        }
@@ -400,13 +323,10 @@ asl_client_count_increment()
 {
        OSSpinLockLock(&count_lock);
 
-#ifndef CONFIG_IPHONE
+#if !TARGET_OS_EMBEDDED
        if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL);
 #endif
        global.client_count++;
-#ifdef DEBUG
-       asldebug("global.client_count++ (%d)\n", global.client_count);
-#endif
 
        OSSpinLockUnlock(&count_lock);
 }
@@ -417,12 +337,9 @@ asl_client_count_decrement()
        OSSpinLockLock(&count_lock);
 
        if (global.client_count > 0) global.client_count--;
-#ifndef CONFIG_IPHONE
+#if !TARGET_OS_EMBEDDED
        if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans);
 #endif
-#ifdef DEBUG
-       asldebug("global.client_count-- (%d)\n", global.client_count);
-#endif
 
        OSSpinLockUnlock(&count_lock);
 }
@@ -440,145 +357,193 @@ asl_client_count_decrement()
  */
 
 static uint32_t
-aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
+aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
 {
-       const char *val, *fac, *ruval, *rgval;
+       const char *val, *fac, *ruval, *rgval, *sval = NULL;
        char buf[64];
        time_t tick, now;
        uid_t uid;
        gid_t gid;
        uint32_t status, level, fnum;
        pid_t pid;
+       uuid_string_t ustr;
+       struct proc_uniqidentifierinfo pinfo;
 
        if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
 
+       /* Time */
+       now = time(NULL);
+
        if (kern_post_level != NULL) *kern_post_level = -1;
        if (uid_out != NULL) *uid_out = -2;
 
        /* PID */
        pid = 0;
 
-       val = asl_get(msg, ASL_KEY_PID);
-       if (val == NULL) asl_set(msg, ASL_KEY_PID, "0");
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_PID);
+       if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
        else pid = (pid_t)atoi(val);
 
-       /* if PID is 1 (launchd), use the refpid if there is one */
+       /* if PID is 1 (launchd), use the RefPID and RefProc provided */
        if (pid == 1)
        {
-               val = asl_get(msg, ASL_KEY_REF_PID);
+               val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID);
                if (val != NULL) pid = (pid_t)atoi(val);
-       }
 
-       /* Time */
-       now = time(NULL);
+               sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC);
+       }
 
        /* Level */
-       val = asl_get(msg, ASL_KEY_LEVEL);
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL);
        level = ASL_LEVEL_DEBUG;
+       if (source == SOURCE_KERN) level = ASL_LEVEL_NOTICE;
+
        if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
        snprintf(buf, sizeof(buf), "%d", level);
-       asl_set(msg, ASL_KEY_LEVEL, buf);
+       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf);
 
-       /*
-        * check quota if no processes are watching
-        */
-       if (global.watchers_active == 0)
+
+       /* check kernel quota if enabled and no processes are watching */
+       if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0))
        {
-               status = quota_check(pid, now, msg, level);
+               status = kern_quota_check(now, msg, level);
                if (status != VERIFY_STATUS_OK) return status;
        }
 
+       if (pid != 0)
+       {
+               /* set Sender_Mach_UUID */
+               uuid_clear(pinfo.p_uuid);
+               if (proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo))
+               {
+                       uuid_unparse(pinfo.p_uuid, ustr);
+                       asl_msg_set_key_val(msg, ASL_KEY_SENDER_MACH_UUID, ustr);
+               }
+       }
+
        tick = 0;
-       val = asl_get(msg, ASL_KEY_TIME);
-       if (val != NULL) tick = asl_parse_time(val);
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_TIME);
+       if (val != NULL) tick = asl_core_parse_time(val, NULL);
 
        /* Set time to now if it is unset or from the future (not allowed!) */
        if ((tick == 0) || (tick > now)) tick = now;
 
        /* Canonical form: seconds since the epoch */
-       snprintf(buf, sizeof(buf) - 1, "%lu", tick);
-       asl_set(msg, ASL_KEY_TIME, buf);
+       snprintf(buf, sizeof(buf) - 1, "%llu", (unsigned long long) tick);
+       asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
 
-       val = asl_get(msg, ASL_KEY_HOST);
-       if (val == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
+       /* Host */
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_HOST);
+       if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, whatsmyhostname());
 
+       /* UID  & GID */
        uid = -2;
-       val = asl_get(msg, ASL_KEY_UID);
-       if (val != NULL)
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_UID);
+       if (val == NULL)
+       {
+               asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
+       }
+       else
        {
                uid = atoi(val);
-               if ((uid == 0) && strcmp(val, "0")) uid = -2;
-               if (uid_out != NULL) *uid_out = uid;
+               if ((uid == 0) && strcmp(val, "0"))
+               {
+                       uid = -2;
+                       asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
+               }
        }
 
        gid = -2;
-       val = asl_get(msg, ASL_KEY_GID);
-       if (val != NULL)
+       val = asl_msg_get_val_for_key(msg, ASL_KEY_GID);
+       if (val == NULL)
+       {
+               asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
+       }
+       else
        {
                gid = atoi(val);
-               if ((gid == 0) && strcmp(val, "0")) gid = -2;
+               if ((gid == 0) && strcmp(val, "0"))
+               {
+                       gid = -2;
+                       asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
+               }
        }
 
-       /* UID  & GID */
        switch (source)
        {
                case SOURCE_KERN:
                case SOURCE_INTERNAL:
                {
-                       asl_set(msg, ASL_KEY_UID, "0");
-                       asl_set(msg, ASL_KEY_GID, "0");
+                       uid = 0;
+                       asl_msg_set_key_val(msg, ASL_KEY_UID, "0");
+
+                       gid = 0;
+                       asl_msg_set_key_val(msg, ASL_KEY_GID, "0");
+
                        break;
                }
-               case SOURCE_ASL_SOCKET:
                case SOURCE_ASL_MESSAGE:
                case SOURCE_LAUNCHD:
                {
-                       /* we trust the UID & GID in the message */
                        break;
                }
                default:
                {
-                       /* we do not trust the UID 0 or GID 0 or 80 in the message */
-                       if (uid == 0) asl_set(msg, ASL_KEY_UID, "-2");
-                       if ((gid == 0) || (gid == 80)) asl_set(msg, ASL_KEY_GID, "-2");
+                       /* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */
+                       if (uid == 0)
+                       {
+                               uid = -2;
+                               asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
+                       }
+
+                       if ((gid == 0) || (gid == 80))
+                       {
+                               gid = -2;
+                               asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
+                       }
                }
        }
 
+       if (uid_out != NULL) *uid_out = uid;
+
        /* Sender */
-       val = asl_get(msg, ASL_KEY_SENDER);
-       if (val == NULL)
+       if (sval == NULL) sval = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER);
+       if (sval == NULL)
        {
                switch (source)
                {
                        case SOURCE_KERN:
                        {
-                               asl_set(msg, ASL_KEY_SENDER, "kernel");
+                               sval = "kernel";
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                                break;
                        }
                        case SOURCE_INTERNAL:
                        {
-                               asl_set(msg, ASL_KEY_SENDER, "syslogd");
+                               sval = "syslogd";
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                                break;
                        }
                        default:
                        {
-                               asl_set(msg, ASL_KEY_SENDER, "Unknown");
+                               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
                        }
                }
        }
-       else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel")))
+       else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(sval, "kernel")))
        {
                /* allow UID 0 to send messages with "Sender kernel", but nobody else */
-               asl_set(msg, ASL_KEY_SENDER, "Unknown");
+               asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
+               sval = NULL;
        }
 
        /* Facility */
-       fac = asl_get(msg, ASL_KEY_FACILITY);
+       fac = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY);
        if (fac == NULL)
        {
                if (source == SOURCE_KERN) fac = "kern";
                else fac = "user";
-               asl_set(msg, ASL_KEY_FACILITY, fac);
+               asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac);
        }
        else if (fac[0] == '#')
        {
@@ -590,12 +555,12 @@ aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_
                }
 
                fac = asl_syslog_faciliy_num_to_name(fnum);
-               asl_set(msg, ASL_KEY_FACILITY, fac);
+               asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac);
        }
        else if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN))
        {
                /* only UID 0 may use "com.apple.system" */
-               if (uid != 0) asl_set(msg, ASL_KEY_FACILITY, FACILITY_USER);
+               if (uid != 0) asl_msg_set_key_val(msg, ASL_KEY_FACILITY, FACILITY_USER);
        }
 
        /*
@@ -605,32 +570,25 @@ aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_
         */
        if (source == SOURCE_KERN)
        {
-               asl_set(msg, ASL_KEY_READ_UID, "0");
-               asl_set(msg, ASL_KEY_READ_GID, "80");
+               asl_msg_set_key_val(msg, ASL_KEY_READ_UID, "0");
+               asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80");
        }
        else
        {
-               ruval = asl_get(msg, ASL_KEY_READ_UID);
-               rgval = asl_get(msg, ASL_KEY_READ_GID);
+               ruval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_UID);
+               rgval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_GID);
 
                if ((ruval == NULL) && (rgval == NULL))
                {
-                       asl_set(msg, ASL_KEY_READ_GID, "80");
+                       asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80");
                }
        }
 
        /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
        if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
        {
-               snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
-               asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
-       }
-
-       /* Set DB Expire Time for Filesystem errors */
-       if (!strcmp(fac, FSLOG_VAL_FACILITY))
-       {
-               snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC);
-               asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
+               snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl);
+               asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
        }
 
        /*
@@ -642,11 +600,16 @@ aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_
                disaster_message(msg);
        }
 
+       /*
+        * gather sender stats
+        */
+       if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg);
+
        return VERIFY_STATUS_OK;
 }
 
 void
-list_append_msg(asl_search_result_t *list, aslmsg msg)
+list_append_msg(asl_msg_list_t *list, asl_msg_t *msg)
 {
        if (list == NULL) return;
        if (msg == NULL) return;
@@ -683,27 +646,42 @@ list_append_msg(asl_search_result_t *list, aslmsg msg)
 void
 init_globals(void)
 {
+       asl_out_rule_t *r;
+
        OSSpinLockLock(&global.lock);
 
+       global.pid = getpid();
        global.debug = 0;
        free(global.debug_file);
        global.debug_file = NULL;
+       global.launchd_enabled = 1;
 
-#ifdef CONFIG_IPHONE
-       global.dbtype = DB_TYPE_MINI;
+#if TARGET_OS_EMBEDDED
+       global.dbtype = DB_TYPE_MEMORY;
 #else
        global.dbtype = DB_TYPE_FILE;
 #endif
        global.db_file_max = DEFAULT_DB_FILE_MAX;
        global.db_memory_max = DEFAULT_DB_MEMORY_MAX;
-       global.db_mini_max = DEFAULT_DB_MINI_MAX;
+       global.db_memory_str_max = DEFAULT_DB_MEMORY_STR_MAX;
        global.mps_limit = DEFAULT_MPS_LIMIT;
        global.remote_delay_time = DEFAULT_REMOTE_DELAY;
        global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
        global.mark_time = DEFAULT_MARK_SEC;
        global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
+       global.memory_max = DEFAULT_MEMORY_MAX;
+       global.stats_interval = DEFAULT_STATS_INTERVAL;
 
+       global.asl_out_module = asl_out_module_init();
        OSSpinLockUnlock(&global.lock);
+
+       if (global.asl_out_module != NULL)
+       {
+               for (r = global.asl_out_module->ruleset; r != NULL; r = r->next)
+               {
+                       if ((r->action == ACTION_SET_PARAM) && (r->query == NULL) && (!strncmp(r->options, "debug", 5))) control_set_param(r->options, true);
+               }
+       }
 }
 
 /*
@@ -711,7 +689,7 @@ init_globals(void)
  * Line format "= name value"
  */
 int
-control_set_param(const char *s)
+control_set_param(const char *s, bool eval)
 {
        char **l;
        uint32_t intval, count, v32a, v32b, v32c;
@@ -720,7 +698,7 @@ control_set_param(const char *s)
        if (s[0] == '\0') return 0;
 
        /* skip '=' and whitespace */
-       s++;
+       if (*s == '=') s++;
        while ((*s == ' ') || (*s == '\t')) s++;
 
        l = explode(s, " \t");
@@ -731,56 +709,113 @@ control_set_param(const char *s)
        /* name is required */
        if (count == 0)
        {
-               freeList(l);
+               free_string_list(l);
                return -1;
        }
 
+       /* Check variables that allow 0 or 1 / boolean */
+       if (!strcasecmp(l[0], "debug"))
+       {
+               /* = debug [0|1] [file] */
+               if (count == 1)
+               {
+                       intval = (eval) ? 1 : 0;
+                       config_debug(intval, NULL);
+               }
+               else if (!strcmp(l[1], "0"))
+               {
+                       config_debug(0, l[2]);
+               }
+               else if (!strcmp(l[1], "1"))
+               {
+                       config_debug(1, l[2]);
+               }
+               else
+               {
+                       intval = (eval) ? 1 : 0;
+                       config_debug(intval, l[1]);
+               }
+
+               free_string_list(l);
+               return 0;
+       }
+
        /* value is required */
        if (count == 1)
        {
-               freeList(l);
+               free_string_list(l);
                return -1;
        }
 
-       if (!strcasecmp(l[0], "debug"))
+       if (!strcasecmp(l[0], "hostname"))
        {
-               /* = debug {0|1} [file] */
-               intval = atoi(l[1]);
-               config_debug(intval, l[2]);
+               /* = hostname name */
+               OSSpinLockLock(&global.lock);
+               if (eval)
+               {
+                       global.hostname = strdup(l[1]);
+               }
+               else
+               {
+                       free(global.hostname);
+                       global.hostname = NULL;
+               }
+               OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "mark_time"))
        {
                /* = mark_time seconds */
                OSSpinLockLock(&global.lock);
-               global.mark_time = atoll(l[1]);
+               if (eval) global.mark_time = atoll(l[1]);
+               else global.mark_time = 0;
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "dup_delay"))
        {
                /* = bsd_max_dup_time seconds */
                OSSpinLockLock(&global.lock);
-               global.bsd_max_dup_time = atoll(l[1]);
+               if (eval) global.bsd_max_dup_time = atoll(l[1]);
+               else global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "remote_delay"))
        {
                /* = remote_delay microseconds */
                OSSpinLockLock(&global.lock);
-               global.remote_delay_time = atol(l[1]);
+               if (eval) global.remote_delay_time = atol(l[1]);
+               else global.remote_delay_time = DEFAULT_REMOTE_DELAY;
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "utmp_ttl"))
        {
                /* = utmp_ttl seconds */
                OSSpinLockLock(&global.lock);
-               global.utmp_ttl = (time_t)atoll(l[1]);
+               if (eval) global.utmp_ttl = (time_t)atoll(l[1]);
+               else global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "mps_limit"))
        {
                /* = mps_limit number */
                OSSpinLockLock(&global.lock);
-               global.mps_limit = (uint32_t)atol(l[1]);
+               if (eval) global.mps_limit = (uint32_t)atol(l[1]);
+               else global.mps_limit = DEFAULT_MPS_LIMIT;
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "memory_max"))
+       {
+               /* = memory_max number */
+               OSSpinLockLock(&global.lock);
+               if (eval) global.memory_max = (int64_t)atoll(l[1]);
+               else global.memory_max = DEFAULT_MEMORY_MAX;
+               OSSpinLockUnlock(&global.lock);
+       }
+       else if (!strcasecmp(l[0], "stats_interval"))
+       {
+               /* = stats_interval number */
+               OSSpinLockLock(&global.lock);
+               if (eval) global.stats_interval = (time_t)atoll(l[1]);
+               else global.stats_interval = DEFAULT_STATS_INTERVAL;
                OSSpinLockUnlock(&global.lock);
        }
        else if (!strcasecmp(l[0], "max_file_size"))
@@ -792,7 +827,8 @@ control_set_param(const char *s)
                {
                        asl_store_close(global.file_db);
                        global.file_db = NULL;
-                       global.db_file_max = atoi(l[1]);
+                       if (eval) global.db_file_max = atoi(l[1]);
+                       else global.db_file_max = DEFAULT_DB_FILE_MAX;
                }
 
                pthread_mutex_unlock(global.db_lock);
@@ -801,54 +837,60 @@ control_set_param(const char *s)
        {
                /* NB this is private / unpublished */
                /* = db type [max]... */
+               if (eval)
+               {
+                       v32a = 0;
+                       v32b = 0;
+                       v32c = 0;
 
-               v32a = 0;
-               v32b = 0;
-               v32c = 0;
+                       if ((l[1][0] >= '0') && (l[1][0] <= '9'))
+                       {
+                               intval = atoi(l[1]);
+                               if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
+                               if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
+                               if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
+                       }
+                       else if (!strcasecmp(l[1], "file"))
+                       {
+                               intval = DB_TYPE_FILE;
+                               if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
+                       }
+                       else if (!strncasecmp(l[1], "mem", 3))
+                       {
+                               intval = DB_TYPE_MEMORY;
+                               if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
+                       }
+                       else
+                       {
+                               free_string_list(l);
+                               return -1;
+                       }
 
-               if ((l[1][0] >= '0') && (l[1][0] <= '9'))
-               {
-                       intval = atoi(l[1]);
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
-                       if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
-                       if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
-               }
-               else if (!strcasecmp(l[1], "file"))
-               {
-                       intval = DB_TYPE_FILE;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
-               }
-               else if (!strncasecmp(l[1], "mem", 3))
-               {
-                       intval = DB_TYPE_MEMORY;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
-               }
-               else if (!strncasecmp(l[1], "min", 3))
-               {
-                       intval = DB_TYPE_MINI;
-                       if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]);
+                       if (v32a == 0) v32a = global.db_file_max;
+                       if (v32b == 0) v32b = global.db_memory_max;
+                       if (v32c == 0) v32c = global.db_memory_str_max;
+
+                       config_data_store(intval, v32a, v32b, v32c);
                }
                else
                {
-                       freeList(l);
-                       return -1;
+#if TARGET_OS_EMBEDDED
+                       intval = DB_TYPE_MEMORY;
+#else
+                       intval = DB_TYPE_FILE;
+#endif
+                       config_data_store(intval, DEFAULT_DB_FILE_MAX, DEFAULT_DB_MEMORY_MAX, DEFAULT_DB_MEMORY_STR_MAX);
                }
-
-               if (v32a == 0) v32a = global.db_file_max;
-               if (v32b == 0) v32b = global.db_memory_max;
-               if (v32c == 0) v32c = global.db_mini_max;
-
-               config_data_store(intval, v32a, v32b, v32c);
        }
 
-       freeList(l);
+       free_string_list(l);
        return 0;
 }
 
 static int
-control_message(aslmsg msg)
+control_message(asl_msg_t *msg)
 {
-       const char *str = asl_get(msg, ASL_KEY_MSG);
+       const char *str = asl_msg_get_val_for_key(msg, ASL_KEY_MSG);
 
        if (str == NULL) return 0;
 
@@ -857,69 +899,122 @@ control_message(aslmsg msg)
                init_globals();
                return asl_action_reset();
        }
-       else if (!strncmp(str, "= rotate", 8))
+       else if (!strncmp(str, "= crash", 7))
+       {
+               abort();
+       }
+       else if (!strncmp(str, "@ ", 2))
        {
-               const char *p = str + 8;
-               while ((*p == ' ') || (*p == '\t')) p++;
-               if (*p == '\0') p = NULL;
-               return asl_action_file_rotate(p);
+               return asl_action_control_set_param(str);
        }
        else if (!strncmp(str, "= ", 2))
        {
-               return control_set_param(str);
+               return control_set_param(str, true);
        }
 
        return 0;
 }
 
 void
-process_message(aslmsg msg, uint32_t source)
+process_message(asl_msg_t *msg, uint32_t source)
 {
-       int32_t kplevel;
-       uint32_t status;
-       uid_t uid;
+       int64_t msize = 0;
+       static bool wq_draining = false;
+       bool is_control = false;
+       asl_msg_t *x;
 
        if (msg == NULL) return;
 
-       kplevel = -1;
-       uid = -2;
+       is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0;
+
+       if ((!is_control) && wq_draining)
+       {
+               if (global.memory_size >= (global.memory_max / 2))
+               {
+                       asldebug("Work queue draining: dropped message.\n");
+                       asl_msg_release(msg);
+                       return;
+               }
+               else
+               {
+                       asldebug("Work queue re-enabled at 1/2 max.  size %lld  max %lld\n", global.memory_size, global.memory_max);
+                       wq_draining = false;
+               }
+       }
 
-       status = aslmsg_verify(msg, source, &kplevel, &uid);
-       if (status == VERIFY_STATUS_OK)
+       __block vproc_transaction_t vt = vproc_transaction_begin(NULL);
+
+       for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
+
+       if ((global.memory_size + msize) >= global.memory_max)
        {
-               if ((source == SOURCE_KERN) && (kplevel >= 0))
+               char str[256];
+
+               wq_draining = true;
+               asl_msg_release(msg);
+
+               asldebug("Work queue disabled.  msize %lld  size %lld  max %lld\n", msize, global.memory_size + msize, global.memory_max);
+               snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Internal memory size limit %lld exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid, global.memory_max);
+               msg = asl_msg_from_string(str);
+       }
+
+       OSAtomicAdd64(msize, &global.memory_size);
+       OSAtomicIncrement32(&global.work_queue_count);
+
+       dispatch_async(global.work_queue, ^{
+               int32_t kplevel;
+               uint32_t status;
+               uid_t uid;
+
+               kplevel = -1;
+               uid = -2;
+
+               status = aslmsg_verify(msg, source, &kplevel, &uid);
+               if (status == VERIFY_STATUS_OK)
                {
-                       if (kplevel > 7) kplevel = 7;
-                       if (kern_notify_token[kplevel] < 0)
+                       if ((source == SOURCE_KERN) && (kplevel >= 0))
                        {
-                               status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel]));
-                               if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status);
+                               if (kplevel > 7) kplevel = 7;
+                               if (kern_notify_token[kplevel] < 0)
+                               {
+                                       status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel]));
+                                       if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status);
+                               }
+
+                               notify_post(kern_notify_key[kplevel]);
                        }
 
-                       notify_post(kern_notify_key[kplevel]);
-               }
+                       if ((uid == 0) && is_control) control_message(msg);
 
-               if ((uid == 0) && asl_check_option(msg, ASL_OPT_CONTROL)) control_message(msg);
+                       /*
+                        * Send message to output module chain (asl is first).
+                        * The last module in the chain will decrement global.memory_size.
+                        */
+                       asl_out_message(msg, msize);
+               }
+               else
+               {
+                       OSAtomicAdd64(-1ll * msize, &global.memory_size);
+               }
 
-               /* send message to output modules */
-               asl_out_message(msg);
-               if (global.bsd_out_enabled) bsd_out_message(msg);
-       }
+               asl_msg_release(msg);
 
-       asl_free(msg);
+               OSAtomicDecrement32(&global.work_queue_count);
+               vproc_transaction_end(NULL, vt);
+       });
 }
 
 int
 internal_log_message(const char *str)
 {
-       aslmsg msg;
+       asl_msg_t *msg;
 
        if (str == NULL) return 1;
 
-       msg = (aslmsg)asl_msg_from_string(str);
+       msg = asl_msg_from_string(str);
        if (msg == NULL) return 1;
 
-       dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
+       process_message(msg, SOURCE_INTERNAL);
 
        return 0;
 }
@@ -937,6 +1032,9 @@ asldebug(const char *str, ...)
        if (dfp == NULL) return 0;
 
        va_start(v, str);
+       fprintf(dfp, "W %d %llu", global.work_queue_count, global.memory_size);
+       if (global.memory_db != NULL) fprintf(dfp, "   M %u %u %lu", global.memory_db->record_count, global.memory_db->string_count, global.memory_db->curr_string_mem);
+       fprintf(dfp, " ; ");
        vfprintf(dfp, str, v);
        va_end(v);
 
@@ -948,27 +1046,21 @@ asldebug(const char *str, ...)
 void
 asl_mark(void)
 {
-       char *str;
-
-       str = NULL;
-       asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
-                        ASL_KEY_SENDER,
-                        ASL_KEY_LEVEL, ASL_LEVEL_INFO,
-                        ASL_KEY_PID, getpid(),
-                        ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID);
+       char *str = NULL;
 
+       asprintf(&str, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global.pid);
        internal_log_message(str);
-       if (str != NULL) free(str);
+       free(str);
 }
 
-aslmsg 
+asl_msg_t *
 asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
 {
        int pf, pri, index, n;
        char *p, *colon, *brace, *space, *tmp, *tval, *hval, *sval, *pval, *mval;
        char prival[8];
        const char *fval;
-       aslmsg msg;
+       asl_msg_t *msg;
        struct tm time;
        time_t tick;
 
@@ -976,6 +1068,8 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
        if (len <= 0) return NULL;
 
        pri = LOG_DEBUG;
+       if (source == SOURCE_KERN) pri = LOG_NOTICE;
+
        tval = NULL;
        hval = NULL;
        sval = NULL;
@@ -1032,7 +1126,7 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
                memcpy(tmp, p, 15);
                tmp[15] = '\0';
 
-               tick = asl_parse_time(tmp);
+               tick = asl_core_parse_time(tmp, NULL);
                if (tick == (time_t)-1)
                {
                        tval = tmp;
@@ -1051,12 +1145,12 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
        /* stop here for kernel messages */
        if (source == SOURCE_KERN)
        {
-               msg = asl_new(ASL_TYPE_MSG);
+               msg = asl_msg_new(ASL_TYPE_MSG);
                if (msg == NULL) return NULL;
 
-               asl_set(msg, ASL_KEY_MSG, p);
-               asl_set(msg, ASL_KEY_LEVEL, prival);
-               asl_set(msg, ASL_KEY_PID, "0");
+               asl_msg_set_key_val(msg, ASL_KEY_MSG, p);
+               asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival);
+               asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
 
                return msg;
        }
@@ -1134,61 +1228,61 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
 
        if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER);
 
-       msg = asl_new(ASL_TYPE_MSG);
+       msg = asl_msg_new(ASL_TYPE_MSG);
        if (msg == NULL) return NULL;
 
        if (tval != NULL)
        {
-               asl_set(msg, ASL_KEY_TIME, tval);
+               asl_msg_set_key_val(msg, ASL_KEY_TIME, tval);
                free(tval);
        }
 
-       if (fval != NULL) asl_set(msg, "Facility", fval);
-       else asl_set(msg, "Facility", "user");
+       if (fval != NULL) asl_msg_set_key_val(msg, "Facility", fval);
+       else asl_msg_set_key_val(msg, "Facility", "user");
 
        if (sval != NULL)
        {
-               asl_set(msg, ASL_KEY_SENDER, sval);
+               asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
                free(sval);
        }
 
        if (pval != NULL)
        {
-               asl_set(msg, ASL_KEY_PID, pval);
+               asl_msg_set_key_val(msg, ASL_KEY_PID, pval);
                free(pval);
        }
        else
        {
-               asl_set(msg, ASL_KEY_PID, "-1");
+               asl_msg_set_key_val(msg, ASL_KEY_PID, "-1");
        }
 
        if (mval != NULL)
        {
-               asl_set(msg, ASL_KEY_MSG, mval);
+               asl_msg_set_key_val(msg, ASL_KEY_MSG, mval);
                free(mval);
        }
 
-       asl_set(msg, ASL_KEY_LEVEL, prival);
-       asl_set(msg, ASL_KEY_UID, "-2");
-       asl_set(msg, ASL_KEY_GID, "-2");
+       asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival);
+       asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
+       asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
 
        if (hval != NULL)
        {
-               asl_set(msg, ASL_KEY_HOST, hval);
+               asl_msg_set_key_val(msg, ASL_KEY_HOST, hval);
                free(hval);
        }
        else if (rhost != NULL)
        {
-               asl_set(msg, ASL_KEY_HOST, rhost);
+               asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost);
        }
 
        return msg;
 }
 
-aslmsg 
+asl_msg_t *
 asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
 {
-       aslmsg msg;
+       asl_msg_t *msg;
        int status, x, legacy, off;
 
        asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in);
@@ -1218,47 +1312,30 @@ asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
        off = 11;
        if (in[0] == '[') off = 0;
 
-       msg = (aslmsg)asl_msg_from_string(in + off);
+       msg = asl_msg_from_string(in + off);
        if (msg == NULL) return NULL;
 
-       if (rhost != NULL) asl_set(msg, ASL_KEY_HOST, rhost);
+       if (rhost != NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost);
 
        return msg;
 }
 
-char *
-get_line_from_file(FILE *f)
-{
-       char *s, *out;
-       size_t len;
-
-       out = fgetln(f, &len);
-       if (out == NULL) return NULL;
-       if (len == 0) return NULL;
-
-       s = malloc(len + 1);
-       if (s == NULL) return NULL;
-
-       memcpy(s, out, len);
-
-       if (s[len - 1] != '\n') len++;
-       s[len - 1] = '\0';
-       return s;
-}
-
+#if !TARGET_IPHONE_SIMULATOR
 void
 launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, const char *from_name, const char *about_name, const char *session_name, const char *msg)
 {
-       aslmsg m;
+       asl_msg_t *m;
        char str[256];
        time_t now;
 
+       if (global.launchd_enabled == 0) return;
+
 /*
        asldebug("launchd_callback Time %lu %lu PID %u RefPID %u UID %d GID %d PRI %d Sender %s Ref %s Session %s Message %s\n",
        when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
 */
 
-       m = asl_new(ASL_TYPE_MSG);
+       m = asl_msg_new(ASL_TYPE_MSG);
        if (m == NULL) return;
 
        /* Level */
@@ -1266,60 +1343,60 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG;
        snprintf(str, sizeof(str), "%d", priority);
 
-       asl_set(m, ASL_KEY_LEVEL, str);
+       asl_msg_set_key_val(m, ASL_KEY_LEVEL, str);
 
        /* Time */
        if (when != NULL)
        {
-               snprintf(str, sizeof(str), "%lu", when->tv_sec);
-               asl_set(m, ASL_KEY_TIME, str);
+               snprintf(str, sizeof(str), "%llu", (unsigned long long) when->tv_sec);
+               asl_msg_set_key_val(m, ASL_KEY_TIME, str);
 
                snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
-               asl_set(m, ASL_KEY_TIME_NSEC, str);
+               asl_msg_set_key_val(m, ASL_KEY_TIME_NSEC, str);
        }
        else
        {
                now = time(NULL);
-               snprintf(str, sizeof(str), "%lu", now);
-               asl_set(m, ASL_KEY_TIME, str);
+               snprintf(str, sizeof(str), "%llu", (unsigned long long) now);
+               asl_msg_set_key_val(m, ASL_KEY_TIME, str);
        }
 
        /* Facility */
-       asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
+       asl_msg_set_key_val(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
 
        /* UID */
        snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid);
-       asl_set(m, ASL_KEY_UID, str);
+       asl_msg_set_key_val(m, ASL_KEY_UID, str);
 
        /* GID */
        snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid);
-       asl_set(m, ASL_KEY_GID, str);
+       asl_msg_set_key_val(m, ASL_KEY_GID, str);
 
        /* PID */
        if (from_pid != 0)
        {
                snprintf(str, sizeof(str), "%u", (unsigned int)from_pid);
-               asl_set(m, ASL_KEY_PID, str);
+               asl_msg_set_key_val(m, ASL_KEY_PID, str);
        }
 
        /* Reference PID */
        if ((about_pid > 0) && (about_pid != from_pid))
        {
                snprintf(str, sizeof(str), "%u", (unsigned int)about_pid);
-               asl_set(m, ASL_KEY_REF_PID, str);
+               asl_msg_set_key_val(m, ASL_KEY_REF_PID, str);
        }
 
        /* Sender */
        if (from_name != NULL)
        {
-               asl_set(m, ASL_KEY_SENDER, from_name);
+               asl_msg_set_key_val(m, ASL_KEY_SENDER, from_name);
        }
 
        /* ReadUID */
        if (sender_uid != 0)
        {
                snprintf(str, sizeof(str), "%d", (int)sender_uid);
-               asl_set(m, ASL_KEY_READ_UID, str);
+               asl_msg_set_key_val(m, ASL_KEY_READ_UID, str);
        }
 
        /* Reference Process */
@@ -1327,22 +1404,23 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se
        {
                if ((from_name != NULL) && (strcmp(from_name, about_name) != 0))
                {
-                       asl_set(m, ASL_KEY_REF_PROC, about_name);
+                       asl_msg_set_key_val(m, ASL_KEY_REF_PROC, about_name);
                }
        }
 
        /* Session */
        if (session_name != NULL)
        {
-               asl_set(m, ASL_KEY_SESSION, session_name);
+               asl_msg_set_key_val(m, ASL_KEY_SESSION, session_name);
        }
 
        /* Message */
        if (msg != NULL)
        {
-               asl_set(m, ASL_KEY_MSG, msg);
+               asl_msg_set_key_val(m, ASL_KEY_MSG, msg);
        }
 
-       dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_LAUNCHD); });
+       process_message(m, SOURCE_LAUNCHD);
 }
 
+#endif