]> git.saurik.com Git - apple/libc.git/blobdiff - gen/asl.c
Libc-594.1.4.tar.gz
[apple/libc.git] / gen / asl.c
index edd1efb6c40c2469b8199923b70d6bca26c451e9..8f1f34df0afadec70a7a15643073a3ca273567b9 100644 (file)
--- a/gen/asl.c
+++ b/gen/asl.c
 #include <pthread.h>
 #include <asl_ipc.h>
 
-#define ASL_SERVICE_NAME "com.apple.system.logger"
-
 #define streq(A, B) (strcmp(A, B) == 0)
 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
 
+#ifndef ASL_QUERY_OP_FALSE
+#define ASL_QUERY_OP_FALSE 0
+#endif
+
 #define forever for(;;)
 
 #define TOKEN_NULL  0
 time_t asl_parse_time(const char *);
 const char *asl_syslog_faciliy_num_to_name(int n);
 __private_extern__ asl_client_t *_asl_open_default();
+__private_extern__ int _asl_send_level_message(aslclient ac, aslmsg msg, int level, const char *message);
 
 /* notify SPI */
 uint32_t notify_register_plain(const char *name, int *out_token);
 
 /* from asl_util.c */
-int _asl_server_socket(int *sock, struct sockaddr_un *server);
 int asl_is_utf8(const char *str);
 uint8_t *asl_b64_encode(const uint8_t *buf, size_t len);
 
+/* fork handling in syslog.c */
+extern void _syslog_fork_child();
+
 /* character encoding lengths */
 static const uint8_t char_encode_len[128] =
 {
@@ -105,32 +110,51 @@ static const char *cvis_7_13 = "abtnvfr";
 typedef struct
 {
        int notify_count;
+       int rc_change_token;
        int notify_token;
        int master_token;
+       uint64_t proc_filter;
+       uint64_t master_filter;
+       int port_count;
+       mach_port_t server_port;
        char *sender;
        pthread_mutex_t lock;
+       pthread_mutex_t port_lock;
        asl_client_t *asl;
 } _asl_global_t;
 
 #ifndef BUILDING_VARIANT
-__private_extern__ _asl_global_t _asl_global = {0, -1, -1, NULL, PTHREAD_MUTEX_INITIALIZER, NULL};
+__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL};
 
-static mach_port_t asl_server_port = MACH_PORT_NULL;
+#define ASL_SERVICE_NAME "com.apple.system.logger"
 
-static int
-_asl_connect(asl_client_t *asl)
+/*
+ * Called from the child process inside fork() to clean up
+ * inherited state from the parent process.
+ *
+ * NB. A lock isn't required, since we're single threaded in this call.
+ */
+__private_extern__ void
+_asl_fork_child()
 {
-       if (asl->sock >= 0) return 0;
+       _asl_global.notify_count = 0;
+       _asl_global.rc_change_token = -1;
+       _asl_global.master_token = -1;
+       _asl_global.notify_token = -1;
 
-       return _asl_server_socket(&asl->sock, &asl->server);
+       _asl_global.port_count = 0;
+       _asl_global.server_port = MACH_PORT_NULL;
+
+       /* clean up in syslog.c */
+       _syslog_fork_child();
 }
 
 static int
 _asl_notify_open(int do_lock)
 {
        char *notify_name;
-       const char *prefix;
        uint32_t status;
+       uint32_t euid;
 
        if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
 
@@ -142,10 +166,11 @@ _asl_notify_open(int do_lock)
                return 0;
        }
 
-       notify_name = NULL;
-
-       prefix = NOTIFY_PREFIX_USER;
-       if (getuid() == 0) prefix = NOTIFY_PREFIX_SYSTEM;
+       if (_asl_global.rc_change_token == -1)
+       {
+               status = notify_register_check(NOTIFY_RC, &_asl_global.rc_change_token);
+               if (status != NOTIFY_STATUS_OK) _asl_global.rc_change_token = -1;
+       }
 
        if (_asl_global.master_token == -1)
        {
@@ -153,7 +178,10 @@ _asl_notify_open(int do_lock)
                if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
        }
 
-       asprintf(&notify_name, "%s.%d", prefix, getpid());
+       euid = geteuid();
+       notify_name = NULL;
+       if (euid == 0) asprintf(&notify_name, "%s.%d", NOTIFY_PREFIX_SYSTEM, getpid());
+       else asprintf(&notify_name, "user.uid.%d.syslog.%d", euid, getpid());
 
        if (notify_name != NULL)
        {
@@ -181,6 +209,9 @@ _asl_notify_close()
                return;
        }
 
+       if (_asl_global.rc_change_token > 0) notify_cancel(_asl_global.rc_change_token);
+       _asl_global.rc_change_token = -1;
+
        if (_asl_global.master_token > 0) notify_cancel(_asl_global.master_token);
        _asl_global.master_token = -1;
 
@@ -195,6 +226,7 @@ asl_open(const char *ident, const char *facility, uint32_t opts)
 {
        char *name, *x;
        asl_client_t *asl;
+       kern_return_t kstatus;
 
        asl = (asl_client_t *)calloc(1, sizeof(asl_client_t));
        if (asl == NULL)
@@ -207,15 +239,23 @@ asl_open(const char *ident, const char *facility, uint32_t opts)
 
        asl->sock = -1;
 
-       if (asl->options & ASL_OPT_NO_DELAY)
+       pthread_mutex_lock(&(_asl_global.port_lock));
+
+       if (_asl_global.server_port == MACH_PORT_NULL) 
        {
-               if (_asl_connect(asl) < 0)
-               {
-                       free(asl);
-                       return NULL;
-               }
+               _asl_global.port_count = 0;
+
+               kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &_asl_global.server_port);
+               if (kstatus == KERN_SUCCESS) _asl_global.port_count = 1;
+               else _asl_global.server_port = MACH_PORT_NULL;
+       }
+       else
+       {
+               _asl_global.port_count++;
        }
 
+       pthread_mutex_unlock(&(_asl_global.port_lock));
+
        asl->pid = getpid();
        asl->uid = getuid();
        asl->gid = getgid();
@@ -227,7 +267,7 @@ asl_open(const char *ident, const char *facility, uint32_t opts)
                asl->name = strdup(ident);
                if (asl->name == NULL)
                {
-                       close(asl->sock);
+                       if (asl->sock >= 0) close(asl->sock);
                        free(asl);
                        return NULL;
                }
@@ -243,7 +283,7 @@ asl_open(const char *ident, const char *facility, uint32_t opts)
                        asl->name = strdup(x);
                        if (asl->name == NULL)
                        {
-                               close(asl->sock);
+                               if (asl->sock >= 0) close(asl->sock);
                                free(asl);
                                return NULL;
                        }
@@ -255,7 +295,7 @@ asl_open(const char *ident, const char *facility, uint32_t opts)
        else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER));
        if (asl->facility == NULL)
        {
-               close(asl->sock);
+               if (asl->sock >= 0) close(asl->sock);
                free(asl);
                return NULL;
        }
@@ -277,6 +317,18 @@ asl_close(aslclient ac)
        if (asl == NULL) return;
 
        if (asl->sock >= 0) close(asl->sock);
+
+       pthread_mutex_lock(&(_asl_global.port_lock));
+
+       if (_asl_global.port_count > 0) _asl_global.port_count--;
+       if (_asl_global.port_count == 0)
+       {
+               mach_port_deallocate(mach_task_self(), _asl_global.server_port);
+               _asl_global.server_port = MACH_PORT_NULL;
+       }
+
+       pthread_mutex_unlock(&(_asl_global.port_lock));
+
        if (asl->name != NULL) free(asl->name);
        if (asl->facility != NULL) free(asl->facility);
        if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_close();
@@ -303,6 +355,8 @@ asl_close(aslclient ac)
 __private_extern__ asl_client_t *
 _asl_open_default()
 {
+       if (_asl_global.asl != NULL) return _asl_global.asl;
+
        pthread_mutex_lock(&_asl_global.lock);
        if (_asl_global.asl != NULL)
        {
@@ -1503,7 +1557,7 @@ _asl_isanumber(char *s)
 }
 
 static int
-_asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
+_asl_msg_basic_test(uint32_t op, char *q, char *m, uint32_t n)
 {
        int cmp;
        uint32_t t;
@@ -1512,23 +1566,33 @@ _asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
 
        t = op & ASL_QUERY_OP_TRUE;
 
+       /* NULL value from query or message string fails */
+       if ((q == NULL) || (m == NULL)) return (t & ASL_QUERY_OP_NOT_EQUAL);
+
        if (op & ASL_QUERY_OP_REGEX)
        {
+               /* greater than or less than make no sense in substring search */
+               if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0;
+
                memset(&rex, 0, sizeof(regex_t));
 
                rflags = REG_EXTENDED | REG_NOSUB;
                if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE;
 
-               if (regcomp(&rex, q, rflags) != 0) return 0;
+               /* A bad reqular expression matches nothing */
+               if (regcomp(&rex, q, rflags) != 0) return (t & ASL_QUERY_OP_NOT_EQUAL);
+
                cmp = regexec(&rex, m, 0, NULL, 0);
                regfree(&rex);
+
+               if (t == ASL_QUERY_OP_NOT_EQUAL) return (cmp != 0);
                return (cmp == 0);
        }
 
        if (op & ASL_QUERY_OP_NUMERIC)
        {
-               /* We assume the query contains a numeric string */
-               if (_asl_isanumber(m) == 0) return 0;
+               if (_asl_isanumber(q) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL);
+               if (_asl_isanumber(m) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL);
 
                nq = atoi(q);
                nm = atoi(m);
@@ -1541,7 +1605,7 @@ _asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
                        case ASL_QUERY_OP_LESS: return (nm < nq);
                        case ASL_QUERY_OP_LESS_EQUAL: return (nm <= nq);
                        case ASL_QUERY_OP_NOT_EQUAL: return (nm != nq);
-                       default: return 0;
+                       default: return (t == ASL_QUERY_OP_NOT_EQUAL);
                }
        }
 
@@ -1565,60 +1629,112 @@ _asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
                case ASL_QUERY_OP_LESS: return (cmp < 0);
                case ASL_QUERY_OP_LESS_EQUAL: return (cmp <= 0);
                case ASL_QUERY_OP_NOT_EQUAL: return (cmp != 0);
-               default: return 0;
        }
 
-       return 0;
+       return (t == ASL_QUERY_OP_NOT_EQUAL);
 }
 
 static int
-_asl_msg_test_op_substr(uint32_t op, char *q, char *m)
+_asl_msg_test_substring(uint32_t op, char *q, char *m)
 {
-       uint32_t i, d, lm, lq;
+       uint32_t t, i, d, lm, lq, match, newop;
+
+       t = op & ASL_QUERY_OP_TRUE;
+
+       lm = 0;
+       if (m != NULL) lm = strlen(m);
 
-       lm = strlen(m);
-       lq = strlen(q);
+       lq = 0;
+       if (q != NULL) lq = strlen(q);
 
-       if (lq > lm) return 0;
+       /* NULL is a substring of any string */
+       if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
+
+       /* A long string is defined to be not equal to a short string */
+       if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
+
+       /* greater than or less than make no sense in substring search */
+       if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0;
+
+       /*
+        * We scan the string doing an equality test.
+        * If the input test is equality, we stop as soon as we hit a match.
+        * Otherwise we keep scanning the whole message string.
+        */
+       newop = op & 0xff0;
+       newop |= ASL_QUERY_OP_EQUAL;
 
+       match = 0;
        d = lm - lq;
        for (i = 0; i <= d; i++)
        {
-               if (_asl_msg_op_test(op, q, m + i, lq) != 0) return 1;
+               if (_asl_msg_basic_test(newop, q, m + i, lq) != 0)
+               {
+                       if (t & ASL_QUERY_OP_EQUAL) return 1;
+                       match++;
+               }
        }
 
-       return 0;
+       /* If the input test was for equality, no matches were found */
+       if (t & ASL_QUERY_OP_EQUAL) return 0;
+
+       /* The input test was for not equal.  Return true if no matches were found */
+       return (match == 0);
 }
 
 static int
-_asl_msg_test_op_prefix(uint32_t op, char *q, char *m)
+_asl_msg_test_prefix(uint32_t op, char *q, char *m)
 {
-       uint32_t lm, lq;
+       uint32_t lm, lq, t;
+
+       t = op & ASL_QUERY_OP_TRUE;
+
+       lm = 0;
+       if (m != NULL) lm = strlen(m);
 
-       lm = strlen(m);
-       lq = strlen(q);
+       lq = 0;
+       if (q != NULL) lq = strlen(q);
 
-       if (lq > lm) return 0;
+       /* NULL is a prefix of any string */
+       if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
 
-       return _asl_msg_op_test(op, q, m, lq);
+       /* A long string is defined to be not equal to a short string */
+       if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
+
+       /* Compare two equal-length strings */
+       return _asl_msg_basic_test(op, q, m, lq);
 }
 
 static int
-_asl_msg_test_op_suffix(uint32_t op, char *q, char *m)
+_asl_msg_test_suffix(uint32_t op, char *q, char *m)
 {
-       uint32_t lm, lq, d;
+       uint32_t lm, lq, d, t;
+
+       t = op & ASL_QUERY_OP_TRUE;
+
+       lm = 0;
+       if (m != NULL) lm = strlen(m);
 
-       lm = strlen(m);
-       lq = strlen(q);
+       lq = 0;
+       if (q != NULL) lq = strlen(q);
 
-       if (lq > lm) return 0;
+       /* NULL is a suffix of any string */
+       if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
 
+       /* A long string is defined to be not equal to a short string */
+       if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
+
+       /* Compare two equal-length strings */
        d = lm - lq;
-       return _asl_msg_op_test(op, q, m + d, lq);
+       return _asl_msg_basic_test(op, q, m + d, lq);
 }
 
+/* 
+ * Splits out prefix, suffix, and substring tests.
+ * Sends the rest to _asl_msg_basic_test().
+ */
 static int
-_asl_msg_test_op(uint32_t op, char *q, char *m)
+_asl_msg_test_expression(uint32_t op, char *q, char *m)
 {
        uint32_t t;
 
@@ -1627,116 +1743,132 @@ _asl_msg_test_op(uint32_t op, char *q, char *m)
 
        if (op & ASL_QUERY_OP_PREFIX)
        {
-               if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_substr(op, q, m);
-               return _asl_msg_test_op_prefix(op, q, m);
+               if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_substring(op, q, m);
+               return _asl_msg_test_prefix(op, q, m);
        }
-       if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_suffix(op, q, m);
+       if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_suffix(op, q, m);
 
-       return _asl_msg_op_test(op, q, m, 0);
+       return _asl_msg_basic_test(op, q, m, 0);
 }
 
+/*
+ * Special case for comparing time values.
+ * If both inputs are time strings, this compares the time
+ * value in seconds.  Otherwise it just does normal matching.
+ */
 static int
-_asl_msg_test_time_op(uint32_t op, char *q, char *m)
+_asl_msg_test_time_expression(uint32_t op, char *q, char *m)
 {
        time_t tq, tm;
-       char *vq, *vm;
-       struct tm gtime;
-       uint32_t t, do_numeric;
-       int cmp;
-
-       do_numeric = 1;
+       uint32_t t;
 
-       if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX) || (op & ASL_QUERY_OP_CASEFOLD)) do_numeric = 0;
+       if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX)) return _asl_msg_test_expression(op, q, m);
+       if ((q == NULL) || (m == NULL)) return _asl_msg_test_expression(op, q, m);
 
        tq = asl_parse_time(q);
-       if (tq < 0) return _asl_msg_test_op(op, q, m);
+       if (tq < 0) return _asl_msg_test_expression(op, q, m);
 
        tm = asl_parse_time(m);
-       if (tm < 0) return _asl_msg_test_op(op, q, m);
+       if (tm < 0) return _asl_msg_test_expression(op, q, m);
+
+       t = op & ASL_QUERY_OP_TRUE;
 
-       if (do_numeric == 1)
+       switch (t)
        {
-               t = op & ASL_QUERY_OP_TRUE;
-               switch (t)
+               case ASL_QUERY_OP_FALSE:
+               {
+                       return 0;
+               }
+               case ASL_QUERY_OP_EQUAL:
                {
-                       case ASL_QUERY_OP_EQUAL:
-                               if (tm == tq) return 1;
-                               return 0;
-                       case ASL_QUERY_OP_GREATER:
-                               if (tm > tq) return 1;
-                               return 0;
-                       case ASL_QUERY_OP_GREATER_EQUAL:
-                               if (tm >= tq) return 1;
-                               return 0;
-                       case ASL_QUERY_OP_LESS:
-                               if (tm < tq) return 1;
-                               return 0;
-                       case ASL_QUERY_OP_LESS_EQUAL:
-                               if (tm <= tq) return 1;
-                               return 0;
-                       case ASL_QUERY_OP_NOT_EQUAL:
-                               if (tm != tq) return 1;
-                               return 0;
-                       default:
-                               return 0;
+                       if (tm == tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_GREATER:
+               {
+                       if (tm > tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_GREATER_EQUAL:
+               {
+                       if (tm >= tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_LESS:
+               {
+                       if (tm < tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_LESS_EQUAL:
+               {
+                       if (tm <= tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_NOT_EQUAL:
+               {
+                       if (tm != tq) return 1;
+                       return 0;
+               }
+               case ASL_QUERY_OP_TRUE:
+               {
+                       return 1;
                }
-
-               return 0;
        }
 
-       memset(&gtime, 0, sizeof(struct tm));
-       gmtime_r(&tq, &gtime);
-
-       /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
-       vq = NULL;
-       asprintf(&vq, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
-       if (vq == NULL) return 0;
-
-       memset(&gtime, 0, sizeof(struct tm));
-       gmtime_r(&tm, &gtime);
-
-       /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
-       vm = NULL;
-       asprintf(&vm, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
-       if (vm == NULL) return 0;
-
-       cmp = _asl_msg_test_op(op, q, m);
-
-       free(vq);
-       free(vm);
-
-       return cmp;
+       /* NOTREACHED */
+       return 0;
 }
 
+/* test a query against a message */
 static int
 _asl_msg_test(asl_msg_t *q, asl_msg_t *m)
 {
-       uint32_t i, j;
+       uint32_t i, j, t;
        int cmp;
-       char *val;
 
+       /*
+        * Check each simple expression (key op val) separately.
+        * The query suceeds (returns 1) if all simple expressions
+        * succeed (i.e. AND the simple expressions).
+        */
        for (i = 0; i < q->count; i++)
        {
+               /* Find query key[i] in the message */
                j = _asl_msg_index(m, q->key[i]);
-               if (j == (uint32_t)-1) return 0;
 
-               if (q->val[i] == NULL) continue;
+               /* NULL op is meaningless, but we allow it to succeed */
                if (q->op == NULL) continue;
 
-               if ((q->op[i] & ASL_QUERY_OP_TRUE) == ASL_QUERY_OP_TRUE) continue;
+               /* ASL_QUERY_OP_TRUE tests if key[i] is present in the message */
+               t = q->op[i] & ASL_QUERY_OP_TRUE;
+               if (t == ASL_QUERY_OP_TRUE)
+               {
+                       if (j == (uint32_t)-1) return 0;
+                       continue;
+               }
 
-               if (m->val[j] == NULL) return 0;
+               /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
+               if (t == ASL_QUERY_OP_FALSE)
+               {
+                       if (j != (uint32_t)-1) return 0;
+                       continue;
+               }
 
-               val = q->val[i];
+               if (j == (uint32_t)-1)
+               {
+                       /* the message does NOT have query key[i] - fail unless we are testing not equal */
+                       if (t == ASL_QUERY_OP_NOT_EQUAL) continue;
+                       return 0;
+               }
 
                cmp = 1;
                if (streq(q->key[i], ASL_KEY_TIME))
                {
-                       cmp = _asl_msg_test_time_op(q->op[i], q->val[i], m->val[j]);
+                       cmp = _asl_msg_test_time_expression(q->op[i], q->val[i], m->val[j]);
                }
                else
                {
-                       cmp = _asl_msg_test_op(q->op[i], val, m->val[j]);
+                       cmp = _asl_msg_test_expression(q->op[i], q->val[i], m->val[j]);
                }
 
                if (cmp == 0) return 0;
@@ -2181,17 +2313,6 @@ asl_vlog(aslclient ac, aslmsg a, 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;
 
-       str = NULL;
-       asprintf(&str, "%d", level);
-       if (str == NULL)
-       {
-               if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
-               return -1;
-       }
-
-       asl_set(msg, ASL_KEY_LEVEL, str);
-       free(str);
-
        /* insert strerror for %m */
        len = 0;
        elen = 0;
@@ -2278,11 +2399,9 @@ asl_vlog(aslclient ac, aslmsg a, int level, const char *format, va_list ap)
                return -1;
        }
 
-       asl_set(msg, ASL_KEY_MSG, str);
+       status = _asl_send_level_message(ac, (aslmsg)msg, level, str);
        free(str);
 
-       status = asl_send(ac, (aslmsg)msg);
-
        if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
        return status;
 }
@@ -2594,17 +2713,17 @@ asl_format_message(aslmsg msg, const char *mfmt, const char *tfmt, uint32_t text
 }
 
 /*
- * asl_send: send a message 
+ * asl_send (internal version): send a message 
  * This routine may be used instead of asl_log() or asl_vlog() if asl_set() 
  * has been used to set all of a message's attributes.
- * msg:  an aslmsg
  * returns 0 for success, non-zero for failure
  */
-int
-asl_send(aslclient ac, aslmsg msg)
+__private_extern__ int
+_asl_send_level_message(aslclient ac, aslmsg msg, int level, const char *message)
 {
-       char *str, *out_raw, *out;
-       uint32_t i, len, level, lmask, outstatus, filter, senderx, facilityx;
+       char *str, *out_raw;
+       caddr_t out;
+       uint32_t i, len, outlen, lmask, outstatus, filter, check, senderx, facilityx;
        uint64_t v64;
        const char *val;
        char *name, *x;
@@ -2613,8 +2732,9 @@ asl_send(aslclient ac, aslmsg msg)
        int status, rc_filter;
        asl_client_t *asl;
        int use_global_lock;
-       asl_msg_t *mt;
+       asl_msg_t *mt, *tmp_msg;
        char hname[_POSIX_HOST_NAME_MAX];
+       kern_return_t kstatus;
 
        use_global_lock = 0;
        asl = (asl_client_t *)ac;
@@ -2627,46 +2747,78 @@ asl_send(aslclient ac, aslmsg msg)
 
        if (msg == NULL) return 0;
 
-       level = ASL_LEVEL_DEBUG;
-
        val = asl_get(msg, ASL_KEY_LEVEL);
        if (val != NULL) level = atoi(val);
 
        lmask = ASL_FILTER_MASK(level);
 
-       filter = asl->filter;
-       rc_filter = 0;
-
        if (!(asl->options & ASL_OPT_NO_REMOTE))
        {
                pthread_mutex_lock(&_asl_global.lock);
 
-               if (_asl_global.notify_token >= 0)
+               if (_asl_global.rc_change_token >= 0)
                {
-                       v64 = 0;
-
-                       status = notify_get_state(_asl_global.notify_token, &v64);
-                       if ((status == NOTIFY_STATUS_OK) && (v64 != 0))
+                       /* initialize or re-check process-specific and master filters  */
+                       check = 0;
+                       status = notify_check(_asl_global.rc_change_token, &check);
+                       if ((status == NOTIFY_STATUS_OK) && (check != 0))
                        {
-                               filter = v64;
-                               rc_filter = 1;
-                       }
-               }
-
-               if ((rc_filter == 0) && (_asl_global.master_token >= 0))
-               {
-                       v64 = 0;
+                               if (_asl_global.master_token >= 0)
+                               {
+                                       v64 = 0;
+                                       status = notify_get_state(_asl_global.master_token, &v64);
+                                       if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
+                               }
 
-                       status = notify_get_state(_asl_global.master_token, &v64);
-                       if ((status == NOTIFY_STATUS_OK) && (v64 != 0))
-                       {
-                               filter = v64;
+                               if (_asl_global.notify_token >= 0)
+                               {
+                                       v64 = 0;
+                                       status = notify_get_state(_asl_global.notify_token, &v64);
+                                       if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
+                               }
                        }
                }
 
                pthread_mutex_unlock(&_asl_global.lock);
        }
 
+       filter = asl->filter;
+       rc_filter = 0;
+
+       /* master filter overrides local filter */
+       if (_asl_global.master_filter != 0)
+       {
+               filter = _asl_global.master_filter;
+               rc_filter = 1;
+       }
+
+       /* process-specific filter overrides local and master */
+       if (_asl_global.proc_filter != 0)
+       {
+               filter = _asl_global.proc_filter;
+               rc_filter = 1;
+       }
+
+       /*
+        * Copy the message to tmp_msg to make setting values thread-safe
+        */
+       tmp_msg = calloc(1, sizeof(asl_msg_t));
+       if (tmp_msg == NULL) return -1;
+
+       tmp_msg->type = ASL_TYPE_MSG;
+
+       mt = (asl_msg_t *)msg;
+       for (i = 0; i < mt->count; i++)
+       {
+               asl_set(tmp_msg, mt->key[i], mt->val[i]);
+       }
+
+       /*
+        * Set Level and Message from parameters.
+        */
+       if (message != NULL) asl_set(tmp_msg, ASL_KEY_MSG, message);
+       asl_set(tmp_msg, ASL_KEY_LEVEL, _asl_level_string(level));
+
        /* 
         * Time, TimeNanoSec, Host, PID, UID, and GID values get set here
         */
@@ -2679,7 +2831,7 @@ asl_send(aslclient ac, aslmsg msg)
                asprintf(&str, "%lu", tval.tv_sec);
                if (str != NULL)
                {
-                       asl_set(msg, ASL_KEY_TIME, str);
+                       asl_set(tmp_msg, ASL_KEY_TIME, str);
                        free(str);
                        str = NULL;
                }
@@ -2687,7 +2839,7 @@ asl_send(aslclient ac, aslmsg msg)
                asprintf(&str, "%lu", tval.tv_usec * 1000);
                if (str != NULL)
                {
-                       asl_set(msg, ASL_KEY_TIME_NSEC, str);
+                       asl_set(tmp_msg, ASL_KEY_TIME_NSEC, str);
                        free(str);
                        str = NULL;
                }
@@ -2698,7 +2850,7 @@ asl_send(aslclient ac, aslmsg msg)
                asprintf(&str, "%lu", tick);
                if (str != NULL)
                {
-                       asl_set(msg, ASL_KEY_TIME, str);
+                       asl_set(tmp_msg, ASL_KEY_TIME, str);
                        free(str);
                        str = NULL;
                }
@@ -2707,14 +2859,14 @@ asl_send(aslclient ac, aslmsg msg)
        memset(&hname, 0, _POSIX_HOST_NAME_MAX);
        if (gethostname(hname, _POSIX_HOST_NAME_MAX) == 0)
        {
-               asl_set(msg, ASL_KEY_HOST, hname);
+               asl_set(tmp_msg, ASL_KEY_HOST, hname);
        }
 
        str = NULL;
        asprintf(&str, "%u", getpid());
        if (str != NULL)
        {
-               asl_set(msg, ASL_KEY_PID, str);
+               asl_set(tmp_msg, ASL_KEY_PID, str);
                free(str);
        }
 
@@ -2722,7 +2874,7 @@ asl_send(aslclient ac, aslmsg msg)
        asprintf(&str, "%d", getuid());
        if (str != NULL)
        {
-               asl_set(msg, ASL_KEY_UID, str);
+               asl_set(tmp_msg, ASL_KEY_UID, str);
                free(str);
        }
 
@@ -2730,30 +2882,29 @@ asl_send(aslclient ac, aslmsg msg)
        asprintf(&str, "%u", getgid());
        if (str != NULL)
        {
-               asl_set(msg, ASL_KEY_GID, str);
+               asl_set(tmp_msg, ASL_KEY_GID, str);
                free(str);
        }
 
        senderx = (uint32_t)-1;
        facilityx = (uint32_t)-1;
-       mt = (asl_msg_t *)msg;
 
-       for (i = 0; (i < mt->count) && ((senderx == (uint32_t)-1) || (facilityx == (uint32_t)-1)); i++)
+       for (i = 0; (i < tmp_msg->count) && ((senderx == (uint32_t)-1) || (facilityx == (uint32_t)-1)); i++)
        {
-               if (mt->key[i] == NULL) continue;
-               if (streq(mt->key[i], ASL_KEY_SENDER)) senderx = i;
-               else if (streq(mt->key[i], ASL_KEY_FACILITY)) facilityx = i;
+               if (tmp_msg->key[i] == NULL) continue;
+               if (streq(tmp_msg->key[i], ASL_KEY_SENDER)) senderx = i;
+               else if (streq(tmp_msg->key[i], ASL_KEY_FACILITY)) facilityx = i;
        }
 
        /*
         * Set Sender if needed
         */
-       if ((senderx == (uint32_t)-1) || (mt->val[senderx] == NULL))
+       if ((senderx == (uint32_t)-1) || (tmp_msg->val[senderx] == NULL))
        {
                if ((ac != NULL) && (ac->name != NULL))
                {
                        /* Use the Sender name from the client handle */
-                       asl_set(msg, ASL_KEY_SENDER, ac->name);
+                       asl_set(tmp_msg, ASL_KEY_SENDER, ac->name);
                }
                else
                {
@@ -2774,67 +2925,97 @@ asl_send(aslclient ac, aslmsg msg)
                                }
                        }
 
-                       if (_asl_global.sender != NULL) asl_set(msg, ASL_KEY_SENDER, _asl_global.sender);
-                       else asl_set(msg, ASL_KEY_SENDER, "Unknown");
+                       if (_asl_global.sender != NULL) asl_set(tmp_msg, ASL_KEY_SENDER, _asl_global.sender);
+                       else asl_set(tmp_msg, ASL_KEY_SENDER, "Unknown");
                }
        }
 
        /*
         * Set Facility
         */
-       if ((facilityx == (uint32_t)-1) || (mt->val[facilityx] == NULL))
+       if ((facilityx == (uint32_t)-1) || (tmp_msg->val[facilityx] == NULL))
        {
                if ((ac != NULL) && (ac->facility != NULL))
                {
                        /* Use the Facility name from the client handle */
-                       asl_set(msg, ASL_KEY_FACILITY, ac->facility);
+                       asl_set(tmp_msg, ASL_KEY_FACILITY, ac->facility);
                }
        }
 
-       outstatus = 0;
+       /* Set "ASLOption store" if remote control is active */
+       if (rc_filter != 0)
+       {
+               val = asl_get(msg, ASL_KEY_OPTION);
+               if (val == NULL)
+               {
+                       asl_set(tmp_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
+               }
+               else
+               {
+                       str = NULL;
+                       asprintf(&str, "%s %s", ASL_OPT_STORE, val);
+                       if (str != NULL)
+                       {
+                               asl_set(tmp_msg, ASL_KEY_OPTION, str);
+                               free(str);
+                               str = NULL;
+                       }
+               }
+       }
+
+       outstatus = -1;
 
        if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
 
        if ((filter != 0) && ((filter & lmask) != 0))
        {
                len = 0;
-               out_raw = asl_msg_to_string((asl_msg_t *)msg, &len);
+               out_raw = asl_msg_to_string(tmp_msg, &len);
 
                if ((out_raw != NULL) && (len != 0))
                {
-                       asprintf(&out, "%10u %s\n", len + 1, out_raw);
-                       if (out != NULL)
+                       /* send a mach message to syslogd */
+                       outlen = len + 11;
+                       kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&out, outlen + 1, TRUE);
+                       if (kstatus == KERN_SUCCESS)
                        {
-                               if (asl->sock == -1) _asl_connect(asl);
+                               memset(out, 0, outlen + 1);
+                               snprintf((char *)out, outlen, "%10u %s", len, out_raw);
+
+                               status = 0;
 
-                               if (asl->sock >= 0)
+                               pthread_mutex_lock(&(_asl_global.port_lock));
+
+                               if (_asl_global.server_port == MACH_PORT_NULL)
                                {
-                                       status = write(asl->sock, out, len + 12);
-                                       if (status < 0)
-                                       {
-                                               /* Write failed - try resetting */
-                                               close(asl->sock);
-                                               asl->sock = -1;
-                                               _asl_connect(asl);
-                                               if (asl->sock >= 0) status = write(asl->sock, out, len + 12);
-                                               if (status < 0) outstatus = -1;
-                                       }
+                                       _asl_global.port_count = 0;
+
+                                       kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &_asl_global.server_port);
+                                       if (kstatus == KERN_SUCCESS) _asl_global.port_count = 1;
+                                       else _asl_global.server_port = MACH_PORT_NULL;
                                }
-                               else outstatus = -1;
 
-                               free(out);
+                               pthread_mutex_unlock(&(_asl_global.port_lock));
+
+                               if (kstatus == KERN_SUCCESS) kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)out, outlen + 1);
+                               else vm_deallocate(mach_task_self(), (vm_address_t)out, outlen + 1);
+
+                               if (kstatus == KERN_SUCCESS) outstatus = 0;
                        }
 
                        free(out_raw);
                }
        }
 
+       outstatus = 0;
+
+       /* write to file descriptors */
        for (i = 0; i < asl->fd_count; i++)
        {
                if (asl->fd_list[i] < 0) continue;
 
                len = 0;
-               out = asl_format_message(msg, asl->fd_mfmt[i], asl->fd_tfmt[i], asl->fd_encoding[i], &len);
+               out = asl_format_message(tmp_msg, asl->fd_mfmt[i], asl->fd_tfmt[i], asl->fd_encoding[i], &len);
                if (out == NULL) continue;
 
                status = write(asl->fd_list[i], out, len - 1);
@@ -2847,11 +3028,23 @@ asl_send(aslclient ac, aslmsg msg)
                free(out);
        }
 
+       asl_free((aslmsg)tmp_msg);
+
        if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
 
        return outstatus;
 }
 
+/*
+ * asl_send: send a message 
+ * returns 0 for success, non-zero for failure
+ */
+int
+asl_send(aslclient ac, aslmsg msg)
+{
+       return _asl_send_level_message(ac, msg, ASL_LEVEL_DEBUG, NULL);
+}
+
 char *
 asl_msg_string(aslmsg a)
 {
@@ -2892,7 +3085,7 @@ asl_free(aslmsg a)
 
 /*
  * Called if there's a malloc error while manipulating a message in asl_set_query.
- * Cleans up the key, kap, and op fields, sets count to zero.
+ * Cleans up the key, val, and op fields, sets count to zero.
  */
 static void
 _asl_clear_msg(asl_msg_t *msg)
@@ -2931,19 +3124,33 @@ _asl_clear_msg(asl_msg_t *msg)
 int
 asl_set_query(aslmsg a, const char *key, const char *val, uint32_t op)
 {
-       uint32_t i;
+       uint32_t i, len;
        char *dk, *dv;
        asl_msg_t *msg;
 
        msg = (asl_msg_t *)a;
 
        if (msg == NULL) return 0;
-
        if (key == NULL) return -1;
 
        dv = NULL;
 
-       if (streq(key, ASL_KEY_LEVEL))
+       if ((streq(key, ASL_KEY_MSG)) && (val != NULL))
+       {
+               /* strip trailing newlines */
+               dv = strdup(val);
+               if (dv == NULL) return -1;
+
+               len = strlen(dv);
+               i = len - 1;
+               while ((len > 0) && (dv[i] == '\n'))
+               {
+                       dv[i] = '\0';
+                       i--;
+                       len--;
+               }
+       }
+       else if (streq(key, ASL_KEY_LEVEL))
        {
                if (val == NULL) return -1;
                if (val[0] == '\0') return -1;
@@ -3070,7 +3277,12 @@ asl_set_query(aslmsg a, const char *key, const char *val, uint32_t op)
        }
 
        dk = strdup(key);
-       if (dk == NULL) return -1;
+       if (dk == NULL)
+       {
+               if (dv != NULL) free(dv);
+               _asl_clear_msg(msg);
+               return -1;
+       }
 
        msg->key[msg->count] = dk;
        msg->val[msg->count] = dv;
@@ -3174,13 +3386,24 @@ aslresponse
 asl_search(aslclient ac, aslmsg a)
 {
        asl_search_result_t query, *out;
-       asl_msg_t *qlist[1];
-       uint32_t status;
-       uint64_t last_id;
+       asl_msg_t *q, *qlist[1];
+       uint32_t status, x;
+       uint64_t last_id, start_id;
        asl_store_t *store;
 
        if (a == NULL) return NULL;
 
+       q = (asl_msg_t *)a;
+
+       /* check for "ASLMessageId >[=] n" and set start_id */
+       start_id = 0;
+       x = _asl_msg_index(q, ASL_KEY_MSG_ID);
+       if ((x != (uint32_t)-1) && (q->val[x] != NULL) && (q->op != NULL) && (q->op[x] & ASL_QUERY_OP_GREATER))
+       {
+               if (q->op[x] & ASL_QUERY_OP_EQUAL) start_id = atoi(q->val[x]);
+               else start_id = atoi(q->val[x]) + 1;
+       }
+
        store = NULL;
        status = asl_store_open_read(NULL, &store);
        if (status != 0) return NULL;
@@ -3194,7 +3417,7 @@ asl_search(aslclient ac, aslmsg a)
        query.count = 1;
        query.msg = qlist;
 
-       status = asl_store_match(store, &query, &out, &last_id, 0, 0, 1);
+       status = asl_store_match(store, &query, &out, &last_id, start_id, 0, 1);
        asl_store_close(store);
 
        return out;
@@ -3559,64 +3782,4 @@ asl_parse_time(const char *in)
        return -1;
 }
 
-#ifdef ASL_SYSLOG_COMPAT
-
-__private_extern__ void
-asl_syslog_syslog(int pri, const char *fmt, ...)
-{
-       va_list ap;
-       asl_msg_t *m;
-
-       if (fmt == NULL) return;
-
-       m = asl_new(ASL_TYPE_MSG);
-
-       va_start(ap, fmt);
-       asl_vlog(NULL, m, pri, fmt, ap);
-       va_end(ap);
-
-       asl_free(m);
-}
-
-__private_extern__ void
-asl_syslog_vsyslog(int pri, const char *fmt, va_list ap)
-{
-       asl_msg_t *m;
-
-       m = asl_new(ASL_TYPE_MSG);
-       asl_vlog(NULL, m, pri, fmt, ap);
-       asl_free(m);
-}
-
-__private_extern__ void
-asl_syslog_openlog(const char *ident, int flags, int facility)
-{
-       const char *fname;
-       uint32_t opts;
-
-       opts = 0;
-
-       if (flags & LOG_NDELAY) opts |= ASL_OPT_NO_DELAY;
-       if (flags & LOG_PERROR) opts |= ASL_OPT_STDERR;
-
-       fname = asl_syslog_faciliy_num_to_name(facility);
-       if (fname == NULL) fname = "user";
-
-       asl_global_client = asl_open(ident, fname, opts);
-}
-
-__private_extern__ void
-asl_syslog_closelog()
-{
-       asl_close();
-}
-
-__private_extern__ int
-asl_syslog_setlogmask(int p)
-{
-       return asl_set_filter(p);
-}
-
-#endif ASL_SYSLOG_COMPAT
-
 #endif /* BUILDING_VARIANT */